diff --git a/Taskfile.yml b/Taskfile.yml index 51fb724..9b7e3a7 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -15,4 +15,4 @@ tasks: cmd: goose -dir ./migrations up gen-http: cmds: - - oapi-codegen -package wizard -generate types,server ./api/openapi/wizard/wizard.yml > ./api/openapi/wizard/wizard.gen.go \ No newline at end of file + - oapi-codegen -package wizard -generate types,server,strict-server ./api/openapi/wizard/wizard.yml > ./api/openapi/wizard/wizard.gen.go \ No newline at end of file diff --git a/api/openapi/wizard/wizard.gen.go b/api/openapi/wizard/wizard.gen.go index db552e3..40da46c 100644 --- a/api/openapi/wizard/wizard.gen.go +++ b/api/openapi/wizard/wizard.gen.go @@ -4,12 +4,15 @@ package wizard import ( + "context" + "encoding/json" "fmt" "net/http" "time" "github.com/labstack/echo/v4" "github.com/oapi-codegen/runtime" + strictecho "github.com/oapi-codegen/runtime/strictmiddleware/echo" openapi_types "github.com/oapi-codegen/runtime/types" ) @@ -44,14 +47,24 @@ type DeviceKind string // ProtectionStatus defines model for ProtectionStatus. type ProtectionStatus string +// RegisterDeviceRequest defines model for RegisterDeviceRequest. +type RegisterDeviceRequest struct { + Ips []string `json:"ips"` + Kind DeviceKind `json:"kind"` + Name *string `json:"name,omitempty"` +} + +// RegisterDeviceJSONRequestBody defines body for RegisterDevice for application/json ContentType. +type RegisterDeviceJSONRequestBody = RegisterDeviceRequest + // ServerInterface represents all server handlers. type ServerInterface interface { // (GET /devices) - GetDevices(ctx echo.Context) error + FindDevices(ctx echo.Context) error // (POST /devices) - PostDevices(ctx echo.Context) error + RegisterDevice(ctx echo.Context) error // (GET /devices/{id}) GetDevicesId(ctx echo.Context, id openapi_types.UUID) error @@ -62,21 +75,21 @@ type ServerInterfaceWrapper struct { Handler ServerInterface } -// GetDevices converts echo context to params. -func (w *ServerInterfaceWrapper) GetDevices(ctx echo.Context) error { +// FindDevices converts echo context to params. +func (w *ServerInterfaceWrapper) FindDevices(ctx echo.Context) error { var err error // Invoke the callback with all the unmarshaled arguments - err = w.Handler.GetDevices(ctx) + err = w.Handler.FindDevices(ctx) return err } -// PostDevices converts echo context to params. -func (w *ServerInterfaceWrapper) PostDevices(ctx echo.Context) error { +// RegisterDevice converts echo context to params. +func (w *ServerInterfaceWrapper) RegisterDevice(ctx echo.Context) error { var err error // Invoke the callback with all the unmarshaled arguments - err = w.Handler.PostDevices(ctx) + err = w.Handler.RegisterDevice(ctx) return err } @@ -124,8 +137,169 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL Handler: si, } - router.GET(baseURL+"/devices", wrapper.GetDevices) - router.POST(baseURL+"/devices", wrapper.PostDevices) + router.GET(baseURL+"/devices", wrapper.FindDevices) + router.POST(baseURL+"/devices", wrapper.RegisterDevice) router.GET(baseURL+"/devices/:id", wrapper.GetDevicesId) } + +type FindDevicesRequestObject struct { +} + +type FindDevicesResponseObject interface { + VisitFindDevicesResponse(w http.ResponseWriter) error +} + +type FindDevices200JSONResponse struct { + Data []Device `json:"data"` + Success bool `json:"success"` +} + +func (response FindDevices200JSONResponse) VisitFindDevicesResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +type RegisterDeviceRequestObject struct { + Body *RegisterDeviceJSONRequestBody +} + +type RegisterDeviceResponseObject interface { + VisitRegisterDeviceResponse(w http.ResponseWriter) error +} + +type RegisterDevice200JSONResponse struct { + Data Device `json:"data"` + Success bool `json:"success"` +} + +func (response RegisterDevice200JSONResponse) VisitRegisterDeviceResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +type GetDevicesIdRequestObject struct { + Id openapi_types.UUID `json:"id"` +} + +type GetDevicesIdResponseObject interface { + VisitGetDevicesIdResponse(w http.ResponseWriter) error +} + +type GetDevicesId200JSONResponse struct { + Data Device `json:"data"` + Success bool `json:"success"` +} + +func (response GetDevicesId200JSONResponse) VisitGetDevicesIdResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +// StrictServerInterface represents all server handlers. +type StrictServerInterface interface { + + // (GET /devices) + FindDevices(ctx context.Context, request FindDevicesRequestObject) (FindDevicesResponseObject, error) + + // (POST /devices) + RegisterDevice(ctx context.Context, request RegisterDeviceRequestObject) (RegisterDeviceResponseObject, error) + + // (GET /devices/{id}) + GetDevicesId(ctx context.Context, request GetDevicesIdRequestObject) (GetDevicesIdResponseObject, error) +} + +type StrictHandlerFunc = strictecho.StrictEchoHandlerFunc +type StrictMiddlewareFunc = strictecho.StrictEchoMiddlewareFunc + +func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface { + return &strictHandler{ssi: ssi, middlewares: middlewares} +} + +type strictHandler struct { + ssi StrictServerInterface + middlewares []StrictMiddlewareFunc +} + +// FindDevices operation middleware +func (sh *strictHandler) FindDevices(ctx echo.Context) error { + var request FindDevicesRequestObject + + handler := func(ctx echo.Context, request interface{}) (interface{}, error) { + return sh.ssi.FindDevices(ctx.Request().Context(), request.(FindDevicesRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "FindDevices") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(FindDevicesResponseObject); ok { + return validResponse.VisitFindDevicesResponse(ctx.Response()) + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// RegisterDevice operation middleware +func (sh *strictHandler) RegisterDevice(ctx echo.Context) error { + var request RegisterDeviceRequestObject + + var body RegisterDeviceJSONRequestBody + if err := ctx.Bind(&body); err != nil { + return err + } + request.Body = &body + + handler := func(ctx echo.Context, request interface{}) (interface{}, error) { + return sh.ssi.RegisterDevice(ctx.Request().Context(), request.(RegisterDeviceRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "RegisterDevice") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(RegisterDeviceResponseObject); ok { + return validResponse.VisitRegisterDeviceResponse(ctx.Response()) + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// GetDevicesId operation middleware +func (sh *strictHandler) GetDevicesId(ctx echo.Context, id openapi_types.UUID) error { + var request GetDevicesIdRequestObject + + request.Id = id + + handler := func(ctx echo.Context, request interface{}) (interface{}, error) { + return sh.ssi.GetDevicesId(ctx.Request().Context(), request.(GetDevicesIdRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetDevicesId") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(GetDevicesIdResponseObject); ok { + return validResponse.VisitGetDevicesIdResponse(ctx.Response()) + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} diff --git a/api/openapi/wizard/wizard.yml b/api/openapi/wizard/wizard.yml index 943e8db..6f44590 100644 --- a/api/openapi/wizard/wizard.yml +++ b/api/openapi/wizard/wizard.yml @@ -10,6 +10,7 @@ paths: /devices: get: description: Returns a list of devices + operationId: findDevices responses: '200': description: Successfully returned a list of devices @@ -29,6 +30,14 @@ paths: $ref: "#/components/schemas/Device" post: description: Registers a new device + operationId: registerDevice + requestBody: + required: true + description: Name, kind and IP addresses of the device to be registered + content: + 'application/json': + schema: + $ref: "#/components/schemas/RegisterDeviceRequest" responses: '200': description: Successfully registered a new device and returned it @@ -72,6 +81,20 @@ paths: components: schemas: + RegisterDeviceRequest: + type: object + properties: + name: + type: string + kind: + $ref: "#/components/schemas/DeviceKind" + ips: + type: array + items: + type: string + required: + - kind + - ips ProtectionStatus: type: string enum: diff --git a/internal/pkg/wizardapi/api.go b/internal/pkg/wizardapi/api.go index 5283fd6..07cfa93 100644 --- a/internal/pkg/wizardapi/api.go +++ b/internal/pkg/wizardapi/api.go @@ -24,7 +24,8 @@ func StartAPIServer(app application.Application) { e.Use(echoMiddleware.Recover()) //e.Use(middleware.OapiRequestValidator()) - api.RegisterHandlers(e, handler) + strictAPIHandler := api.NewStrictHandler(handler, nil) + api.RegisterHandlers(e, strictAPIHandler) e.Logger.Fatal(e.Start(net.JoinHostPort("0.0.0.0", *port))) } diff --git a/internal/pkg/wizardapi/handler.go b/internal/pkg/wizardapi/handler.go index 65b36e0..7041ec0 100644 --- a/internal/pkg/wizardapi/handler.go +++ b/internal/pkg/wizardapi/handler.go @@ -3,15 +3,16 @@ package wizardapi import ( "bwizard/api/openapi/wizard" "bwizard/internal/pkg/wizard/application" - "github.com/labstack/echo/v4" - openapiTypes "github.com/oapi-codegen/runtime/types" + deviceValue "bwizard/internal/pkg/wizard/domain/valueobject/device" + "bwizard/internal/pkg/wizardapi/mappings" + "context" ) type Handler struct { app application.Application } -var _ wizard.ServerInterface = &Handler{} +var _ wizard.StrictServerInterface = &Handler{} func NewHandler(app application.Application) *Handler { return &Handler{ @@ -19,17 +20,32 @@ func NewHandler(app application.Application) *Handler { } } -func (h *Handler) GetDevices(ctx echo.Context) error { +func (h *Handler) FindDevices(ctx context.Context, request wizard.FindDevicesRequestObject) (wizard.FindDevicesResponseObject, error) { //TODO implement me panic("implement me") } -func (h *Handler) PostDevices(ctx echo.Context) error { - //TODO implement me - panic("implement me") +func (h *Handler) RegisterDevice(ctx context.Context, request wizard.RegisterDeviceRequestObject) (wizard.RegisterDeviceResponseObject, error) { + ips := make([]deviceValue.IPAddress, 0) + for _, ip := range ips { + ips = append(ips, ip) + } + + device, err := h.app.SetupDevice(ips, deviceValue.Kind(request.Body.Kind), request.Body.Name) + if err != nil { + // TODO: Add error handling here + return nil, err + } + + mappedDevice := mappings.MapDevice(device) + + return wizard.RegisterDevice200JSONResponse{ + Success: true, + Data: mappedDevice, + }, nil } -func (h *Handler) GetDevicesId(ctx echo.Context, id openapiTypes.UUID) error { +func (h *Handler) GetDevicesId(ctx context.Context, request wizard.GetDevicesIdRequestObject) (wizard.GetDevicesIdResponseObject, error) { //TODO implement me panic("implement me") } diff --git a/internal/pkg/wizardapi/mappings/device.go b/internal/pkg/wizardapi/mappings/device.go new file mode 100644 index 0000000..50ad687 --- /dev/null +++ b/internal/pkg/wizardapi/mappings/device.go @@ -0,0 +1,23 @@ +package mappings + +import ( + "bwizard/api/openapi/wizard" + "bwizard/internal/pkg/wizard/domain/entity/device" +) + +func MapDevice(device *device.Device) wizard.Device { + ips := make([]string, 0, len(device.IPs)) + for _, ip := range ips { + ips = append(ips, ip) + } + + return wizard.Device{ + Id: device.ID, + Name: device.Name, + Kind: wizard.DeviceKind(device.Kind), + Protection: wizard.ProtectionStatus(device.Protection), + Agent: device.Agent, + Ips: ips, + LastBackup: device.LastBackup, + } +}