123 lines
2.8 KiB
Go
123 lines
2.8 KiB
Go
package api
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"log/slog"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
|
|
"git.dubyatp.xyz/chat-api-server/db"
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/go-chi/chi/v5/middleware"
|
|
"github.com/go-chi/cors"
|
|
"github.com/go-chi/docgen"
|
|
"github.com/go-chi/render"
|
|
)
|
|
|
|
var routes = flag.Bool("routes", false, "Generate API route documentation")
|
|
|
|
func RequestLog(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
slog.Debug("api: request received",
|
|
"request_uri", r.RequestURI,
|
|
"source_ip", r.RemoteAddr,
|
|
"user_agent", r.UserAgent())
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
func Start() {
|
|
|
|
db.InitScyllaDB()
|
|
defer db.CloseScyllaDB()
|
|
|
|
flag.Parse()
|
|
|
|
r := chi.NewRouter()
|
|
|
|
r.Use(cors.Handler(cors.Options{
|
|
AllowedOrigins: strings.Split(os.Getenv("ALLOWED_ORIGINS"), ","),
|
|
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
|
|
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
|
|
ExposedHeaders: []string{"Link"},
|
|
AllowCredentials: true,
|
|
MaxAge: 300, // Maximum value for preflight request cache
|
|
}))
|
|
|
|
r.Use(middleware.RequestID)
|
|
r.Use(RequestLog)
|
|
r.Use(middleware.Recoverer)
|
|
r.Use(middleware.URLFormat)
|
|
r.Use(render.SetContentType(render.ContentTypeJSON))
|
|
|
|
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
|
w.Write([]byte("hello world"))
|
|
})
|
|
|
|
r.Get("/ping", func(w http.ResponseWriter, r *http.Request) {
|
|
w.Write([]byte("pong"))
|
|
})
|
|
|
|
r.Get("/panic", func(w http.ResponseWriter, r *http.Request) {
|
|
panic("oh no")
|
|
})
|
|
|
|
r.Route("/whoami", func(r chi.Router) {
|
|
r.Use(SessionAuthMiddleware)
|
|
r.Use(LoginCtx)
|
|
r.Get("/", Whoami)
|
|
})
|
|
|
|
r.Route("/messages", func(r chi.Router) {
|
|
r.Use(SessionAuthMiddleware) // Protect with authentication
|
|
|
|
r.Get("/", ListMessages)
|
|
r.Route("/{messageID}", func(r chi.Router) {
|
|
r.Use(MessageCtx) // Load message
|
|
r.Get("/", GetMessage)
|
|
r.Delete("/", DeleteMessage)
|
|
r.Post("/edit", EditMessage)
|
|
})
|
|
r.Route("/new", func(r chi.Router) {
|
|
r.Use(LoginCtx)
|
|
r.Post("/", NewMessage)
|
|
})
|
|
})
|
|
|
|
r.Route("/users", func(r chi.Router) {
|
|
r.Use(SessionAuthMiddleware) // Protect with authentication
|
|
|
|
r.Get("/", ListUsers)
|
|
r.Route("/{userID}", func(r chi.Router) {
|
|
r.Use(UserCtx) // Load user
|
|
r.Get("/", GetUser)
|
|
})
|
|
})
|
|
|
|
r.Route("/login", func(r chi.Router) {
|
|
r.Post("/", Login)
|
|
})
|
|
|
|
r.Route("/logout", func(r chi.Router) {
|
|
r.Use(SessionAuthMiddleware)
|
|
|
|
r.Post("/", Logout)
|
|
})
|
|
|
|
r.Route("/register", func(r chi.Router) {
|
|
r.Post("/", NewUser)
|
|
})
|
|
|
|
if *routes {
|
|
fmt.Println(docgen.MarkdownRoutesDoc(r, docgen.MarkdownOpts{
|
|
ProjectPath: "git.dubyatp.xyz/chat-api-server",
|
|
Intro: "Welcome to the chat API server. This is a simple API for sending and receiving messages.",
|
|
}))
|
|
return
|
|
}
|
|
|
|
http.ListenAndServe(":3000", r)
|
|
}
|