diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f6c7fde --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +.PHONY: codegen +codegen: + @echo "Generating code..." + @oapi-codegen --config=./oapi-codegen.cli.yaml ./api/v1/openapi.yaml diff --git a/internal/server/api.gen.go b/internal/server/api.gen.go new file mode 100644 index 0000000..e0ea6ec --- /dev/null +++ b/internal/server/api.gen.go @@ -0,0 +1,679 @@ +// Package server provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/deepmap/oapi-codegen/v2 version v2.1.0 DO NOT EDIT. +package server + +import ( + "bytes" + "compress/gzip" + "context" + "encoding/base64" + "fmt" + "net/url" + "path" + "strings" + + "github.com/getkin/kin-openapi/openapi3" + "github.com/gofiber/fiber/v2" + "github.com/oapi-codegen/runtime" + "gitlab.mareshq.com/hq/yggdrasil/pkg/training" +) + +// CreateTrainingRequest defines model for CreateTrainingRequest. +type CreateTrainingRequest = NewTraining + +// CreateTrainingResponse defines model for CreateTrainingResponse. +type CreateTrainingResponse = Training + +// GetTrainingResponse defines model for GetTrainingResponse. +type GetTrainingResponse = Training + +// ListTrainingsResponse defines model for ListTrainingsResponse. +type ListTrainingsResponse = []Training + +// NewTraining defines model for NewTraining. +type NewTraining struct { + Days int32 `json:"days"` + Name string `json:"name"` +} + +// ProblemDetails Schema that carries the details of an error in an HTTP response. See https://datatracker.ietf.org/doc/html/rfc7807 for more information. +type ProblemDetails struct { + // Detail A human-readable explanation specific to this occurrence of the problem. + Detail string `json:"detail"` + + // Instance A URI reference that identifies the specific occurrence of the problem. + Instance string `json:"instance"` + + // Status The HTTP status code generated by the origin server for this occurrence of the problem. + Status int `json:"status"` + + // Title A human-readable summary of the problem type. + Title string `json:"title"` + + // Type A URI reference that identifies the problem type. + Type string `json:"type"` +} + +// Training defines model for Training. +type Training struct { + Days int32 `json:"days"` + Id TrainingID `json:"id"` + Name string `json:"name"` +} + +// TrainingID defines model for TrainingID. +type TrainingID = training.TrainingID + +// UpdateTrainingRequest defines model for UpdateTrainingRequest. +type UpdateTrainingRequest = NewTraining + +// UpdateTrainingResponse defines model for UpdateTrainingResponse. +type UpdateTrainingResponse = Training + +// InternalError Schema that carries the details of an error in an HTTP response. See https://datatracker.ietf.org/doc/html/rfc7807 for more information. +type InternalError = ProblemDetails + +// InvalidInputError Schema that carries the details of an error in an HTTP response. See https://datatracker.ietf.org/doc/html/rfc7807 for more information. +type InvalidInputError = ProblemDetails + +// NotFoundError Schema that carries the details of an error in an HTTP response. See https://datatracker.ietf.org/doc/html/rfc7807 for more information. +type NotFoundError = ProblemDetails + +// CreateTrainingJSONRequestBody defines body for CreateTraining for application/json ContentType. +type CreateTrainingJSONRequestBody = CreateTrainingRequest + +// UpdateTrainingJSONRequestBody defines body for UpdateTraining for application/json ContentType. +type UpdateTrainingJSONRequestBody = UpdateTrainingRequest + +// ServerInterface represents all server handlers. +type ServerInterface interface { + // List all trainings + // (GET /v1/trainings) + ListTrainings(c *fiber.Ctx) error + // Create a new training + // (POST /v1/trainings) + CreateTraining(c *fiber.Ctx) error + // Delete a training by ID + // (DELETE /v1/trainings/{trainingID}) + DeleteTraining(c *fiber.Ctx, trainingID TrainingID) error + // Get a training by ID + // (GET /v1/trainings/{trainingID}) + GetTraining(c *fiber.Ctx, trainingID TrainingID) error + // Update a training by ID + // (PUT /v1/trainings/{trainingID}) + UpdateTraining(c *fiber.Ctx, trainingID TrainingID) error +} + +// ServerInterfaceWrapper converts contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface +} + +type MiddlewareFunc fiber.Handler + +// ListTrainings operation middleware +func (siw *ServerInterfaceWrapper) ListTrainings(c *fiber.Ctx) error { + + return siw.Handler.ListTrainings(c) +} + +// CreateTraining operation middleware +func (siw *ServerInterfaceWrapper) CreateTraining(c *fiber.Ctx) error { + + return siw.Handler.CreateTraining(c) +} + +// DeleteTraining operation middleware +func (siw *ServerInterfaceWrapper) DeleteTraining(c *fiber.Ctx) error { + + var err error + + // ------------- Path parameter "trainingID" ------------- + var trainingID TrainingID + + err = runtime.BindStyledParameterWithOptions("simple", "trainingID", c.Params("trainingID"), &trainingID, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter trainingID: %w", err).Error()) + } + + return siw.Handler.DeleteTraining(c, trainingID) +} + +// GetTraining operation middleware +func (siw *ServerInterfaceWrapper) GetTraining(c *fiber.Ctx) error { + + var err error + + // ------------- Path parameter "trainingID" ------------- + var trainingID TrainingID + + err = runtime.BindStyledParameterWithOptions("simple", "trainingID", c.Params("trainingID"), &trainingID, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter trainingID: %w", err).Error()) + } + + return siw.Handler.GetTraining(c, trainingID) +} + +// UpdateTraining operation middleware +func (siw *ServerInterfaceWrapper) UpdateTraining(c *fiber.Ctx) error { + + var err error + + // ------------- Path parameter "trainingID" ------------- + var trainingID TrainingID + + err = runtime.BindStyledParameterWithOptions("simple", "trainingID", c.Params("trainingID"), &trainingID, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter trainingID: %w", err).Error()) + } + + return siw.Handler.UpdateTraining(c, trainingID) +} + +// FiberServerOptions provides options for the Fiber server. +type FiberServerOptions struct { + BaseURL string + Middlewares []MiddlewareFunc +} + +// RegisterHandlers creates http.Handler with routing matching OpenAPI spec. +func RegisterHandlers(router fiber.Router, si ServerInterface) { + RegisterHandlersWithOptions(router, si, FiberServerOptions{}) +} + +// RegisterHandlersWithOptions creates http.Handler with additional options +func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) { + wrapper := ServerInterfaceWrapper{ + Handler: si, + } + + for _, m := range options.Middlewares { + router.Use(m) + } + + router.Get(options.BaseURL+"/v1/trainings", wrapper.ListTrainings) + + router.Post(options.BaseURL+"/v1/trainings", wrapper.CreateTraining) + + router.Delete(options.BaseURL+"/v1/trainings/:trainingID", wrapper.DeleteTraining) + + router.Get(options.BaseURL+"/v1/trainings/:trainingID", wrapper.GetTraining) + + router.Put(options.BaseURL+"/v1/trainings/:trainingID", wrapper.UpdateTraining) + +} + +type InternalErrorApplicationProblemPlusJSONResponse ProblemDetails + +type InvalidInputErrorApplicationProblemPlusJSONResponse ProblemDetails + +type NotFoundErrorApplicationProblemPlusJSONResponse ProblemDetails + +type ListTrainingsRequestObject struct { +} + +type ListTrainingsResponseObject interface { + VisitListTrainingsResponse(ctx *fiber.Ctx) error +} + +type ListTrainings200JSONResponse ListTrainingsResponse + +func (response ListTrainings200JSONResponse) VisitListTrainingsResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type ListTrainings500ApplicationProblemPlusJSONResponse struct { + InternalErrorApplicationProblemPlusJSONResponse +} + +func (response ListTrainings500ApplicationProblemPlusJSONResponse) VisitListTrainingsResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/problem+json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type CreateTrainingRequestObject struct { + Body *CreateTrainingJSONRequestBody +} + +type CreateTrainingResponseObject interface { + VisitCreateTrainingResponse(ctx *fiber.Ctx) error +} + +type CreateTraining201JSONResponse CreateTrainingResponse + +func (response CreateTraining201JSONResponse) VisitCreateTrainingResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(201) + + return ctx.JSON(&response) +} + +type CreateTraining400ApplicationProblemPlusJSONResponse struct { + InvalidInputErrorApplicationProblemPlusJSONResponse +} + +func (response CreateTraining400ApplicationProblemPlusJSONResponse) VisitCreateTrainingResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/problem+json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type CreateTraining500ApplicationProblemPlusJSONResponse struct { + InternalErrorApplicationProblemPlusJSONResponse +} + +func (response CreateTraining500ApplicationProblemPlusJSONResponse) VisitCreateTrainingResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/problem+json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type DeleteTrainingRequestObject struct { + TrainingID TrainingID `json:"trainingID"` +} + +type DeleteTrainingResponseObject interface { + VisitDeleteTrainingResponse(ctx *fiber.Ctx) error +} + +type DeleteTraining204Response struct { +} + +func (response DeleteTraining204Response) VisitDeleteTrainingResponse(ctx *fiber.Ctx) error { + ctx.Status(204) + return nil +} + +type DeleteTraining404ApplicationProblemPlusJSONResponse struct { + NotFoundErrorApplicationProblemPlusJSONResponse +} + +func (response DeleteTraining404ApplicationProblemPlusJSONResponse) VisitDeleteTrainingResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/problem+json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type DeleteTraining500ApplicationProblemPlusJSONResponse struct { + InternalErrorApplicationProblemPlusJSONResponse +} + +func (response DeleteTraining500ApplicationProblemPlusJSONResponse) VisitDeleteTrainingResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/problem+json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type GetTrainingRequestObject struct { + TrainingID TrainingID `json:"trainingID"` +} + +type GetTrainingResponseObject interface { + VisitGetTrainingResponse(ctx *fiber.Ctx) error +} + +type GetTraining200JSONResponse GetTrainingResponse + +func (response GetTraining200JSONResponse) VisitGetTrainingResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type GetTraining404ApplicationProblemPlusJSONResponse struct { + NotFoundErrorApplicationProblemPlusJSONResponse +} + +func (response GetTraining404ApplicationProblemPlusJSONResponse) VisitGetTrainingResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/problem+json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type GetTraining500ApplicationProblemPlusJSONResponse struct { + InternalErrorApplicationProblemPlusJSONResponse +} + +func (response GetTraining500ApplicationProblemPlusJSONResponse) VisitGetTrainingResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/problem+json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type UpdateTrainingRequestObject struct { + TrainingID TrainingID `json:"trainingID"` + Body *UpdateTrainingJSONRequestBody +} + +type UpdateTrainingResponseObject interface { + VisitUpdateTrainingResponse(ctx *fiber.Ctx) error +} + +type UpdateTraining200JSONResponse UpdateTrainingResponse + +func (response UpdateTraining200JSONResponse) VisitUpdateTrainingResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type UpdateTraining400ApplicationProblemPlusJSONResponse struct { + InvalidInputErrorApplicationProblemPlusJSONResponse +} + +func (response UpdateTraining400ApplicationProblemPlusJSONResponse) VisitUpdateTrainingResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/problem+json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type UpdateTraining404ApplicationProblemPlusJSONResponse struct { + NotFoundErrorApplicationProblemPlusJSONResponse +} + +func (response UpdateTraining404ApplicationProblemPlusJSONResponse) VisitUpdateTrainingResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/problem+json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type UpdateTraining500ApplicationProblemPlusJSONResponse struct { + InternalErrorApplicationProblemPlusJSONResponse +} + +func (response UpdateTraining500ApplicationProblemPlusJSONResponse) VisitUpdateTrainingResponse(ctx *fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/problem+json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +// StrictServerInterface represents all server handlers. +type StrictServerInterface interface { + // List all trainings + // (GET /v1/trainings) + ListTrainings(ctx context.Context, request ListTrainingsRequestObject) (ListTrainingsResponseObject, error) + // Create a new training + // (POST /v1/trainings) + CreateTraining(ctx context.Context, request CreateTrainingRequestObject) (CreateTrainingResponseObject, error) + // Delete a training by ID + // (DELETE /v1/trainings/{trainingID}) + DeleteTraining(ctx context.Context, request DeleteTrainingRequestObject) (DeleteTrainingResponseObject, error) + // Get a training by ID + // (GET /v1/trainings/{trainingID}) + GetTraining(ctx context.Context, request GetTrainingRequestObject) (GetTrainingResponseObject, error) + // Update a training by ID + // (PUT /v1/trainings/{trainingID}) + UpdateTraining(ctx context.Context, request UpdateTrainingRequestObject) (UpdateTrainingResponseObject, error) +} + +type StrictHandlerFunc func(ctx *fiber.Ctx, args interface{}) (interface{}, error) + +type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc + +func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface { + return &strictHandler{ssi: ssi, middlewares: middlewares} +} + +type strictHandler struct { + ssi StrictServerInterface + middlewares []StrictMiddlewareFunc +} + +// ListTrainings operation middleware +func (sh *strictHandler) ListTrainings(ctx *fiber.Ctx) error { + var request ListTrainingsRequestObject + + handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.ListTrainings(ctx.UserContext(), request.(ListTrainingsRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "ListTrainings") + } + + response, err := handler(ctx, request) + + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } else if validResponse, ok := response.(ListTrainingsResponseObject); ok { + if err := validResponse.VisitListTrainingsResponse(ctx); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// CreateTraining operation middleware +func (sh *strictHandler) CreateTraining(ctx *fiber.Ctx) error { + var request CreateTrainingRequestObject + + var body CreateTrainingJSONRequestBody + if err := ctx.BodyParser(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.CreateTraining(ctx.UserContext(), request.(CreateTrainingRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "CreateTraining") + } + + response, err := handler(ctx, request) + + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } else if validResponse, ok := response.(CreateTrainingResponseObject); ok { + if err := validResponse.VisitCreateTrainingResponse(ctx); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// DeleteTraining operation middleware +func (sh *strictHandler) DeleteTraining(ctx *fiber.Ctx, trainingID TrainingID) error { + var request DeleteTrainingRequestObject + + request.TrainingID = trainingID + + handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.DeleteTraining(ctx.UserContext(), request.(DeleteTrainingRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "DeleteTraining") + } + + response, err := handler(ctx, request) + + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } else if validResponse, ok := response.(DeleteTrainingResponseObject); ok { + if err := validResponse.VisitDeleteTrainingResponse(ctx); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// GetTraining operation middleware +func (sh *strictHandler) GetTraining(ctx *fiber.Ctx, trainingID TrainingID) error { + var request GetTrainingRequestObject + + request.TrainingID = trainingID + + handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.GetTraining(ctx.UserContext(), request.(GetTrainingRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetTraining") + } + + response, err := handler(ctx, request) + + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } else if validResponse, ok := response.(GetTrainingResponseObject); ok { + if err := validResponse.VisitGetTrainingResponse(ctx); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// UpdateTraining operation middleware +func (sh *strictHandler) UpdateTraining(ctx *fiber.Ctx, trainingID TrainingID) error { + var request UpdateTrainingRequestObject + + request.TrainingID = trainingID + + var body UpdateTrainingJSONRequestBody + if err := ctx.BodyParser(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.UpdateTraining(ctx.UserContext(), request.(UpdateTrainingRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "UpdateTraining") + } + + response, err := handler(ctx, request) + + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } else if validResponse, ok := response.(UpdateTrainingResponseObject); ok { + if err := validResponse.VisitUpdateTrainingResponse(ctx); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// Base64 encoded, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/9RXz3LbthN+FQx+v1tpUc6fSYenpnWbaCZN3MTpxfUBApckHBKAgaVsjYZP0lPfpX2v", + "DgCRIiXakRtlHJ8sg8Dut98uPuyuKFeVVhIkWpqsqGaGVYBg/H9nhgkpZD47cf+lYLkRGoWSNOm+kdkJ", + "jahwS5phQSMqWQU0obg5HFEDV7UwkNIETQ0RtbyAijmr/zeQ0YT+L94AicNXG/f8N03jrFitpAUPbiYR", + "jGTlz8Yo4xa4kggS3U+mdSk4c1BjbdS8hOq7S+twr/Z0fRpOnQAyUdrgfkhA65+AB9BEdCYXrBTpTOoa", + "Hw6Vx0CEA7GB9lbhL6qW6UPBequQZA5AC6lpa8Dn8icDDKFN93u4qsF6bNooDQZFSHnKlv5vpkzFkCZU", + "SHz6hEa0YjeiqiuaPI9oJWT4fRxRXGoI2yAHT0QozlX7xaIRMqehuNoSPQ+7ouDvojOj5pfA0VnZxhvK", + "0pNZlu8ympzfTdhbuG4P0yZa7TjYDlyk97wqq0E4IqUXzUUT0VeAjw/0G2E71LYPWyBUdl8fLm1rxMwY", + "tvS3ohfRt1tsW7drR4k/+EgJFgwJZ8YIsAQLIGk4QFRGmAz3jgjpfr8+OzslrZhOyAcAUiBqm8RxypCh", + "YfwTmIkAzCbK5HGqeFxgVcYm4y++n74gmTKkUgaIkIEeoeTkD0mjbQ49hF3IL0lRV0weGWApm5dA4EaX", + "THo7xGrgIhOcoCJYCEsU57UxIDm4WFxoa5ma0GibW/cUWWSSw5jXj+9nxEAGwZhnTKQgUWQtaZ3z+zm1", + "yLAeyc1ZAYHtsIFwlQLJQYJhCCmZL71lZUQuJLFgFmA8uXvH3as2FFjCHlzbuqqYWW7ZJM7gaGxh4b+Q", + "+RnTW/fAf23D6CiN2iLqZXbslvQv8retZ8OuqpOXuhbpDkcRvTnK1dF6sW2pJmf93qrbcSQqrUx4N10r", + "ltBcYMnmk4oZsMXVhKsqLq7iZZ6nhllRxvpTHmPHQRPRjzp9VA/xNt7H8aY1XqYy1TZijHuOofJiSQWr", + "flioSwRe+My5vG366t/VJf79Jy/Ir8zAP3/RiNbGnWoV/Pr6erJzuoloKTisuVlbOjVKGwHIzLKnH9TZ", + "ta9/Iy9PZzSiCzA23Pjp5HgydRuVBsm0oAl96pciX26en3hx3BWUX8jBh+Y49Oo+S2kyfNHpVl//ZDq9", + "o0G9X2M63jqM9KcvSSkseknscDURfR6wjLnoMMfDQcR3tkFh15ESVpY9sxFF5rg5pxsKnCxoZUeoGnaa", + "60kKLP6o0uXBaBpvv5vhZXSDW7OTq+OvBuL2ZHWjJ/dHUpepZ/tlantAO0SOA3DCiITrLs+3pLmJhlck", + "Xm3G5CY8siUg7NbBiV/v1UF/Ur9F5DZbBqp0sZPEZ3eM9wHQmuNnn2dqOGkegt8QOmEdt65t8i/f+EUa", + "lZze5HNg8g6nVmPT2ahWYW+meaCkvALcPyO6HsnI8On+8qQcXhbHm6G9ZHH61UDsIYu1P/KFsvhAdRXC", + "3be0/Fk/NYWaGRLyRnFWkhQWUCpdgcT1hDVomZI4Lt2+QllMnk6nU19Oa2fbFt+1FWwJm6saB8/6uqva", + "4Gsumn8DAAD//4xDbzZgFQAA", +} + +// GetSwagger returns the content of the embedded swagger specification file +// or error if failed to decode +func decodeSpec() ([]byte, error) { + zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, "")) + if err != nil { + return nil, fmt.Errorf("error base64 decoding spec: %w", err) + } + zr, err := gzip.NewReader(bytes.NewReader(zipped)) + if err != nil { + return nil, fmt.Errorf("error decompressing spec: %w", err) + } + var buf bytes.Buffer + _, err = buf.ReadFrom(zr) + if err != nil { + return nil, fmt.Errorf("error decompressing spec: %w", err) + } + + return buf.Bytes(), nil +} + +var rawSpec = decodeSpecCached() + +// a naive cached of a decoded swagger spec +func decodeSpecCached() func() ([]byte, error) { + data, err := decodeSpec() + return func() ([]byte, error) { + return data, err + } +} + +// Constructs a synthetic filesystem for resolving external references when loading openapi specifications. +func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) { + res := make(map[string]func() ([]byte, error)) + if len(pathToFile) > 0 { + res[pathToFile] = rawSpec + } + + return res +} + +// GetSwagger returns the Swagger specification corresponding to the generated code +// in this file. The external references of Swagger specification are resolved. +// The logic of resolving external references is tightly connected to "import-mapping" feature. +// Externally referenced files must be embedded in the corresponding golang packages. +// Urls can be supported but this task was out of the scope. +func GetSwagger() (swagger *openapi3.T, err error) { + resolvePath := PathToRawSpec("") + + loader := openapi3.NewLoader() + loader.IsExternalRefsAllowed = true + loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) { + pathToFile := url.String() + pathToFile = path.Clean(pathToFile) + getSpec, ok := resolvePath[pathToFile] + if !ok { + err1 := fmt.Errorf("path not found: %s", pathToFile) + return nil, err1 + } + return getSpec() + } + var specData []byte + specData, err = rawSpec() + if err != nil { + return + } + swagger, err = loader.LoadFromData(specData) + if err != nil { + return + } + return +} diff --git a/oapi-codegen.cli.yaml b/oapi-codegen.cli.yaml new file mode 100644 index 0000000..db145c2 --- /dev/null +++ b/oapi-codegen.cli.yaml @@ -0,0 +1,8 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/deepmap/oapi-codegen/HEAD/configuration-schema.json +package: server +generate: + models: true + fiber-server: true + strict-server: true + embedded-spec: true +output: ./internal/server/api.gen.go