Created a base to build on
This commit is contained in:
@@ -0,0 +1,257 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/danielgtaylor/huma/v2"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
|
||||
"completed/internal/db"
|
||||
)
|
||||
|
||||
func RegisterRoutes(api huma.API, queries db.Querier) {
|
||||
// Root/Hello Route
|
||||
huma.Register(api, huma.Operation{
|
||||
OperationID: "get-hello",
|
||||
Method: http.MethodGet,
|
||||
Path: "/hello",
|
||||
Summary: "Say Hello",
|
||||
Description: "Returns a friendly hello message.",
|
||||
}, func(ctx context.Context, input *struct{}) (*struct {
|
||||
Body struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
}, error) {
|
||||
resp := &struct {
|
||||
Body struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
}{}
|
||||
resp.Body.Message = "Hello from Huma + Echo!"
|
||||
return resp, nil
|
||||
})
|
||||
|
||||
registerPlatformRoutes(api, queries)
|
||||
registerGameRoutes(api, queries)
|
||||
}
|
||||
|
||||
// --- Platform Routes ---
|
||||
|
||||
// PlatformDTO ensures consistent JSON output
|
||||
type PlatformDTO struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type PlatformInput struct {
|
||||
Name string `json:"name" doc:"Name of the platform"`
|
||||
}
|
||||
|
||||
func registerPlatformRoutes(api huma.API, queries db.Querier) {
|
||||
huma.Register(api, huma.Operation{
|
||||
OperationID: "list-platforms",
|
||||
Method: http.MethodGet,
|
||||
Path: "/platforms",
|
||||
Summary: "List Platforms",
|
||||
}, func(ctx context.Context, input *struct{}) (*struct{ Body []PlatformDTO }, error) {
|
||||
platforms, err := queries.ListPlatforms(ctx)
|
||||
if err != nil {
|
||||
return nil, huma.Error500InternalServerError("Database error: " + err.Error())
|
||||
}
|
||||
dtos := make([]PlatformDTO, len(platforms))
|
||||
for i, p := range platforms {
|
||||
dtos[i] = PlatformDTO{ID: p.ID, Name: p.Name}
|
||||
}
|
||||
return &struct{ Body []PlatformDTO }{Body: dtos}, nil
|
||||
})
|
||||
|
||||
huma.Register(api, huma.Operation{
|
||||
OperationID: "create-platform",
|
||||
Method: http.MethodPost,
|
||||
Path: "/platforms",
|
||||
Summary: "Create Platform",
|
||||
}, func(ctx context.Context, input *struct{ Body PlatformInput }) (*struct{ Body PlatformDTO }, error) {
|
||||
platform, err := queries.CreatePlatform(ctx, input.Body.Name)
|
||||
if err != nil {
|
||||
return nil, huma.Error500InternalServerError("Database error: " + err.Error())
|
||||
}
|
||||
return &struct{ Body PlatformDTO }{Body: PlatformDTO{ID: platform.ID, Name: platform.Name}}, nil
|
||||
})
|
||||
|
||||
huma.Register(api, huma.Operation{
|
||||
OperationID: "update-platform",
|
||||
Method: http.MethodPut,
|
||||
Path: "/platforms/{id}",
|
||||
Summary: "Update Platform",
|
||||
}, func(ctx context.Context, input *struct {
|
||||
ID int64 `path:"id"`
|
||||
Body PlatformInput
|
||||
}) (*struct{ Body PlatformDTO }, error) {
|
||||
platform, err := queries.UpdatePlatform(ctx, db.UpdatePlatformParams{
|
||||
ID: input.ID,
|
||||
Name: input.Body.Name,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, huma.Error500InternalServerError("Database error: " + err.Error())
|
||||
}
|
||||
return &struct{ Body PlatformDTO }{Body: PlatformDTO{ID: platform.ID, Name: platform.Name}}, nil
|
||||
})
|
||||
|
||||
huma.Register(api, huma.Operation{
|
||||
OperationID: "delete-platform",
|
||||
Method: http.MethodDelete,
|
||||
Path: "/platforms/{id}",
|
||||
Summary: "Delete Platform",
|
||||
}, func(ctx context.Context, input *struct {
|
||||
ID int64 `path:"id"`
|
||||
}) (*struct{}, error) {
|
||||
err := queries.DeletePlatform(ctx, input.ID)
|
||||
if err != nil {
|
||||
return nil, huma.Error500InternalServerError("Database error: " + err.Error())
|
||||
}
|
||||
return nil, nil
|
||||
})
|
||||
}
|
||||
|
||||
// --- Game Routes ---
|
||||
|
||||
// GameDTO for API communication (Clean JSON)
|
||||
type GameDTO struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
PlatformID int64 `json:"platform_id"`
|
||||
Score int32 `json:"score"`
|
||||
ReleaseYear string `json:"release_year" format:"date" doc:"YYYY-MM-DD"`
|
||||
Finished string `json:"finished,omitempty" format:"date" doc:"YYYY-MM-DD (optional)"`
|
||||
}
|
||||
|
||||
type GameInput struct {
|
||||
Name string `json:"name"`
|
||||
PlatformID int64 `json:"platform_id"`
|
||||
Score int32 `json:"score"`
|
||||
ReleaseYear string `json:"release_year" format:"date" doc:"YYYY-MM-DD"`
|
||||
Finished string `json:"finished,omitempty" format:"date" doc:"YYYY-MM-DD (optional)"`
|
||||
}
|
||||
|
||||
// Helper to convert DB Game to DTO
|
||||
func toGameDTO(g db.Game) GameDTO {
|
||||
dto := GameDTO{
|
||||
ID: g.ID,
|
||||
Name: g.Name,
|
||||
PlatformID: g.PlatformID,
|
||||
Score: g.Score,
|
||||
ReleaseYear: g.ReleaseYear.Time.Format("2006-01-02"),
|
||||
}
|
||||
if g.Finished.Valid {
|
||||
dto.Finished = g.Finished.Time.Format("2006-01-02")
|
||||
}
|
||||
return dto
|
||||
}
|
||||
|
||||
// Helper to parse date string to pgtype.Date
|
||||
func parseDate(s string) (pgtype.Date, error) {
|
||||
if s == "" {
|
||||
return pgtype.Date{}, nil
|
||||
}
|
||||
t, err := time.Parse("2006-01-02", s)
|
||||
if err != nil {
|
||||
return pgtype.Date{}, err
|
||||
}
|
||||
return pgtype.Date{Time: t, Valid: true}, nil
|
||||
}
|
||||
|
||||
func registerGameRoutes(api huma.API, queries db.Querier) {
|
||||
huma.Register(api, huma.Operation{
|
||||
OperationID: "list-games",
|
||||
Method: http.MethodGet,
|
||||
Path: "/games",
|
||||
Summary: "List Games",
|
||||
}, func(ctx context.Context, input *struct{}) (*struct{ Body []GameDTO }, error) {
|
||||
games, err := queries.ListGames(ctx)
|
||||
if err != nil {
|
||||
return nil, huma.Error500InternalServerError("Database error: " + err.Error())
|
||||
}
|
||||
dtos := make([]GameDTO, len(games))
|
||||
for i, g := range games {
|
||||
dtos[i] = toGameDTO(g)
|
||||
}
|
||||
return &struct{ Body []GameDTO }{Body: dtos}, nil
|
||||
})
|
||||
|
||||
huma.Register(api, huma.Operation{
|
||||
OperationID: "create-game",
|
||||
Method: http.MethodPost,
|
||||
Path: "/games",
|
||||
Summary: "Create Game",
|
||||
}, func(ctx context.Context, input *struct{ Body GameInput }) (*struct{ Body GameDTO }, error) {
|
||||
ry, err := parseDate(input.Body.ReleaseYear)
|
||||
if err != nil {
|
||||
return nil, huma.Error400BadRequest("Invalid release_year format (expected YYYY-MM-DD)")
|
||||
}
|
||||
fin, err := parseDate(input.Body.Finished)
|
||||
if err != nil {
|
||||
return nil, huma.Error400BadRequest("Invalid finished format (expected YYYY-MM-DD)")
|
||||
}
|
||||
|
||||
game, err := queries.CreateGame(ctx, db.CreateGameParams{
|
||||
Name: input.Body.Name,
|
||||
PlatformID: input.Body.PlatformID,
|
||||
Score: input.Body.Score,
|
||||
ReleaseYear: ry,
|
||||
Finished: fin,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, huma.Error500InternalServerError("Database error: " + err.Error())
|
||||
}
|
||||
return &struct{ Body GameDTO }{Body: toGameDTO(game)}, nil
|
||||
})
|
||||
|
||||
huma.Register(api, huma.Operation{
|
||||
OperationID: "update-game",
|
||||
Method: http.MethodPut,
|
||||
Path: "/games/{id}",
|
||||
Summary: "Update Game",
|
||||
}, func(ctx context.Context, input *struct {
|
||||
ID int64 `path:"id"`
|
||||
Body GameInput
|
||||
}) (*struct{ Body GameDTO }, error) {
|
||||
ry, err := parseDate(input.Body.ReleaseYear)
|
||||
if err != nil {
|
||||
return nil, huma.Error400BadRequest("Invalid release_year format (expected YYYY-MM-DD)")
|
||||
}
|
||||
fin, err := parseDate(input.Body.Finished)
|
||||
if err != nil {
|
||||
return nil, huma.Error400BadRequest("Invalid finished format (expected YYYY-MM-DD)")
|
||||
}
|
||||
|
||||
game, err := queries.UpdateGame(ctx, db.UpdateGameParams{
|
||||
ID: input.ID,
|
||||
Name: input.Body.Name,
|
||||
PlatformID: input.Body.PlatformID,
|
||||
Score: input.Body.Score,
|
||||
ReleaseYear: ry,
|
||||
Finished: fin,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, huma.Error500InternalServerError("Database error: " + err.Error())
|
||||
}
|
||||
return &struct{ Body GameDTO }{Body: toGameDTO(game)}, nil
|
||||
})
|
||||
|
||||
huma.Register(api, huma.Operation{
|
||||
OperationID: "delete-game",
|
||||
Method: http.MethodDelete,
|
||||
Path: "/games/{id}",
|
||||
Summary: "Delete Game",
|
||||
}, func(ctx context.Context, input *struct {
|
||||
ID int64 `path:"id"`
|
||||
}) (*struct{}, error) {
|
||||
err := queries.DeleteGame(ctx, input.ID)
|
||||
if err != nil {
|
||||
return nil, huma.Error500InternalServerError("Database error: " + err.Error())
|
||||
}
|
||||
return nil, nil
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user