From 839dea933bea8927d979e2bfce8d7b610b2f3cc3 Mon Sep 17 00:00:00 2001 From: Tine Date: Thu, 1 Feb 2024 19:57:25 +0100 Subject: [PATCH] wip --- .spectral.yaml | 1 + api/openapi.yaml | 348 +++++++ cmd/server.go | 20 + go.mod | 16 + go.sum | 23 + justfile | 5 + pkg/api/oas_cfg_gen.go | 281 ++++++ pkg/api/oas_client_gen.go | 1160 +++++++++++++++++++++ pkg/api/oas_handlers_gen.go | 1398 ++++++++++++++++++++++++++ pkg/api/oas_interfaces_gen.go | 30 + pkg/api/oas_json_gen.go | 755 ++++++++++++++ pkg/api/oas_middleware_gen.go | 10 + pkg/api/oas_parameters_gen.go | 520 ++++++++++ pkg/api/oas_request_decoders_gen.go | 331 ++++++ pkg/api/oas_request_encoders_gen.go | 82 ++ pkg/api/oas_response_decoders_gen.go | 1290 ++++++++++++++++++++++++ pkg/api/oas_response_encoders_gen.go | 350 +++++++ pkg/api/oas_router_gen.go | 551 ++++++++++ pkg/api/oas_schemas_gen.go | 422 ++++++++ pkg/api/oas_server_gen.go | 104 ++ pkg/api/oas_unimplemented_gen.go | 128 +++ pkg/groups.go | 18 + pkg/users.go | 0 tools/generate.go | 3 + 24 files changed, 7846 insertions(+) create mode 100644 .spectral.yaml create mode 100644 api/openapi.yaml create mode 100644 cmd/server.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 justfile create mode 100644 pkg/api/oas_cfg_gen.go create mode 100644 pkg/api/oas_client_gen.go create mode 100644 pkg/api/oas_handlers_gen.go create mode 100644 pkg/api/oas_interfaces_gen.go create mode 100644 pkg/api/oas_json_gen.go create mode 100644 pkg/api/oas_middleware_gen.go create mode 100644 pkg/api/oas_parameters_gen.go create mode 100644 pkg/api/oas_request_decoders_gen.go create mode 100644 pkg/api/oas_request_encoders_gen.go create mode 100644 pkg/api/oas_response_decoders_gen.go create mode 100644 pkg/api/oas_response_encoders_gen.go create mode 100644 pkg/api/oas_router_gen.go create mode 100644 pkg/api/oas_schemas_gen.go create mode 100644 pkg/api/oas_server_gen.go create mode 100644 pkg/api/oas_unimplemented_gen.go create mode 100644 pkg/groups.go create mode 100644 pkg/users.go create mode 100644 tools/generate.go diff --git a/.spectral.yaml b/.spectral.yaml new file mode 100644 index 0000000..1cac3b3 --- /dev/null +++ b/.spectral.yaml @@ -0,0 +1 @@ +extends: ["spectral:oas", "spectral:asyncapi"] diff --git a/api/openapi.yaml b/api/openapi.yaml new file mode 100644 index 0000000..33dbc36 --- /dev/null +++ b/api/openapi.yaml @@ -0,0 +1,348 @@ +openapi: 3.0.0 +info: + version: 1.0.0 + title: golang-rest-example + license: + name: MIT + url: https://opensource.org/license/MIT/ + description: > + Example OpenAPI Golang server. +servers: + - url: http://localhost:1323/api/v1 + description: Local server +tags: + - name: health + description: Health check + - name: users + description: User management + - name: groups + description: Group management +paths: + /healthz: + description: Health check + get: + tags: + - health + responses: + '200': + $ref: '#/components/responses/Ok' + default: + $ref: '#/components/responses/UnexpectedError' + /users: + get: + description: Get all users + tags: + - users + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + default: + $ref: '#/components/responses/UnexpectedError' + post: + description: Create user + tags: + - users + requestBody: + description: User object + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UserUpdate' + responses: + '201': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/User' + default: + $ref: '#/components/responses/UnexpectedError' + /users/{id}: + get: + description: Get user by id + tags: + - users + parameters: + - name: id + in: path + required: true + schema: + $ref: '#/components/schemas/Id' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: '#/components/responses/UnexpectedError' + put: + description: Update user by id + tags: + - users + parameters: + - name: id + in: path + required: true + schema: + $ref: '#/components/schemas/Id' + requestBody: + description: User object + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UserUpdate' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: '#/components/responses/UnexpectedError' + delete: + description: Delete user by id + tags: + - users + parameters: + - name: id + in: path + required: true + schema: + $ref: '#/components/schemas/Id' + responses: + '200': + $ref: '#/components/responses/Ok' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: '#/components/responses/UnexpectedError' + /users/{id}/group: + put: + description: Update user group by id + tags: + - users + parameters: + - name: id + in: path + required: true + schema: + $ref: '#/components/schemas/Id' + requestBody: + description: Group object + required: true + content: + application/json: + schema: + type: object + properties: + group: + $ref: '#/components/schemas/Id' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: '#/components/responses/UnexpectedError' + /groups: + get: + description: Get all groups + tags: + - groups + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Group' + default: + $ref: '#/components/responses/UnexpectedError' + post: + description: Create group + tags: + - groups + requestBody: + description: Group object + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GroupUpdate' + responses: + '201': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Group' + default: + $ref: '#/components/responses/UnexpectedError' + /groups/{id}: + get: + description: Get group by id + tags: + - groups + parameters: + - name: id + in: path + required: true + schema: + $ref: '#/components/schemas/Id' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Group' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: '#/components/responses/UnexpectedError' + put: + description: Update group by id + tags: + - groups + parameters: + - name: id + in: path + required: true + schema: + $ref: '#/components/schemas/Id' + requestBody: + description: Group object + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GroupUpdate' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Group' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: '#/components/responses/UnexpectedError' + delete: + description: Delete group by id + tags: + - groups + parameters: + - name: id + in: path + required: true + schema: + $ref: '#/components/schemas/Id' + responses: + '200': + $ref: '#/components/responses/Ok' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: '#/components/responses/UnexpectedError' +components: + responses: + Ok: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Ok' + NotFound: + description: Not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + UnexpectedError: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + schemas: + Ok: + type: object + properties: + message: + type: string + example: OK + Error: + type: object + properties: + message: + type: string + example: Not found + code: + type: integer + example: 404 + Id: + type: integer + format: int64 + example: 1 + User: + type: object + properties: + id: + $ref: '#/components/schemas/Id' + name: + type: string + example: John + email: + type: string + example: john@example.com + group: + $ref: '#/components/schemas/Group' + UserUpdate: + type: object + properties: + name: + type: string + example: John + email: + type: string + example: john@example.com + Group: + type: object + properties: + id: + $ref: '#/components/schemas/Id' + name: + type: string + example: admins + users: + type: array + items: + $ref: '#/components/schemas/User' + GroupUpdate: + type: object + properties: + name: + type: string + example: admins diff --git a/cmd/server.go b/cmd/server.go new file mode 100644 index 0000000..824af55 --- /dev/null +++ b/cmd/server.go @@ -0,0 +1,20 @@ +package main + +import ( + "log" + "net/http" + + "github.com/mentos1386/golang-rest-example/pkg/api" +) + +func main() { + + srv, err := api.NewServer() + if err != nil { + log.Fatal(err) + } + + if err := http.ListenAndServe(":8080", srv); err != nil { + log.Fatal(err) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..84fe531 --- /dev/null +++ b/go.mod @@ -0,0 +1,16 @@ +module github.com/mentos1386/golang-rest-example + +go 1.21.6 + +require ( + github.com/labstack/echo/v4 v4.11.4 // indirect + github.com/labstack/gommon v0.4.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect + golang.org/x/crypto v0.17.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..453ca6f --- /dev/null +++ b/go.sum @@ -0,0 +1,23 @@ +github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8= +github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8= +github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= +github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= diff --git a/justfile b/justfile new file mode 100644 index 0000000..416a924 --- /dev/null +++ b/justfile @@ -0,0 +1,5 @@ +run: + go run cmd/server.go + +gen: + go generate ./... diff --git a/pkg/api/oas_cfg_gen.go b/pkg/api/oas_cfg_gen.go new file mode 100644 index 0000000..e7311e7 --- /dev/null +++ b/pkg/api/oas_cfg_gen.go @@ -0,0 +1,281 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +import ( + "net/http" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/trace" + + ht "github.com/ogen-go/ogen/http" + "github.com/ogen-go/ogen/middleware" + "github.com/ogen-go/ogen/ogenerrors" + "github.com/ogen-go/ogen/otelogen" +) + +var ( + // Allocate option closure once. + clientSpanKind = trace.WithSpanKind(trace.SpanKindClient) + // Allocate option closure once. + serverSpanKind = trace.WithSpanKind(trace.SpanKindServer) +) + +type ( + optionFunc[C any] func(*C) + otelOptionFunc func(*otelConfig) +) + +type otelConfig struct { + TracerProvider trace.TracerProvider + Tracer trace.Tracer + MeterProvider metric.MeterProvider + Meter metric.Meter +} + +func (cfg *otelConfig) initOTEL() { + if cfg.TracerProvider == nil { + cfg.TracerProvider = otel.GetTracerProvider() + } + if cfg.MeterProvider == nil { + cfg.MeterProvider = otel.GetMeterProvider() + } + cfg.Tracer = cfg.TracerProvider.Tracer(otelogen.Name, + trace.WithInstrumentationVersion(otelogen.SemVersion()), + ) + cfg.Meter = cfg.MeterProvider.Meter(otelogen.Name) +} + +// ErrorHandler is error handler. +type ErrorHandler = ogenerrors.ErrorHandler + +type serverConfig struct { + otelConfig + NotFound http.HandlerFunc + MethodNotAllowed func(w http.ResponseWriter, r *http.Request, allowed string) + ErrorHandler ErrorHandler + Prefix string + Middleware Middleware + MaxMultipartMemory int64 +} + +// ServerOption is server config option. +type ServerOption interface { + applyServer(*serverConfig) +} + +var _ ServerOption = (optionFunc[serverConfig])(nil) + +func (o optionFunc[C]) applyServer(c *C) { + o(c) +} + +var _ ServerOption = (otelOptionFunc)(nil) + +func (o otelOptionFunc) applyServer(c *serverConfig) { + o(&c.otelConfig) +} + +func newServerConfig(opts ...ServerOption) serverConfig { + cfg := serverConfig{ + NotFound: http.NotFound, + MethodNotAllowed: func(w http.ResponseWriter, r *http.Request, allowed string) { + status := http.StatusMethodNotAllowed + if r.Method == "OPTIONS" { + w.Header().Set("Access-Control-Allow-Methods", allowed) + w.Header().Set("Access-Control-Allow-Headers", "Content-Type") + status = http.StatusNoContent + } else { + w.Header().Set("Allow", allowed) + } + w.WriteHeader(status) + }, + ErrorHandler: ogenerrors.DefaultErrorHandler, + Middleware: nil, + MaxMultipartMemory: 32 << 20, // 32 MB + } + for _, opt := range opts { + opt.applyServer(&cfg) + } + cfg.initOTEL() + return cfg +} + +type baseServer struct { + cfg serverConfig + requests metric.Int64Counter + errors metric.Int64Counter + duration metric.Float64Histogram +} + +func (s baseServer) notFound(w http.ResponseWriter, r *http.Request) { + s.cfg.NotFound(w, r) +} + +func (s baseServer) notAllowed(w http.ResponseWriter, r *http.Request, allowed string) { + s.cfg.MethodNotAllowed(w, r, allowed) +} + +func (cfg serverConfig) baseServer() (s baseServer, err error) { + s = baseServer{cfg: cfg} + if s.requests, err = s.cfg.Meter.Int64Counter(otelogen.ServerRequestCount); err != nil { + return s, err + } + if s.errors, err = s.cfg.Meter.Int64Counter(otelogen.ServerErrorsCount); err != nil { + return s, err + } + if s.duration, err = s.cfg.Meter.Float64Histogram(otelogen.ServerDuration); err != nil { + return s, err + } + return s, nil +} + +type clientConfig struct { + otelConfig + Client ht.Client +} + +// ClientOption is client config option. +type ClientOption interface { + applyClient(*clientConfig) +} + +var _ ClientOption = (optionFunc[clientConfig])(nil) + +func (o optionFunc[C]) applyClient(c *C) { + o(c) +} + +var _ ClientOption = (otelOptionFunc)(nil) + +func (o otelOptionFunc) applyClient(c *clientConfig) { + o(&c.otelConfig) +} + +func newClientConfig(opts ...ClientOption) clientConfig { + cfg := clientConfig{ + Client: http.DefaultClient, + } + for _, opt := range opts { + opt.applyClient(&cfg) + } + cfg.initOTEL() + return cfg +} + +type baseClient struct { + cfg clientConfig + requests metric.Int64Counter + errors metric.Int64Counter + duration metric.Float64Histogram +} + +func (cfg clientConfig) baseClient() (c baseClient, err error) { + c = baseClient{cfg: cfg} + if c.requests, err = c.cfg.Meter.Int64Counter(otelogen.ClientRequestCount); err != nil { + return c, err + } + if c.errors, err = c.cfg.Meter.Int64Counter(otelogen.ClientErrorsCount); err != nil { + return c, err + } + if c.duration, err = c.cfg.Meter.Float64Histogram(otelogen.ClientDuration); err != nil { + return c, err + } + return c, nil +} + +// Option is config option. +type Option interface { + ServerOption + ClientOption +} + +// WithTracerProvider specifies a tracer provider to use for creating a tracer. +// +// If none is specified, the global provider is used. +func WithTracerProvider(provider trace.TracerProvider) Option { + return otelOptionFunc(func(cfg *otelConfig) { + if provider != nil { + cfg.TracerProvider = provider + } + }) +} + +// WithMeterProvider specifies a meter provider to use for creating a meter. +// +// If none is specified, the otel.GetMeterProvider() is used. +func WithMeterProvider(provider metric.MeterProvider) Option { + return otelOptionFunc(func(cfg *otelConfig) { + if provider != nil { + cfg.MeterProvider = provider + } + }) +} + +// WithClient specifies http client to use. +func WithClient(client ht.Client) ClientOption { + return optionFunc[clientConfig](func(cfg *clientConfig) { + if client != nil { + cfg.Client = client + } + }) +} + +// WithNotFound specifies Not Found handler to use. +func WithNotFound(notFound http.HandlerFunc) ServerOption { + return optionFunc[serverConfig](func(cfg *serverConfig) { + if notFound != nil { + cfg.NotFound = notFound + } + }) +} + +// WithMethodNotAllowed specifies Method Not Allowed handler to use. +func WithMethodNotAllowed(methodNotAllowed func(w http.ResponseWriter, r *http.Request, allowed string)) ServerOption { + return optionFunc[serverConfig](func(cfg *serverConfig) { + if methodNotAllowed != nil { + cfg.MethodNotAllowed = methodNotAllowed + } + }) +} + +// WithErrorHandler specifies error handler to use. +func WithErrorHandler(h ErrorHandler) ServerOption { + return optionFunc[serverConfig](func(cfg *serverConfig) { + if h != nil { + cfg.ErrorHandler = h + } + }) +} + +// WithPathPrefix specifies server path prefix. +func WithPathPrefix(prefix string) ServerOption { + return optionFunc[serverConfig](func(cfg *serverConfig) { + cfg.Prefix = prefix + }) +} + +// WithMiddleware specifies middlewares to use. +func WithMiddleware(m ...Middleware) ServerOption { + return optionFunc[serverConfig](func(cfg *serverConfig) { + switch len(m) { + case 0: + cfg.Middleware = nil + case 1: + cfg.Middleware = m[0] + default: + cfg.Middleware = middleware.ChainMiddlewares(m...) + } + }) +} + +// WithMaxMultipartMemory specifies limit of memory for storing file parts. +// File parts which can't be stored in memory will be stored on disk in temporary files. +func WithMaxMultipartMemory(max int64) ServerOption { + return optionFunc[serverConfig](func(cfg *serverConfig) { + if max > 0 { + cfg.MaxMultipartMemory = max + } + }) +} diff --git a/pkg/api/oas_client_gen.go b/pkg/api/oas_client_gen.go new file mode 100644 index 0000000..f35a520 --- /dev/null +++ b/pkg/api/oas_client_gen.go @@ -0,0 +1,1160 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +import ( + "context" + "net/url" + "strings" + "time" + + "github.com/go-faster/errors" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/metric" + semconv "go.opentelemetry.io/otel/semconv/v1.19.0" + "go.opentelemetry.io/otel/trace" + + "github.com/ogen-go/ogen/conv" + ht "github.com/ogen-go/ogen/http" + "github.com/ogen-go/ogen/uri" +) + +// Invoker invokes operations described by OpenAPI v3 specification. +type Invoker interface { + // GroupsGet invokes GET /groups operation. + // + // Get all groups. + // + // GET /groups + GroupsGet(ctx context.Context) ([]Group, error) + // GroupsIDDelete invokes DELETE /groups/{id} operation. + // + // Delete group by id. + // + // DELETE /groups/{id} + GroupsIDDelete(ctx context.Context, params GroupsIDDeleteParams) (GroupsIDDeleteRes, error) + // GroupsIDGet invokes GET /groups/{id} operation. + // + // Get group by id. + // + // GET /groups/{id} + GroupsIDGet(ctx context.Context, params GroupsIDGetParams) (GroupsIDGetRes, error) + // GroupsIDPut invokes PUT /groups/{id} operation. + // + // Update group by id. + // + // PUT /groups/{id} + GroupsIDPut(ctx context.Context, request *GroupUpdate, params GroupsIDPutParams) (GroupsIDPutRes, error) + // GroupsPost invokes POST /groups operation. + // + // Create group. + // + // POST /groups + GroupsPost(ctx context.Context, request *GroupUpdate) (*Group, error) + // HealthzGet invokes GET /healthz operation. + // + // GET /healthz + HealthzGet(ctx context.Context) (*Ok, error) + // UsersGet invokes GET /users operation. + // + // Get all users. + // + // GET /users + UsersGet(ctx context.Context) ([]User, error) + // UsersIDDelete invokes DELETE /users/{id} operation. + // + // Delete user by id. + // + // DELETE /users/{id} + UsersIDDelete(ctx context.Context, params UsersIDDeleteParams) (UsersIDDeleteRes, error) + // UsersIDGet invokes GET /users/{id} operation. + // + // Get user by id. + // + // GET /users/{id} + UsersIDGet(ctx context.Context, params UsersIDGetParams) (UsersIDGetRes, error) + // UsersIDGroupPut invokes PUT /users/{id}/group operation. + // + // Update user group by id. + // + // PUT /users/{id}/group + UsersIDGroupPut(ctx context.Context, request *UsersIDGroupPutReq, params UsersIDGroupPutParams) (UsersIDGroupPutRes, error) + // UsersIDPut invokes PUT /users/{id} operation. + // + // Update user by id. + // + // PUT /users/{id} + UsersIDPut(ctx context.Context, request *UserUpdate, params UsersIDPutParams) (UsersIDPutRes, error) + // UsersPost invokes POST /users operation. + // + // Create user. + // + // POST /users + UsersPost(ctx context.Context, request *UserUpdate) (*User, error) +} + +// Client implements OAS client. +type Client struct { + serverURL *url.URL + baseClient +} +type errorHandler interface { + NewError(ctx context.Context, err error) *ErrorStatusCode +} + +var _ Handler = struct { + errorHandler + *Client +}{} + +func trimTrailingSlashes(u *url.URL) { + u.Path = strings.TrimRight(u.Path, "/") + u.RawPath = strings.TrimRight(u.RawPath, "/") +} + +// NewClient initializes new Client defined by OAS. +func NewClient(serverURL string, opts ...ClientOption) (*Client, error) { + u, err := url.Parse(serverURL) + if err != nil { + return nil, err + } + trimTrailingSlashes(u) + + c, err := newClientConfig(opts...).baseClient() + if err != nil { + return nil, err + } + return &Client{ + serverURL: u, + baseClient: c, + }, nil +} + +type serverURLKey struct{} + +// WithServerURL sets context key to override server URL. +func WithServerURL(ctx context.Context, u *url.URL) context.Context { + return context.WithValue(ctx, serverURLKey{}, u) +} + +func (c *Client) requestURL(ctx context.Context) *url.URL { + u, ok := ctx.Value(serverURLKey{}).(*url.URL) + if !ok { + return c.serverURL + } + return u +} + +// GroupsGet invokes GET /groups operation. +// +// Get all groups. +// +// GET /groups +func (c *Client) GroupsGet(ctx context.Context) ([]Group, error) { + res, err := c.sendGroupsGet(ctx) + return res, err +} + +func (c *Client) sendGroupsGet(ctx context.Context) (res []Group, err error) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/groups"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, "GroupsGet", + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [1]string + pathParts[0] = "/groups" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "GET", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeGroupsGetResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// GroupsIDDelete invokes DELETE /groups/{id} operation. +// +// Delete group by id. +// +// DELETE /groups/{id} +func (c *Client) GroupsIDDelete(ctx context.Context, params GroupsIDDeleteParams) (GroupsIDDeleteRes, error) { + res, err := c.sendGroupsIDDelete(ctx, params) + return res, err +} + +func (c *Client) sendGroupsIDDelete(ctx context.Context, params GroupsIDDeleteParams) (res GroupsIDDeleteRes, err error) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("DELETE"), + semconv.HTTPRouteKey.String("/groups/{id}"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, "GroupsIDDelete", + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [2]string + pathParts[0] = "/groups/" + { + // Encode "id" parameter. + e := uri.NewPathEncoder(uri.PathEncoderConfig{ + Param: "id", + Style: uri.PathStyleSimple, + Explode: false, + }) + if err := func() error { + if unwrapped := int64(params.ID); true { + return e.EncodeValue(conv.Int64ToString(unwrapped)) + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "encode path") + } + encoded, err := e.Result() + if err != nil { + return res, errors.Wrap(err, "encode path") + } + pathParts[1] = encoded + } + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "DELETE", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeGroupsIDDeleteResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// GroupsIDGet invokes GET /groups/{id} operation. +// +// Get group by id. +// +// GET /groups/{id} +func (c *Client) GroupsIDGet(ctx context.Context, params GroupsIDGetParams) (GroupsIDGetRes, error) { + res, err := c.sendGroupsIDGet(ctx, params) + return res, err +} + +func (c *Client) sendGroupsIDGet(ctx context.Context, params GroupsIDGetParams) (res GroupsIDGetRes, err error) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/groups/{id}"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, "GroupsIDGet", + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [2]string + pathParts[0] = "/groups/" + { + // Encode "id" parameter. + e := uri.NewPathEncoder(uri.PathEncoderConfig{ + Param: "id", + Style: uri.PathStyleSimple, + Explode: false, + }) + if err := func() error { + if unwrapped := int64(params.ID); true { + return e.EncodeValue(conv.Int64ToString(unwrapped)) + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "encode path") + } + encoded, err := e.Result() + if err != nil { + return res, errors.Wrap(err, "encode path") + } + pathParts[1] = encoded + } + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "GET", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeGroupsIDGetResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// GroupsIDPut invokes PUT /groups/{id} operation. +// +// Update group by id. +// +// PUT /groups/{id} +func (c *Client) GroupsIDPut(ctx context.Context, request *GroupUpdate, params GroupsIDPutParams) (GroupsIDPutRes, error) { + res, err := c.sendGroupsIDPut(ctx, request, params) + return res, err +} + +func (c *Client) sendGroupsIDPut(ctx context.Context, request *GroupUpdate, params GroupsIDPutParams) (res GroupsIDPutRes, err error) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("PUT"), + semconv.HTTPRouteKey.String("/groups/{id}"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, "GroupsIDPut", + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [2]string + pathParts[0] = "/groups/" + { + // Encode "id" parameter. + e := uri.NewPathEncoder(uri.PathEncoderConfig{ + Param: "id", + Style: uri.PathStyleSimple, + Explode: false, + }) + if err := func() error { + if unwrapped := int64(params.ID); true { + return e.EncodeValue(conv.Int64ToString(unwrapped)) + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "encode path") + } + encoded, err := e.Result() + if err != nil { + return res, errors.Wrap(err, "encode path") + } + pathParts[1] = encoded + } + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "PUT", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + if err := encodeGroupsIDPutRequest(request, r); err != nil { + return res, errors.Wrap(err, "encode request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeGroupsIDPutResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// GroupsPost invokes POST /groups operation. +// +// Create group. +// +// POST /groups +func (c *Client) GroupsPost(ctx context.Context, request *GroupUpdate) (*Group, error) { + res, err := c.sendGroupsPost(ctx, request) + return res, err +} + +func (c *Client) sendGroupsPost(ctx context.Context, request *GroupUpdate) (res *Group, err error) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/groups"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, "GroupsPost", + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [1]string + pathParts[0] = "/groups" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "POST", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + if err := encodeGroupsPostRequest(request, r); err != nil { + return res, errors.Wrap(err, "encode request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeGroupsPostResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// HealthzGet invokes GET /healthz operation. +// +// GET /healthz +func (c *Client) HealthzGet(ctx context.Context) (*Ok, error) { + res, err := c.sendHealthzGet(ctx) + return res, err +} + +func (c *Client) sendHealthzGet(ctx context.Context) (res *Ok, err error) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/healthz"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, "HealthzGet", + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [1]string + pathParts[0] = "/healthz" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "GET", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeHealthzGetResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// UsersGet invokes GET /users operation. +// +// Get all users. +// +// GET /users +func (c *Client) UsersGet(ctx context.Context) ([]User, error) { + res, err := c.sendUsersGet(ctx) + return res, err +} + +func (c *Client) sendUsersGet(ctx context.Context) (res []User, err error) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/users"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, "UsersGet", + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [1]string + pathParts[0] = "/users" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "GET", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeUsersGetResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// UsersIDDelete invokes DELETE /users/{id} operation. +// +// Delete user by id. +// +// DELETE /users/{id} +func (c *Client) UsersIDDelete(ctx context.Context, params UsersIDDeleteParams) (UsersIDDeleteRes, error) { + res, err := c.sendUsersIDDelete(ctx, params) + return res, err +} + +func (c *Client) sendUsersIDDelete(ctx context.Context, params UsersIDDeleteParams) (res UsersIDDeleteRes, err error) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("DELETE"), + semconv.HTTPRouteKey.String("/users/{id}"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, "UsersIDDelete", + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [2]string + pathParts[0] = "/users/" + { + // Encode "id" parameter. + e := uri.NewPathEncoder(uri.PathEncoderConfig{ + Param: "id", + Style: uri.PathStyleSimple, + Explode: false, + }) + if err := func() error { + if unwrapped := int64(params.ID); true { + return e.EncodeValue(conv.Int64ToString(unwrapped)) + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "encode path") + } + encoded, err := e.Result() + if err != nil { + return res, errors.Wrap(err, "encode path") + } + pathParts[1] = encoded + } + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "DELETE", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeUsersIDDeleteResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// UsersIDGet invokes GET /users/{id} operation. +// +// Get user by id. +// +// GET /users/{id} +func (c *Client) UsersIDGet(ctx context.Context, params UsersIDGetParams) (UsersIDGetRes, error) { + res, err := c.sendUsersIDGet(ctx, params) + return res, err +} + +func (c *Client) sendUsersIDGet(ctx context.Context, params UsersIDGetParams) (res UsersIDGetRes, err error) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/users/{id}"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, "UsersIDGet", + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [2]string + pathParts[0] = "/users/" + { + // Encode "id" parameter. + e := uri.NewPathEncoder(uri.PathEncoderConfig{ + Param: "id", + Style: uri.PathStyleSimple, + Explode: false, + }) + if err := func() error { + if unwrapped := int64(params.ID); true { + return e.EncodeValue(conv.Int64ToString(unwrapped)) + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "encode path") + } + encoded, err := e.Result() + if err != nil { + return res, errors.Wrap(err, "encode path") + } + pathParts[1] = encoded + } + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "GET", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeUsersIDGetResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// UsersIDGroupPut invokes PUT /users/{id}/group operation. +// +// Update user group by id. +// +// PUT /users/{id}/group +func (c *Client) UsersIDGroupPut(ctx context.Context, request *UsersIDGroupPutReq, params UsersIDGroupPutParams) (UsersIDGroupPutRes, error) { + res, err := c.sendUsersIDGroupPut(ctx, request, params) + return res, err +} + +func (c *Client) sendUsersIDGroupPut(ctx context.Context, request *UsersIDGroupPutReq, params UsersIDGroupPutParams) (res UsersIDGroupPutRes, err error) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("PUT"), + semconv.HTTPRouteKey.String("/users/{id}/group"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, "UsersIDGroupPut", + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [3]string + pathParts[0] = "/users/" + { + // Encode "id" parameter. + e := uri.NewPathEncoder(uri.PathEncoderConfig{ + Param: "id", + Style: uri.PathStyleSimple, + Explode: false, + }) + if err := func() error { + if unwrapped := int64(params.ID); true { + return e.EncodeValue(conv.Int64ToString(unwrapped)) + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "encode path") + } + encoded, err := e.Result() + if err != nil { + return res, errors.Wrap(err, "encode path") + } + pathParts[1] = encoded + } + pathParts[2] = "/group" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "PUT", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + if err := encodeUsersIDGroupPutRequest(request, r); err != nil { + return res, errors.Wrap(err, "encode request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeUsersIDGroupPutResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// UsersIDPut invokes PUT /users/{id} operation. +// +// Update user by id. +// +// PUT /users/{id} +func (c *Client) UsersIDPut(ctx context.Context, request *UserUpdate, params UsersIDPutParams) (UsersIDPutRes, error) { + res, err := c.sendUsersIDPut(ctx, request, params) + return res, err +} + +func (c *Client) sendUsersIDPut(ctx context.Context, request *UserUpdate, params UsersIDPutParams) (res UsersIDPutRes, err error) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("PUT"), + semconv.HTTPRouteKey.String("/users/{id}"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, "UsersIDPut", + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [2]string + pathParts[0] = "/users/" + { + // Encode "id" parameter. + e := uri.NewPathEncoder(uri.PathEncoderConfig{ + Param: "id", + Style: uri.PathStyleSimple, + Explode: false, + }) + if err := func() error { + if unwrapped := int64(params.ID); true { + return e.EncodeValue(conv.Int64ToString(unwrapped)) + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "encode path") + } + encoded, err := e.Result() + if err != nil { + return res, errors.Wrap(err, "encode path") + } + pathParts[1] = encoded + } + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "PUT", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + if err := encodeUsersIDPutRequest(request, r); err != nil { + return res, errors.Wrap(err, "encode request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeUsersIDPutResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// UsersPost invokes POST /users operation. +// +// Create user. +// +// POST /users +func (c *Client) UsersPost(ctx context.Context, request *UserUpdate) (*User, error) { + res, err := c.sendUsersPost(ctx, request) + return res, err +} + +func (c *Client) sendUsersPost(ctx context.Context, request *UserUpdate) (res *User, err error) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/users"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, "UsersPost", + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [1]string + pathParts[0] = "/users" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "POST", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + if err := encodeUsersPostRequest(request, r); err != nil { + return res, errors.Wrap(err, "encode request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeUsersPostResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} diff --git a/pkg/api/oas_handlers_gen.go b/pkg/api/oas_handlers_gen.go new file mode 100644 index 0000000..9bf3564 --- /dev/null +++ b/pkg/api/oas_handlers_gen.go @@ -0,0 +1,1398 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +import ( + "context" + "net/http" + "time" + + "github.com/go-faster/errors" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/metric" + semconv "go.opentelemetry.io/otel/semconv/v1.19.0" + "go.opentelemetry.io/otel/trace" + + ht "github.com/ogen-go/ogen/http" + "github.com/ogen-go/ogen/middleware" + "github.com/ogen-go/ogen/ogenerrors" +) + +// handleGroupsGetRequest handles GET /groups operation. +// +// Get all groups. +// +// GET /groups +func (s *Server) handleGroupsGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/groups"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), "GroupsGet", + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + s.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + s.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + err error + ) + + var response []Group + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: "GroupsGet", + OperationSummary: "", + OperationID: "", + Body: nil, + Params: middleware.Parameters{}, + Raw: r, + } + + type ( + Request = struct{} + Params = struct{} + Response = []Group + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + nil, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.GroupsGet(ctx) + return response, err + }, + ) + } else { + response, err = s.h.GroupsGet(ctx) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + recordError("Internal", err) + } + return + } + + if err := encodeGroupsGetResponse(response, w, span); err != nil { + recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + +// handleGroupsIDDeleteRequest handles DELETE /groups/{id} operation. +// +// Delete group by id. +// +// DELETE /groups/{id} +func (s *Server) handleGroupsIDDeleteRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("DELETE"), + semconv.HTTPRouteKey.String("/groups/{id}"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), "GroupsIDDelete", + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + s.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + s.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: "GroupsIDDelete", + ID: "", + } + ) + params, err := decodeGroupsIDDeleteParams(args, argsEscaped, r) + if err != nil { + err = &ogenerrors.DecodeParamsError{ + OperationContext: opErrContext, + Err: err, + } + recordError("DecodeParams", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + + var response GroupsIDDeleteRes + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: "GroupsIDDelete", + OperationSummary: "", + OperationID: "", + Body: nil, + Params: middleware.Parameters{ + { + Name: "id", + In: "path", + }: params.ID, + }, + Raw: r, + } + + type ( + Request = struct{} + Params = GroupsIDDeleteParams + Response = GroupsIDDeleteRes + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + unpackGroupsIDDeleteParams, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.GroupsIDDelete(ctx, params) + return response, err + }, + ) + } else { + response, err = s.h.GroupsIDDelete(ctx, params) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + recordError("Internal", err) + } + return + } + + if err := encodeGroupsIDDeleteResponse(response, w, span); err != nil { + recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + +// handleGroupsIDGetRequest handles GET /groups/{id} operation. +// +// Get group by id. +// +// GET /groups/{id} +func (s *Server) handleGroupsIDGetRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/groups/{id}"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), "GroupsIDGet", + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + s.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + s.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: "GroupsIDGet", + ID: "", + } + ) + params, err := decodeGroupsIDGetParams(args, argsEscaped, r) + if err != nil { + err = &ogenerrors.DecodeParamsError{ + OperationContext: opErrContext, + Err: err, + } + recordError("DecodeParams", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + + var response GroupsIDGetRes + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: "GroupsIDGet", + OperationSummary: "", + OperationID: "", + Body: nil, + Params: middleware.Parameters{ + { + Name: "id", + In: "path", + }: params.ID, + }, + Raw: r, + } + + type ( + Request = struct{} + Params = GroupsIDGetParams + Response = GroupsIDGetRes + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + unpackGroupsIDGetParams, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.GroupsIDGet(ctx, params) + return response, err + }, + ) + } else { + response, err = s.h.GroupsIDGet(ctx, params) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + recordError("Internal", err) + } + return + } + + if err := encodeGroupsIDGetResponse(response, w, span); err != nil { + recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + +// handleGroupsIDPutRequest handles PUT /groups/{id} operation. +// +// Update group by id. +// +// PUT /groups/{id} +func (s *Server) handleGroupsIDPutRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("PUT"), + semconv.HTTPRouteKey.String("/groups/{id}"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), "GroupsIDPut", + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + s.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + s.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: "GroupsIDPut", + ID: "", + } + ) + params, err := decodeGroupsIDPutParams(args, argsEscaped, r) + if err != nil { + err = &ogenerrors.DecodeParamsError{ + OperationContext: opErrContext, + Err: err, + } + recordError("DecodeParams", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + request, close, err := s.decodeGroupsIDPutRequest(r) + if err != nil { + err = &ogenerrors.DecodeRequestError{ + OperationContext: opErrContext, + Err: err, + } + recordError("DecodeRequest", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + defer func() { + if err := close(); err != nil { + recordError("CloseRequest", err) + } + }() + + var response GroupsIDPutRes + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: "GroupsIDPut", + OperationSummary: "", + OperationID: "", + Body: request, + Params: middleware.Parameters{ + { + Name: "id", + In: "path", + }: params.ID, + }, + Raw: r, + } + + type ( + Request = *GroupUpdate + Params = GroupsIDPutParams + Response = GroupsIDPutRes + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + unpackGroupsIDPutParams, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.GroupsIDPut(ctx, request, params) + return response, err + }, + ) + } else { + response, err = s.h.GroupsIDPut(ctx, request, params) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + recordError("Internal", err) + } + return + } + + if err := encodeGroupsIDPutResponse(response, w, span); err != nil { + recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + +// handleGroupsPostRequest handles POST /groups operation. +// +// Create group. +// +// POST /groups +func (s *Server) handleGroupsPostRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/groups"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), "GroupsPost", + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + s.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + s.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: "GroupsPost", + ID: "", + } + ) + request, close, err := s.decodeGroupsPostRequest(r) + if err != nil { + err = &ogenerrors.DecodeRequestError{ + OperationContext: opErrContext, + Err: err, + } + recordError("DecodeRequest", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + defer func() { + if err := close(); err != nil { + recordError("CloseRequest", err) + } + }() + + var response *Group + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: "GroupsPost", + OperationSummary: "", + OperationID: "", + Body: request, + Params: middleware.Parameters{}, + Raw: r, + } + + type ( + Request = *GroupUpdate + Params = struct{} + Response = *Group + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + nil, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.GroupsPost(ctx, request) + return response, err + }, + ) + } else { + response, err = s.h.GroupsPost(ctx, request) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + recordError("Internal", err) + } + return + } + + if err := encodeGroupsPostResponse(response, w, span); err != nil { + recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + +// handleHealthzGetRequest handles GET /healthz operation. +// +// GET /healthz +func (s *Server) handleHealthzGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/healthz"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), "HealthzGet", + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + s.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + s.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + err error + ) + + var response *Ok + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: "HealthzGet", + OperationSummary: "", + OperationID: "", + Body: nil, + Params: middleware.Parameters{}, + Raw: r, + } + + type ( + Request = struct{} + Params = struct{} + Response = *Ok + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + nil, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.HealthzGet(ctx) + return response, err + }, + ) + } else { + response, err = s.h.HealthzGet(ctx) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + recordError("Internal", err) + } + return + } + + if err := encodeHealthzGetResponse(response, w, span); err != nil { + recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + +// handleUsersGetRequest handles GET /users operation. +// +// Get all users. +// +// GET /users +func (s *Server) handleUsersGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/users"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), "UsersGet", + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + s.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + s.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + err error + ) + + var response []User + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: "UsersGet", + OperationSummary: "", + OperationID: "", + Body: nil, + Params: middleware.Parameters{}, + Raw: r, + } + + type ( + Request = struct{} + Params = struct{} + Response = []User + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + nil, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.UsersGet(ctx) + return response, err + }, + ) + } else { + response, err = s.h.UsersGet(ctx) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + recordError("Internal", err) + } + return + } + + if err := encodeUsersGetResponse(response, w, span); err != nil { + recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + +// handleUsersIDDeleteRequest handles DELETE /users/{id} operation. +// +// Delete user by id. +// +// DELETE /users/{id} +func (s *Server) handleUsersIDDeleteRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("DELETE"), + semconv.HTTPRouteKey.String("/users/{id}"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), "UsersIDDelete", + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + s.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + s.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: "UsersIDDelete", + ID: "", + } + ) + params, err := decodeUsersIDDeleteParams(args, argsEscaped, r) + if err != nil { + err = &ogenerrors.DecodeParamsError{ + OperationContext: opErrContext, + Err: err, + } + recordError("DecodeParams", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + + var response UsersIDDeleteRes + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: "UsersIDDelete", + OperationSummary: "", + OperationID: "", + Body: nil, + Params: middleware.Parameters{ + { + Name: "id", + In: "path", + }: params.ID, + }, + Raw: r, + } + + type ( + Request = struct{} + Params = UsersIDDeleteParams + Response = UsersIDDeleteRes + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + unpackUsersIDDeleteParams, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.UsersIDDelete(ctx, params) + return response, err + }, + ) + } else { + response, err = s.h.UsersIDDelete(ctx, params) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + recordError("Internal", err) + } + return + } + + if err := encodeUsersIDDeleteResponse(response, w, span); err != nil { + recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + +// handleUsersIDGetRequest handles GET /users/{id} operation. +// +// Get user by id. +// +// GET /users/{id} +func (s *Server) handleUsersIDGetRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/users/{id}"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), "UsersIDGet", + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + s.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + s.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: "UsersIDGet", + ID: "", + } + ) + params, err := decodeUsersIDGetParams(args, argsEscaped, r) + if err != nil { + err = &ogenerrors.DecodeParamsError{ + OperationContext: opErrContext, + Err: err, + } + recordError("DecodeParams", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + + var response UsersIDGetRes + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: "UsersIDGet", + OperationSummary: "", + OperationID: "", + Body: nil, + Params: middleware.Parameters{ + { + Name: "id", + In: "path", + }: params.ID, + }, + Raw: r, + } + + type ( + Request = struct{} + Params = UsersIDGetParams + Response = UsersIDGetRes + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + unpackUsersIDGetParams, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.UsersIDGet(ctx, params) + return response, err + }, + ) + } else { + response, err = s.h.UsersIDGet(ctx, params) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + recordError("Internal", err) + } + return + } + + if err := encodeUsersIDGetResponse(response, w, span); err != nil { + recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + +// handleUsersIDGroupPutRequest handles PUT /users/{id}/group operation. +// +// Update user group by id. +// +// PUT /users/{id}/group +func (s *Server) handleUsersIDGroupPutRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("PUT"), + semconv.HTTPRouteKey.String("/users/{id}/group"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), "UsersIDGroupPut", + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + s.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + s.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: "UsersIDGroupPut", + ID: "", + } + ) + params, err := decodeUsersIDGroupPutParams(args, argsEscaped, r) + if err != nil { + err = &ogenerrors.DecodeParamsError{ + OperationContext: opErrContext, + Err: err, + } + recordError("DecodeParams", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + request, close, err := s.decodeUsersIDGroupPutRequest(r) + if err != nil { + err = &ogenerrors.DecodeRequestError{ + OperationContext: opErrContext, + Err: err, + } + recordError("DecodeRequest", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + defer func() { + if err := close(); err != nil { + recordError("CloseRequest", err) + } + }() + + var response UsersIDGroupPutRes + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: "UsersIDGroupPut", + OperationSummary: "", + OperationID: "", + Body: request, + Params: middleware.Parameters{ + { + Name: "id", + In: "path", + }: params.ID, + }, + Raw: r, + } + + type ( + Request = *UsersIDGroupPutReq + Params = UsersIDGroupPutParams + Response = UsersIDGroupPutRes + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + unpackUsersIDGroupPutParams, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.UsersIDGroupPut(ctx, request, params) + return response, err + }, + ) + } else { + response, err = s.h.UsersIDGroupPut(ctx, request, params) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + recordError("Internal", err) + } + return + } + + if err := encodeUsersIDGroupPutResponse(response, w, span); err != nil { + recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + +// handleUsersIDPutRequest handles PUT /users/{id} operation. +// +// Update user by id. +// +// PUT /users/{id} +func (s *Server) handleUsersIDPutRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("PUT"), + semconv.HTTPRouteKey.String("/users/{id}"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), "UsersIDPut", + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + s.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + s.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: "UsersIDPut", + ID: "", + } + ) + params, err := decodeUsersIDPutParams(args, argsEscaped, r) + if err != nil { + err = &ogenerrors.DecodeParamsError{ + OperationContext: opErrContext, + Err: err, + } + recordError("DecodeParams", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + request, close, err := s.decodeUsersIDPutRequest(r) + if err != nil { + err = &ogenerrors.DecodeRequestError{ + OperationContext: opErrContext, + Err: err, + } + recordError("DecodeRequest", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + defer func() { + if err := close(); err != nil { + recordError("CloseRequest", err) + } + }() + + var response UsersIDPutRes + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: "UsersIDPut", + OperationSummary: "", + OperationID: "", + Body: request, + Params: middleware.Parameters{ + { + Name: "id", + In: "path", + }: params.ID, + }, + Raw: r, + } + + type ( + Request = *UserUpdate + Params = UsersIDPutParams + Response = UsersIDPutRes + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + unpackUsersIDPutParams, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.UsersIDPut(ctx, request, params) + return response, err + }, + ) + } else { + response, err = s.h.UsersIDPut(ctx, request, params) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + recordError("Internal", err) + } + return + } + + if err := encodeUsersIDPutResponse(response, w, span); err != nil { + recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + +// handleUsersPostRequest handles POST /users operation. +// +// Create user. +// +// POST /users +func (s *Server) handleUsersPostRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + otelAttrs := []attribute.KeyValue{ + semconv.HTTPMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/users"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), "UsersPost", + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + s.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + s.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: "UsersPost", + ID: "", + } + ) + request, close, err := s.decodeUsersPostRequest(r) + if err != nil { + err = &ogenerrors.DecodeRequestError{ + OperationContext: opErrContext, + Err: err, + } + recordError("DecodeRequest", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + defer func() { + if err := close(); err != nil { + recordError("CloseRequest", err) + } + }() + + var response *User + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: "UsersPost", + OperationSummary: "", + OperationID: "", + Body: request, + Params: middleware.Parameters{}, + Raw: r, + } + + type ( + Request = *UserUpdate + Params = struct{} + Response = *User + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + nil, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.UsersPost(ctx, request) + return response, err + }, + ) + } else { + response, err = s.h.UsersPost(ctx, request) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + recordError("Internal", err) + } + return + } + + if err := encodeUsersPostResponse(response, w, span); err != nil { + recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} diff --git a/pkg/api/oas_interfaces_gen.go b/pkg/api/oas_interfaces_gen.go new file mode 100644 index 0000000..aae4046 --- /dev/null +++ b/pkg/api/oas_interfaces_gen.go @@ -0,0 +1,30 @@ +// Code generated by ogen, DO NOT EDIT. +package api + +type GroupsIDDeleteRes interface { + groupsIDDeleteRes() +} + +type GroupsIDGetRes interface { + groupsIDGetRes() +} + +type GroupsIDPutRes interface { + groupsIDPutRes() +} + +type UsersIDDeleteRes interface { + usersIDDeleteRes() +} + +type UsersIDGetRes interface { + usersIDGetRes() +} + +type UsersIDGroupPutRes interface { + usersIDGroupPutRes() +} + +type UsersIDPutRes interface { + usersIDPutRes() +} diff --git a/pkg/api/oas_json_gen.go b/pkg/api/oas_json_gen.go new file mode 100644 index 0000000..adfe890 --- /dev/null +++ b/pkg/api/oas_json_gen.go @@ -0,0 +1,755 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +import ( + "github.com/go-faster/errors" + "github.com/go-faster/jx" +) + +// Encode implements json.Marshaler. +func (s *Error) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *Error) encodeFields(e *jx.Encoder) { + { + if s.Message.Set { + e.FieldStart("message") + s.Message.Encode(e) + } + } + { + if s.Code.Set { + e.FieldStart("code") + s.Code.Encode(e) + } + } +} + +var jsonFieldsNameOfError = [2]string{ + 0: "message", + 1: "code", +} + +// Decode decodes Error from json. +func (s *Error) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode Error to nil") + } + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "message": + if err := func() error { + s.Message.Reset() + if err := s.Message.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"message\"") + } + case "code": + if err := func() error { + s.Code.Reset() + if err := s.Code.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"code\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode Error") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *Error) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *Error) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *Group) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *Group) encodeFields(e *jx.Encoder) { + { + if s.ID.Set { + e.FieldStart("id") + s.ID.Encode(e) + } + } + { + if s.Name.Set { + e.FieldStart("name") + s.Name.Encode(e) + } + } + { + if s.Users != nil { + e.FieldStart("users") + e.ArrStart() + for _, elem := range s.Users { + elem.Encode(e) + } + e.ArrEnd() + } + } +} + +var jsonFieldsNameOfGroup = [3]string{ + 0: "id", + 1: "name", + 2: "users", +} + +// Decode decodes Group from json. +func (s *Group) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode Group to nil") + } + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "id": + if err := func() error { + s.ID.Reset() + if err := s.ID.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"id\"") + } + case "name": + if err := func() error { + s.Name.Reset() + if err := s.Name.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"name\"") + } + case "users": + if err := func() error { + s.Users = make([]User, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem User + if err := elem.Decode(d); err != nil { + return err + } + s.Users = append(s.Users, elem) + return nil + }); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"users\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode Group") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *Group) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *Group) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *GroupUpdate) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *GroupUpdate) encodeFields(e *jx.Encoder) { + { + if s.Name.Set { + e.FieldStart("name") + s.Name.Encode(e) + } + } +} + +var jsonFieldsNameOfGroupUpdate = [1]string{ + 0: "name", +} + +// Decode decodes GroupUpdate from json. +func (s *GroupUpdate) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode GroupUpdate to nil") + } + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "name": + if err := func() error { + s.Name.Reset() + if err := s.Name.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"name\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode GroupUpdate") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *GroupUpdate) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *GroupUpdate) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes ID as json. +func (s ID) Encode(e *jx.Encoder) { + unwrapped := int64(s) + + e.Int64(unwrapped) +} + +// Decode decodes ID from json. +func (s *ID) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode ID to nil") + } + var unwrapped int64 + if err := func() error { + v, err := d.Int64() + unwrapped = int64(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "alias") + } + *s = ID(unwrapped) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s ID) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *ID) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *Ok) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *Ok) encodeFields(e *jx.Encoder) { + { + if s.Message.Set { + e.FieldStart("message") + s.Message.Encode(e) + } + } +} + +var jsonFieldsNameOfOk = [1]string{ + 0: "message", +} + +// Decode decodes Ok from json. +func (s *Ok) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode Ok to nil") + } + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "message": + if err := func() error { + s.Message.Reset() + if err := s.Message.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"message\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode Ok") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *Ok) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *Ok) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes Group as json. +func (o OptGroup) Encode(e *jx.Encoder) { + if !o.Set { + return + } + o.Value.Encode(e) +} + +// Decode decodes Group from json. +func (o *OptGroup) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptGroup to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptGroup) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptGroup) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes ID as json. +func (o OptID) Encode(e *jx.Encoder) { + if !o.Set { + return + } + o.Value.Encode(e) +} + +// Decode decodes ID from json. +func (o *OptID) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptID to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptID) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptID) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes int as json. +func (o OptInt) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.Int(int(o.Value)) +} + +// Decode decodes int from json. +func (o *OptInt) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptInt to nil") + } + o.Set = true + v, err := d.Int() + if err != nil { + return err + } + o.Value = int(v) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptInt) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptInt) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes string as json. +func (o OptString) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.Str(string(o.Value)) +} + +// Decode decodes string from json. +func (o *OptString) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptString to nil") + } + o.Set = true + v, err := d.Str() + if err != nil { + return err + } + o.Value = string(v) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptString) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptString) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *User) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *User) encodeFields(e *jx.Encoder) { + { + if s.ID.Set { + e.FieldStart("id") + s.ID.Encode(e) + } + } + { + if s.Name.Set { + e.FieldStart("name") + s.Name.Encode(e) + } + } + { + if s.Email.Set { + e.FieldStart("email") + s.Email.Encode(e) + } + } + { + if s.Group.Set { + e.FieldStart("group") + s.Group.Encode(e) + } + } +} + +var jsonFieldsNameOfUser = [4]string{ + 0: "id", + 1: "name", + 2: "email", + 3: "group", +} + +// Decode decodes User from json. +func (s *User) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode User to nil") + } + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "id": + if err := func() error { + s.ID.Reset() + if err := s.ID.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"id\"") + } + case "name": + if err := func() error { + s.Name.Reset() + if err := s.Name.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"name\"") + } + case "email": + if err := func() error { + s.Email.Reset() + if err := s.Email.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"email\"") + } + case "group": + if err := func() error { + s.Group.Reset() + if err := s.Group.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"group\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode User") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *User) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *User) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *UserUpdate) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *UserUpdate) encodeFields(e *jx.Encoder) { + { + if s.Name.Set { + e.FieldStart("name") + s.Name.Encode(e) + } + } + { + if s.Email.Set { + e.FieldStart("email") + s.Email.Encode(e) + } + } +} + +var jsonFieldsNameOfUserUpdate = [2]string{ + 0: "name", + 1: "email", +} + +// Decode decodes UserUpdate from json. +func (s *UserUpdate) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode UserUpdate to nil") + } + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "name": + if err := func() error { + s.Name.Reset() + if err := s.Name.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"name\"") + } + case "email": + if err := func() error { + s.Email.Reset() + if err := s.Email.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"email\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode UserUpdate") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *UserUpdate) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *UserUpdate) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *UsersIDGroupPutReq) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *UsersIDGroupPutReq) encodeFields(e *jx.Encoder) { + { + if s.Group.Set { + e.FieldStart("group") + s.Group.Encode(e) + } + } +} + +var jsonFieldsNameOfUsersIDGroupPutReq = [1]string{ + 0: "group", +} + +// Decode decodes UsersIDGroupPutReq from json. +func (s *UsersIDGroupPutReq) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode UsersIDGroupPutReq to nil") + } + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "group": + if err := func() error { + s.Group.Reset() + if err := s.Group.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"group\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode UsersIDGroupPutReq") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *UsersIDGroupPutReq) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *UsersIDGroupPutReq) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} diff --git a/pkg/api/oas_middleware_gen.go b/pkg/api/oas_middleware_gen.go new file mode 100644 index 0000000..6f58a1a --- /dev/null +++ b/pkg/api/oas_middleware_gen.go @@ -0,0 +1,10 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +import ( + "github.com/ogen-go/ogen/middleware" +) + +// Middleware is middleware type. +type Middleware = middleware.Middleware diff --git a/pkg/api/oas_parameters_gen.go b/pkg/api/oas_parameters_gen.go new file mode 100644 index 0000000..5e6351d --- /dev/null +++ b/pkg/api/oas_parameters_gen.go @@ -0,0 +1,520 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +import ( + "net/http" + "net/url" + + "github.com/go-faster/errors" + + "github.com/ogen-go/ogen/conv" + "github.com/ogen-go/ogen/middleware" + "github.com/ogen-go/ogen/ogenerrors" + "github.com/ogen-go/ogen/uri" + "github.com/ogen-go/ogen/validate" +) + +// GroupsIDDeleteParams is parameters of DELETE /groups/{id} operation. +type GroupsIDDeleteParams struct { + ID ID +} + +func unpackGroupsIDDeleteParams(packed middleware.Parameters) (params GroupsIDDeleteParams) { + { + key := middleware.ParameterKey{ + Name: "id", + In: "path", + } + params.ID = packed[key].(ID) + } + return params +} + +func decodeGroupsIDDeleteParams(args [1]string, argsEscaped bool, r *http.Request) (params GroupsIDDeleteParams, _ error) { + // Decode path: id. + if err := func() error { + param := args[0] + if argsEscaped { + unescaped, err := url.PathUnescape(args[0]) + if err != nil { + return errors.Wrap(err, "unescape path") + } + param = unescaped + } + if len(param) > 0 { + d := uri.NewPathDecoder(uri.PathDecoderConfig{ + Param: "id", + Value: param, + Style: uri.PathStyleSimple, + Explode: false, + }) + + if err := func() error { + var paramsDotIDVal int64 + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToInt64(val) + if err != nil { + return err + } + + paramsDotIDVal = c + return nil + }(); err != nil { + return err + } + params.ID = ID(paramsDotIDVal) + return nil + }(); err != nil { + return err + } + } else { + return validate.ErrFieldRequired + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "id", + In: "path", + Err: err, + } + } + return params, nil +} + +// GroupsIDGetParams is parameters of GET /groups/{id} operation. +type GroupsIDGetParams struct { + ID ID +} + +func unpackGroupsIDGetParams(packed middleware.Parameters) (params GroupsIDGetParams) { + { + key := middleware.ParameterKey{ + Name: "id", + In: "path", + } + params.ID = packed[key].(ID) + } + return params +} + +func decodeGroupsIDGetParams(args [1]string, argsEscaped bool, r *http.Request) (params GroupsIDGetParams, _ error) { + // Decode path: id. + if err := func() error { + param := args[0] + if argsEscaped { + unescaped, err := url.PathUnescape(args[0]) + if err != nil { + return errors.Wrap(err, "unescape path") + } + param = unescaped + } + if len(param) > 0 { + d := uri.NewPathDecoder(uri.PathDecoderConfig{ + Param: "id", + Value: param, + Style: uri.PathStyleSimple, + Explode: false, + }) + + if err := func() error { + var paramsDotIDVal int64 + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToInt64(val) + if err != nil { + return err + } + + paramsDotIDVal = c + return nil + }(); err != nil { + return err + } + params.ID = ID(paramsDotIDVal) + return nil + }(); err != nil { + return err + } + } else { + return validate.ErrFieldRequired + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "id", + In: "path", + Err: err, + } + } + return params, nil +} + +// GroupsIDPutParams is parameters of PUT /groups/{id} operation. +type GroupsIDPutParams struct { + ID ID +} + +func unpackGroupsIDPutParams(packed middleware.Parameters) (params GroupsIDPutParams) { + { + key := middleware.ParameterKey{ + Name: "id", + In: "path", + } + params.ID = packed[key].(ID) + } + return params +} + +func decodeGroupsIDPutParams(args [1]string, argsEscaped bool, r *http.Request) (params GroupsIDPutParams, _ error) { + // Decode path: id. + if err := func() error { + param := args[0] + if argsEscaped { + unescaped, err := url.PathUnescape(args[0]) + if err != nil { + return errors.Wrap(err, "unescape path") + } + param = unescaped + } + if len(param) > 0 { + d := uri.NewPathDecoder(uri.PathDecoderConfig{ + Param: "id", + Value: param, + Style: uri.PathStyleSimple, + Explode: false, + }) + + if err := func() error { + var paramsDotIDVal int64 + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToInt64(val) + if err != nil { + return err + } + + paramsDotIDVal = c + return nil + }(); err != nil { + return err + } + params.ID = ID(paramsDotIDVal) + return nil + }(); err != nil { + return err + } + } else { + return validate.ErrFieldRequired + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "id", + In: "path", + Err: err, + } + } + return params, nil +} + +// UsersIDDeleteParams is parameters of DELETE /users/{id} operation. +type UsersIDDeleteParams struct { + ID ID +} + +func unpackUsersIDDeleteParams(packed middleware.Parameters) (params UsersIDDeleteParams) { + { + key := middleware.ParameterKey{ + Name: "id", + In: "path", + } + params.ID = packed[key].(ID) + } + return params +} + +func decodeUsersIDDeleteParams(args [1]string, argsEscaped bool, r *http.Request) (params UsersIDDeleteParams, _ error) { + // Decode path: id. + if err := func() error { + param := args[0] + if argsEscaped { + unescaped, err := url.PathUnescape(args[0]) + if err != nil { + return errors.Wrap(err, "unescape path") + } + param = unescaped + } + if len(param) > 0 { + d := uri.NewPathDecoder(uri.PathDecoderConfig{ + Param: "id", + Value: param, + Style: uri.PathStyleSimple, + Explode: false, + }) + + if err := func() error { + var paramsDotIDVal int64 + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToInt64(val) + if err != nil { + return err + } + + paramsDotIDVal = c + return nil + }(); err != nil { + return err + } + params.ID = ID(paramsDotIDVal) + return nil + }(); err != nil { + return err + } + } else { + return validate.ErrFieldRequired + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "id", + In: "path", + Err: err, + } + } + return params, nil +} + +// UsersIDGetParams is parameters of GET /users/{id} operation. +type UsersIDGetParams struct { + ID ID +} + +func unpackUsersIDGetParams(packed middleware.Parameters) (params UsersIDGetParams) { + { + key := middleware.ParameterKey{ + Name: "id", + In: "path", + } + params.ID = packed[key].(ID) + } + return params +} + +func decodeUsersIDGetParams(args [1]string, argsEscaped bool, r *http.Request) (params UsersIDGetParams, _ error) { + // Decode path: id. + if err := func() error { + param := args[0] + if argsEscaped { + unescaped, err := url.PathUnescape(args[0]) + if err != nil { + return errors.Wrap(err, "unescape path") + } + param = unescaped + } + if len(param) > 0 { + d := uri.NewPathDecoder(uri.PathDecoderConfig{ + Param: "id", + Value: param, + Style: uri.PathStyleSimple, + Explode: false, + }) + + if err := func() error { + var paramsDotIDVal int64 + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToInt64(val) + if err != nil { + return err + } + + paramsDotIDVal = c + return nil + }(); err != nil { + return err + } + params.ID = ID(paramsDotIDVal) + return nil + }(); err != nil { + return err + } + } else { + return validate.ErrFieldRequired + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "id", + In: "path", + Err: err, + } + } + return params, nil +} + +// UsersIDGroupPutParams is parameters of PUT /users/{id}/group operation. +type UsersIDGroupPutParams struct { + ID ID +} + +func unpackUsersIDGroupPutParams(packed middleware.Parameters) (params UsersIDGroupPutParams) { + { + key := middleware.ParameterKey{ + Name: "id", + In: "path", + } + params.ID = packed[key].(ID) + } + return params +} + +func decodeUsersIDGroupPutParams(args [1]string, argsEscaped bool, r *http.Request) (params UsersIDGroupPutParams, _ error) { + // Decode path: id. + if err := func() error { + param := args[0] + if argsEscaped { + unescaped, err := url.PathUnescape(args[0]) + if err != nil { + return errors.Wrap(err, "unescape path") + } + param = unescaped + } + if len(param) > 0 { + d := uri.NewPathDecoder(uri.PathDecoderConfig{ + Param: "id", + Value: param, + Style: uri.PathStyleSimple, + Explode: false, + }) + + if err := func() error { + var paramsDotIDVal int64 + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToInt64(val) + if err != nil { + return err + } + + paramsDotIDVal = c + return nil + }(); err != nil { + return err + } + params.ID = ID(paramsDotIDVal) + return nil + }(); err != nil { + return err + } + } else { + return validate.ErrFieldRequired + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "id", + In: "path", + Err: err, + } + } + return params, nil +} + +// UsersIDPutParams is parameters of PUT /users/{id} operation. +type UsersIDPutParams struct { + ID ID +} + +func unpackUsersIDPutParams(packed middleware.Parameters) (params UsersIDPutParams) { + { + key := middleware.ParameterKey{ + Name: "id", + In: "path", + } + params.ID = packed[key].(ID) + } + return params +} + +func decodeUsersIDPutParams(args [1]string, argsEscaped bool, r *http.Request) (params UsersIDPutParams, _ error) { + // Decode path: id. + if err := func() error { + param := args[0] + if argsEscaped { + unescaped, err := url.PathUnescape(args[0]) + if err != nil { + return errors.Wrap(err, "unescape path") + } + param = unescaped + } + if len(param) > 0 { + d := uri.NewPathDecoder(uri.PathDecoderConfig{ + Param: "id", + Value: param, + Style: uri.PathStyleSimple, + Explode: false, + }) + + if err := func() error { + var paramsDotIDVal int64 + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToInt64(val) + if err != nil { + return err + } + + paramsDotIDVal = c + return nil + }(); err != nil { + return err + } + params.ID = ID(paramsDotIDVal) + return nil + }(); err != nil { + return err + } + } else { + return validate.ErrFieldRequired + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "id", + In: "path", + Err: err, + } + } + return params, nil +} diff --git a/pkg/api/oas_request_decoders_gen.go b/pkg/api/oas_request_decoders_gen.go new file mode 100644 index 0000000..cea7e00 --- /dev/null +++ b/pkg/api/oas_request_decoders_gen.go @@ -0,0 +1,331 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +import ( + "io" + "mime" + "net/http" + + "github.com/go-faster/errors" + "github.com/go-faster/jx" + "go.uber.org/multierr" + + "github.com/ogen-go/ogen/ogenerrors" + "github.com/ogen-go/ogen/validate" +) + +func (s *Server) decodeGroupsIDPutRequest(r *http.Request) ( + req *GroupUpdate, + close func() error, + rerr error, +) { + var closers []func() error + close = func() error { + var merr error + // Close in reverse order, to match defer behavior. + for i := len(closers) - 1; i >= 0; i-- { + c := closers[i] + merr = multierr.Append(merr, c()) + } + return merr + } + defer func() { + if rerr != nil { + rerr = multierr.Append(rerr, close()) + } + }() + ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) + if err != nil { + return req, close, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + if r.ContentLength == 0 { + return req, close, validate.ErrBodyRequired + } + buf, err := io.ReadAll(r.Body) + if err != nil { + return req, close, err + } + + if len(buf) == 0 { + return req, close, validate.ErrBodyRequired + } + + d := jx.DecodeBytes(buf) + + var request GroupUpdate + if err := func() error { + if err := request.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return req, close, err + } + return &request, close, nil + default: + return req, close, validate.InvalidContentType(ct) + } +} + +func (s *Server) decodeGroupsPostRequest(r *http.Request) ( + req *GroupUpdate, + close func() error, + rerr error, +) { + var closers []func() error + close = func() error { + var merr error + // Close in reverse order, to match defer behavior. + for i := len(closers) - 1; i >= 0; i-- { + c := closers[i] + merr = multierr.Append(merr, c()) + } + return merr + } + defer func() { + if rerr != nil { + rerr = multierr.Append(rerr, close()) + } + }() + ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) + if err != nil { + return req, close, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + if r.ContentLength == 0 { + return req, close, validate.ErrBodyRequired + } + buf, err := io.ReadAll(r.Body) + if err != nil { + return req, close, err + } + + if len(buf) == 0 { + return req, close, validate.ErrBodyRequired + } + + d := jx.DecodeBytes(buf) + + var request GroupUpdate + if err := func() error { + if err := request.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return req, close, err + } + return &request, close, nil + default: + return req, close, validate.InvalidContentType(ct) + } +} + +func (s *Server) decodeUsersIDGroupPutRequest(r *http.Request) ( + req *UsersIDGroupPutReq, + close func() error, + rerr error, +) { + var closers []func() error + close = func() error { + var merr error + // Close in reverse order, to match defer behavior. + for i := len(closers) - 1; i >= 0; i-- { + c := closers[i] + merr = multierr.Append(merr, c()) + } + return merr + } + defer func() { + if rerr != nil { + rerr = multierr.Append(rerr, close()) + } + }() + ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) + if err != nil { + return req, close, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + if r.ContentLength == 0 { + return req, close, validate.ErrBodyRequired + } + buf, err := io.ReadAll(r.Body) + if err != nil { + return req, close, err + } + + if len(buf) == 0 { + return req, close, validate.ErrBodyRequired + } + + d := jx.DecodeBytes(buf) + + var request UsersIDGroupPutReq + if err := func() error { + if err := request.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return req, close, err + } + return &request, close, nil + default: + return req, close, validate.InvalidContentType(ct) + } +} + +func (s *Server) decodeUsersIDPutRequest(r *http.Request) ( + req *UserUpdate, + close func() error, + rerr error, +) { + var closers []func() error + close = func() error { + var merr error + // Close in reverse order, to match defer behavior. + for i := len(closers) - 1; i >= 0; i-- { + c := closers[i] + merr = multierr.Append(merr, c()) + } + return merr + } + defer func() { + if rerr != nil { + rerr = multierr.Append(rerr, close()) + } + }() + ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) + if err != nil { + return req, close, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + if r.ContentLength == 0 { + return req, close, validate.ErrBodyRequired + } + buf, err := io.ReadAll(r.Body) + if err != nil { + return req, close, err + } + + if len(buf) == 0 { + return req, close, validate.ErrBodyRequired + } + + d := jx.DecodeBytes(buf) + + var request UserUpdate + if err := func() error { + if err := request.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return req, close, err + } + return &request, close, nil + default: + return req, close, validate.InvalidContentType(ct) + } +} + +func (s *Server) decodeUsersPostRequest(r *http.Request) ( + req *UserUpdate, + close func() error, + rerr error, +) { + var closers []func() error + close = func() error { + var merr error + // Close in reverse order, to match defer behavior. + for i := len(closers) - 1; i >= 0; i-- { + c := closers[i] + merr = multierr.Append(merr, c()) + } + return merr + } + defer func() { + if rerr != nil { + rerr = multierr.Append(rerr, close()) + } + }() + ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) + if err != nil { + return req, close, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + if r.ContentLength == 0 { + return req, close, validate.ErrBodyRequired + } + buf, err := io.ReadAll(r.Body) + if err != nil { + return req, close, err + } + + if len(buf) == 0 { + return req, close, validate.ErrBodyRequired + } + + d := jx.DecodeBytes(buf) + + var request UserUpdate + if err := func() error { + if err := request.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return req, close, err + } + return &request, close, nil + default: + return req, close, validate.InvalidContentType(ct) + } +} diff --git a/pkg/api/oas_request_encoders_gen.go b/pkg/api/oas_request_encoders_gen.go new file mode 100644 index 0000000..3003827 --- /dev/null +++ b/pkg/api/oas_request_encoders_gen.go @@ -0,0 +1,82 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +import ( + "bytes" + "net/http" + + "github.com/go-faster/jx" + + ht "github.com/ogen-go/ogen/http" +) + +func encodeGroupsIDPutRequest( + req *GroupUpdate, + r *http.Request, +) error { + const contentType = "application/json" + e := new(jx.Encoder) + { + req.Encode(e) + } + encoded := e.Bytes() + ht.SetBody(r, bytes.NewReader(encoded), contentType) + return nil +} + +func encodeGroupsPostRequest( + req *GroupUpdate, + r *http.Request, +) error { + const contentType = "application/json" + e := new(jx.Encoder) + { + req.Encode(e) + } + encoded := e.Bytes() + ht.SetBody(r, bytes.NewReader(encoded), contentType) + return nil +} + +func encodeUsersIDGroupPutRequest( + req *UsersIDGroupPutReq, + r *http.Request, +) error { + const contentType = "application/json" + e := new(jx.Encoder) + { + req.Encode(e) + } + encoded := e.Bytes() + ht.SetBody(r, bytes.NewReader(encoded), contentType) + return nil +} + +func encodeUsersIDPutRequest( + req *UserUpdate, + r *http.Request, +) error { + const contentType = "application/json" + e := new(jx.Encoder) + { + req.Encode(e) + } + encoded := e.Bytes() + ht.SetBody(r, bytes.NewReader(encoded), contentType) + return nil +} + +func encodeUsersPostRequest( + req *UserUpdate, + r *http.Request, +) error { + const contentType = "application/json" + e := new(jx.Encoder) + { + req.Encode(e) + } + encoded := e.Bytes() + ht.SetBody(r, bytes.NewReader(encoded), contentType) + return nil +} diff --git a/pkg/api/oas_response_decoders_gen.go b/pkg/api/oas_response_decoders_gen.go new file mode 100644 index 0000000..ead0fac --- /dev/null +++ b/pkg/api/oas_response_decoders_gen.go @@ -0,0 +1,1290 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +import ( + "io" + "mime" + "net/http" + + "github.com/go-faster/errors" + "github.com/go-faster/jx" + + "github.com/ogen-go/ogen/ogenerrors" + "github.com/ogen-go/ogen/validate" +) + +func decodeGroupsGetResponse(resp *http.Response) (res []Group, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response []Group + if err := func() error { + response = make([]Group, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem Group + if err := elem.Decode(d); err != nil { + return err + } + response = append(response, elem) + return nil + }); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if response == nil { + return errors.New("nil is invalid value") + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + +func decodeGroupsIDDeleteResponse(resp *http.Response) (res GroupsIDDeleteRes, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Ok + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + case 404: + // Code 404. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + +func decodeGroupsIDGetResponse(resp *http.Response) (res GroupsIDGetRes, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Group + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + case 404: + // Code 404. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + +func decodeGroupsIDPutResponse(resp *http.Response) (res GroupsIDPutRes, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Group + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + case 404: + // Code 404. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + +func decodeGroupsPostResponse(resp *http.Response) (res *Group, _ error) { + switch resp.StatusCode { + case 201: + // Code 201. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Group + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + +func decodeHealthzGetResponse(resp *http.Response) (res *Ok, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Ok + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + +func decodeUsersGetResponse(resp *http.Response) (res []User, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response []User + if err := func() error { + response = make([]User, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem User + if err := elem.Decode(d); err != nil { + return err + } + response = append(response, elem) + return nil + }); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if response == nil { + return errors.New("nil is invalid value") + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + +func decodeUsersIDDeleteResponse(resp *http.Response) (res UsersIDDeleteRes, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Ok + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + case 404: + // Code 404. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + +func decodeUsersIDGetResponse(resp *http.Response) (res UsersIDGetRes, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response User + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + case 404: + // Code 404. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + +func decodeUsersIDGroupPutResponse(resp *http.Response) (res UsersIDGroupPutRes, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response User + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + case 404: + // Code 404. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + +func decodeUsersIDPutResponse(resp *http.Response) (res UsersIDPutRes, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response User + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + case 404: + // Code 404. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + +func decodeUsersPostResponse(resp *http.Response) (res *User, _ error) { + switch resp.StatusCode { + case 201: + // Code 201. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response User + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} diff --git a/pkg/api/oas_response_encoders_gen.go b/pkg/api/oas_response_encoders_gen.go new file mode 100644 index 0000000..bc4eed5 --- /dev/null +++ b/pkg/api/oas_response_encoders_gen.go @@ -0,0 +1,350 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +import ( + "net/http" + + "github.com/go-faster/errors" + "github.com/go-faster/jx" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/trace" + + ht "github.com/ogen-go/ogen/http" +) + +func encodeGroupsGetResponse(response []Group, w http.ResponseWriter, span trace.Span) error { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(200) + span.SetStatus(codes.Ok, http.StatusText(200)) + + e := new(jx.Encoder) + e.ArrStart() + for _, elem := range response { + elem.Encode(e) + } + e.ArrEnd() + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil +} + +func encodeGroupsIDDeleteResponse(response GroupsIDDeleteRes, w http.ResponseWriter, span trace.Span) error { + switch response := response.(type) { + case *Ok: + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(200) + span.SetStatus(codes.Ok, http.StatusText(200)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil + + case *Error: + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(404) + span.SetStatus(codes.Error, http.StatusText(404)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil + + default: + return errors.Errorf("unexpected response type: %T", response) + } +} + +func encodeGroupsIDGetResponse(response GroupsIDGetRes, w http.ResponseWriter, span trace.Span) error { + switch response := response.(type) { + case *Group: + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(200) + span.SetStatus(codes.Ok, http.StatusText(200)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil + + case *Error: + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(404) + span.SetStatus(codes.Error, http.StatusText(404)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil + + default: + return errors.Errorf("unexpected response type: %T", response) + } +} + +func encodeGroupsIDPutResponse(response GroupsIDPutRes, w http.ResponseWriter, span trace.Span) error { + switch response := response.(type) { + case *Group: + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(200) + span.SetStatus(codes.Ok, http.StatusText(200)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil + + case *Error: + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(404) + span.SetStatus(codes.Error, http.StatusText(404)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil + + default: + return errors.Errorf("unexpected response type: %T", response) + } +} + +func encodeGroupsPostResponse(response *Group, w http.ResponseWriter, span trace.Span) error { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(201) + span.SetStatus(codes.Ok, http.StatusText(201)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil +} + +func encodeHealthzGetResponse(response *Ok, w http.ResponseWriter, span trace.Span) error { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(200) + span.SetStatus(codes.Ok, http.StatusText(200)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil +} + +func encodeUsersGetResponse(response []User, w http.ResponseWriter, span trace.Span) error { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(200) + span.SetStatus(codes.Ok, http.StatusText(200)) + + e := new(jx.Encoder) + e.ArrStart() + for _, elem := range response { + elem.Encode(e) + } + e.ArrEnd() + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil +} + +func encodeUsersIDDeleteResponse(response UsersIDDeleteRes, w http.ResponseWriter, span trace.Span) error { + switch response := response.(type) { + case *Ok: + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(200) + span.SetStatus(codes.Ok, http.StatusText(200)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil + + case *Error: + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(404) + span.SetStatus(codes.Error, http.StatusText(404)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil + + default: + return errors.Errorf("unexpected response type: %T", response) + } +} + +func encodeUsersIDGetResponse(response UsersIDGetRes, w http.ResponseWriter, span trace.Span) error { + switch response := response.(type) { + case *User: + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(200) + span.SetStatus(codes.Ok, http.StatusText(200)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil + + case *Error: + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(404) + span.SetStatus(codes.Error, http.StatusText(404)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil + + default: + return errors.Errorf("unexpected response type: %T", response) + } +} + +func encodeUsersIDGroupPutResponse(response UsersIDGroupPutRes, w http.ResponseWriter, span trace.Span) error { + switch response := response.(type) { + case *User: + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(200) + span.SetStatus(codes.Ok, http.StatusText(200)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil + + case *Error: + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(404) + span.SetStatus(codes.Error, http.StatusText(404)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil + + default: + return errors.Errorf("unexpected response type: %T", response) + } +} + +func encodeUsersIDPutResponse(response UsersIDPutRes, w http.ResponseWriter, span trace.Span) error { + switch response := response.(type) { + case *User: + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(200) + span.SetStatus(codes.Ok, http.StatusText(200)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil + + case *Error: + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(404) + span.SetStatus(codes.Error, http.StatusText(404)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil + + default: + return errors.Errorf("unexpected response type: %T", response) + } +} + +func encodeUsersPostResponse(response *User, w http.ResponseWriter, span trace.Span) error { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(201) + span.SetStatus(codes.Ok, http.StatusText(201)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil +} + +func encodeErrorResponse(response *ErrorStatusCode, w http.ResponseWriter, span trace.Span) error { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + code := response.StatusCode + if code == 0 { + // Set default status code. + code = http.StatusOK + } + w.WriteHeader(code) + if st := http.StatusText(code); code >= http.StatusBadRequest { + span.SetStatus(codes.Error, st) + } else { + span.SetStatus(codes.Ok, st) + } + + e := new(jx.Encoder) + response.Response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + if code >= http.StatusInternalServerError { + return errors.Wrapf(ht.ErrInternalServerErrorResponse, "code: %d, message: %s", code, http.StatusText(code)) + } + return nil + +} diff --git a/pkg/api/oas_router_gen.go b/pkg/api/oas_router_gen.go new file mode 100644 index 0000000..f5d102b --- /dev/null +++ b/pkg/api/oas_router_gen.go @@ -0,0 +1,551 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +import ( + "net/http" + "net/url" + "strings" + + "github.com/ogen-go/ogen/uri" +) + +func (s *Server) cutPrefix(path string) (string, bool) { + prefix := s.cfg.Prefix + if prefix == "" { + return path, true + } + if !strings.HasPrefix(path, prefix) { + // Prefix doesn't match. + return "", false + } + // Cut prefix from the path. + return strings.TrimPrefix(path, prefix), true +} + +// ServeHTTP serves http request as defined by OpenAPI v3 specification, +// calling handler that matches the path or returning not found error. +func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { + elem := r.URL.Path + elemIsEscaped := false + if rawPath := r.URL.RawPath; rawPath != "" { + if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok { + elem = normalized + elemIsEscaped = strings.ContainsRune(elem, '%') + } + } + + elem, ok := s.cutPrefix(elem) + if !ok || len(elem) == 0 { + s.notFound(w, r) + return + } + args := [1]string{} + + // Static code generated router with unwrapped path search. + switch { + default: + if len(elem) == 0 { + break + } + switch elem[0] { + case '/': // Prefix: "/" + origElem := elem + if l := len("/"); len(elem) >= l && elem[0:l] == "/" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 'g': // Prefix: "groups" + origElem := elem + if l := len("groups"); len(elem) >= l && elem[0:l] == "groups" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + switch r.Method { + case "GET": + s.handleGroupsGetRequest([0]string{}, elemIsEscaped, w, r) + case "POST": + s.handleGroupsPostRequest([0]string{}, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "GET,POST") + } + + return + } + switch elem[0] { + case '/': // Prefix: "/" + origElem := elem + if l := len("/"); len(elem) >= l && elem[0:l] == "/" { + elem = elem[l:] + } else { + break + } + + // Param: "id" + // Leaf parameter + args[0] = elem + elem = "" + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "DELETE": + s.handleGroupsIDDeleteRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + case "GET": + s.handleGroupsIDGetRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + case "PUT": + s.handleGroupsIDPutRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "DELETE,GET,PUT") + } + + return + } + + elem = origElem + } + + elem = origElem + case 'h': // Prefix: "healthz" + origElem := elem + if l := len("healthz"); len(elem) >= l && elem[0:l] == "healthz" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "GET": + s.handleHealthzGetRequest([0]string{}, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "GET") + } + + return + } + + elem = origElem + case 'u': // Prefix: "users" + origElem := elem + if l := len("users"); len(elem) >= l && elem[0:l] == "users" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + switch r.Method { + case "GET": + s.handleUsersGetRequest([0]string{}, elemIsEscaped, w, r) + case "POST": + s.handleUsersPostRequest([0]string{}, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "GET,POST") + } + + return + } + switch elem[0] { + case '/': // Prefix: "/" + origElem := elem + if l := len("/"); len(elem) >= l && elem[0:l] == "/" { + elem = elem[l:] + } else { + break + } + + // Param: "id" + // Match until "/" + idx := strings.IndexByte(elem, '/') + if idx < 0 { + idx = len(elem) + } + args[0] = elem[:idx] + elem = elem[idx:] + + if len(elem) == 0 { + switch r.Method { + case "DELETE": + s.handleUsersIDDeleteRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + case "GET": + s.handleUsersIDGetRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + case "PUT": + s.handleUsersIDPutRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "DELETE,GET,PUT") + } + + return + } + switch elem[0] { + case '/': // Prefix: "/group" + origElem := elem + if l := len("/group"); len(elem) >= l && elem[0:l] == "/group" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "PUT": + s.handleUsersIDGroupPutRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "PUT") + } + + return + } + + elem = origElem + } + + elem = origElem + } + + elem = origElem + } + + elem = origElem + } + } + s.notFound(w, r) +} + +// Route is route object. +type Route struct { + name string + summary string + operationID string + pathPattern string + count int + args [1]string +} + +// Name returns ogen operation name. +// +// It is guaranteed to be unique and not empty. +func (r Route) Name() string { + return r.name +} + +// Summary returns OpenAPI summary. +func (r Route) Summary() string { + return r.summary +} + +// OperationID returns OpenAPI operationId. +func (r Route) OperationID() string { + return r.operationID +} + +// PathPattern returns OpenAPI path. +func (r Route) PathPattern() string { + return r.pathPattern +} + +// Args returns parsed arguments. +func (r Route) Args() []string { + return r.args[:r.count] +} + +// FindRoute finds Route for given method and path. +// +// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead. +func (s *Server) FindRoute(method, path string) (Route, bool) { + return s.FindPath(method, &url.URL{Path: path}) +} + +// FindPath finds Route for given method and URL. +func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { + var ( + elem = u.Path + args = r.args + ) + if rawPath := u.RawPath; rawPath != "" { + if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok { + elem = normalized + } + defer func() { + for i, arg := range r.args[:r.count] { + if unescaped, err := url.PathUnescape(arg); err == nil { + r.args[i] = unescaped + } + } + }() + } + + elem, ok := s.cutPrefix(elem) + if !ok { + return r, false + } + + // Static code generated router with unwrapped path search. + switch { + default: + if len(elem) == 0 { + break + } + switch elem[0] { + case '/': // Prefix: "/" + origElem := elem + if l := len("/"); len(elem) >= l && elem[0:l] == "/" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 'g': // Prefix: "groups" + origElem := elem + if l := len("groups"); len(elem) >= l && elem[0:l] == "groups" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + switch method { + case "GET": + r.name = "GroupsGet" + r.summary = "" + r.operationID = "" + r.pathPattern = "/groups" + r.args = args + r.count = 0 + return r, true + case "POST": + r.name = "GroupsPost" + r.summary = "" + r.operationID = "" + r.pathPattern = "/groups" + r.args = args + r.count = 0 + return r, true + default: + return + } + } + switch elem[0] { + case '/': // Prefix: "/" + origElem := elem + if l := len("/"); len(elem) >= l && elem[0:l] == "/" { + elem = elem[l:] + } else { + break + } + + // Param: "id" + // Leaf parameter + args[0] = elem + elem = "" + + if len(elem) == 0 { + switch method { + case "DELETE": + // Leaf: GroupsIDDelete + r.name = "GroupsIDDelete" + r.summary = "" + r.operationID = "" + r.pathPattern = "/groups/{id}" + r.args = args + r.count = 1 + return r, true + case "GET": + // Leaf: GroupsIDGet + r.name = "GroupsIDGet" + r.summary = "" + r.operationID = "" + r.pathPattern = "/groups/{id}" + r.args = args + r.count = 1 + return r, true + case "PUT": + // Leaf: GroupsIDPut + r.name = "GroupsIDPut" + r.summary = "" + r.operationID = "" + r.pathPattern = "/groups/{id}" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + elem = origElem + } + + elem = origElem + case 'h': // Prefix: "healthz" + origElem := elem + if l := len("healthz"); len(elem) >= l && elem[0:l] == "healthz" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + switch method { + case "GET": + // Leaf: HealthzGet + r.name = "HealthzGet" + r.summary = "" + r.operationID = "" + r.pathPattern = "/healthz" + r.args = args + r.count = 0 + return r, true + default: + return + } + } + + elem = origElem + case 'u': // Prefix: "users" + origElem := elem + if l := len("users"); len(elem) >= l && elem[0:l] == "users" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + switch method { + case "GET": + r.name = "UsersGet" + r.summary = "" + r.operationID = "" + r.pathPattern = "/users" + r.args = args + r.count = 0 + return r, true + case "POST": + r.name = "UsersPost" + r.summary = "" + r.operationID = "" + r.pathPattern = "/users" + r.args = args + r.count = 0 + return r, true + default: + return + } + } + switch elem[0] { + case '/': // Prefix: "/" + origElem := elem + if l := len("/"); len(elem) >= l && elem[0:l] == "/" { + elem = elem[l:] + } else { + break + } + + // Param: "id" + // Match until "/" + idx := strings.IndexByte(elem, '/') + if idx < 0 { + idx = len(elem) + } + args[0] = elem[:idx] + elem = elem[idx:] + + if len(elem) == 0 { + switch method { + case "DELETE": + r.name = "UsersIDDelete" + r.summary = "" + r.operationID = "" + r.pathPattern = "/users/{id}" + r.args = args + r.count = 1 + return r, true + case "GET": + r.name = "UsersIDGet" + r.summary = "" + r.operationID = "" + r.pathPattern = "/users/{id}" + r.args = args + r.count = 1 + return r, true + case "PUT": + r.name = "UsersIDPut" + r.summary = "" + r.operationID = "" + r.pathPattern = "/users/{id}" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + switch elem[0] { + case '/': // Prefix: "/group" + origElem := elem + if l := len("/group"); len(elem) >= l && elem[0:l] == "/group" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + switch method { + case "PUT": + // Leaf: UsersIDGroupPut + r.name = "UsersIDGroupPut" + r.summary = "" + r.operationID = "" + r.pathPattern = "/users/{id}/group" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + elem = origElem + } + + elem = origElem + } + + elem = origElem + } + + elem = origElem + } + } + return r, false +} diff --git a/pkg/api/oas_schemas_gen.go b/pkg/api/oas_schemas_gen.go new file mode 100644 index 0000000..269f8f9 --- /dev/null +++ b/pkg/api/oas_schemas_gen.go @@ -0,0 +1,422 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +import ( + "fmt" +) + +func (s *ErrorStatusCode) Error() string { + return fmt.Sprintf("code %d: %+v", s.StatusCode, s.Response) +} + +// Ref: #/components/schemas/Error +type Error struct { + Message OptString `json:"message"` + Code OptInt `json:"code"` +} + +// GetMessage returns the value of Message. +func (s *Error) GetMessage() OptString { + return s.Message +} + +// GetCode returns the value of Code. +func (s *Error) GetCode() OptInt { + return s.Code +} + +// SetMessage sets the value of Message. +func (s *Error) SetMessage(val OptString) { + s.Message = val +} + +// SetCode sets the value of Code. +func (s *Error) SetCode(val OptInt) { + s.Code = val +} + +func (*Error) groupsIDDeleteRes() {} +func (*Error) groupsIDGetRes() {} +func (*Error) groupsIDPutRes() {} +func (*Error) usersIDDeleteRes() {} +func (*Error) usersIDGetRes() {} +func (*Error) usersIDGroupPutRes() {} +func (*Error) usersIDPutRes() {} + +// ErrorStatusCode wraps Error with StatusCode. +type ErrorStatusCode struct { + StatusCode int + Response Error +} + +// GetStatusCode returns the value of StatusCode. +func (s *ErrorStatusCode) GetStatusCode() int { + return s.StatusCode +} + +// GetResponse returns the value of Response. +func (s *ErrorStatusCode) GetResponse() Error { + return s.Response +} + +// SetStatusCode sets the value of StatusCode. +func (s *ErrorStatusCode) SetStatusCode(val int) { + s.StatusCode = val +} + +// SetResponse sets the value of Response. +func (s *ErrorStatusCode) SetResponse(val Error) { + s.Response = val +} + +// Ref: #/components/schemas/Group +type Group struct { + ID OptID `json:"id"` + Name OptString `json:"name"` + Users []User `json:"users"` +} + +// GetID returns the value of ID. +func (s *Group) GetID() OptID { + return s.ID +} + +// GetName returns the value of Name. +func (s *Group) GetName() OptString { + return s.Name +} + +// GetUsers returns the value of Users. +func (s *Group) GetUsers() []User { + return s.Users +} + +// SetID sets the value of ID. +func (s *Group) SetID(val OptID) { + s.ID = val +} + +// SetName sets the value of Name. +func (s *Group) SetName(val OptString) { + s.Name = val +} + +// SetUsers sets the value of Users. +func (s *Group) SetUsers(val []User) { + s.Users = val +} + +func (*Group) groupsIDGetRes() {} +func (*Group) groupsIDPutRes() {} + +// Ref: #/components/schemas/GroupUpdate +type GroupUpdate struct { + Name OptString `json:"name"` +} + +// GetName returns the value of Name. +func (s *GroupUpdate) GetName() OptString { + return s.Name +} + +// SetName sets the value of Name. +func (s *GroupUpdate) SetName(val OptString) { + s.Name = val +} + +type ID int64 + +// Ref: #/components/schemas/Ok +type Ok struct { + Message OptString `json:"message"` +} + +// GetMessage returns the value of Message. +func (s *Ok) GetMessage() OptString { + return s.Message +} + +// SetMessage sets the value of Message. +func (s *Ok) SetMessage(val OptString) { + s.Message = val +} + +func (*Ok) groupsIDDeleteRes() {} +func (*Ok) usersIDDeleteRes() {} + +// NewOptGroup returns new OptGroup with value set to v. +func NewOptGroup(v Group) OptGroup { + return OptGroup{ + Value: v, + Set: true, + } +} + +// OptGroup is optional Group. +type OptGroup struct { + Value Group + Set bool +} + +// IsSet returns true if OptGroup was set. +func (o OptGroup) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptGroup) Reset() { + var v Group + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptGroup) SetTo(v Group) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptGroup) Get() (v Group, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptGroup) Or(d Group) Group { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptID returns new OptID with value set to v. +func NewOptID(v ID) OptID { + return OptID{ + Value: v, + Set: true, + } +} + +// OptID is optional ID. +type OptID struct { + Value ID + Set bool +} + +// IsSet returns true if OptID was set. +func (o OptID) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptID) Reset() { + var v ID + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptID) SetTo(v ID) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptID) Get() (v ID, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptID) Or(d ID) ID { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptInt returns new OptInt with value set to v. +func NewOptInt(v int) OptInt { + return OptInt{ + Value: v, + Set: true, + } +} + +// OptInt is optional int. +type OptInt struct { + Value int + Set bool +} + +// IsSet returns true if OptInt was set. +func (o OptInt) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptInt) Reset() { + var v int + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptInt) SetTo(v int) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptInt) Get() (v int, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptInt) Or(d int) int { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptString returns new OptString with value set to v. +func NewOptString(v string) OptString { + return OptString{ + Value: v, + Set: true, + } +} + +// OptString is optional string. +type OptString struct { + Value string + Set bool +} + +// IsSet returns true if OptString was set. +func (o OptString) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptString) Reset() { + var v string + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptString) SetTo(v string) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptString) Get() (v string, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptString) Or(d string) string { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// Ref: #/components/schemas/User +type User struct { + ID OptID `json:"id"` + Name OptString `json:"name"` + Email OptString `json:"email"` + Group OptGroup `json:"group"` +} + +// GetID returns the value of ID. +func (s *User) GetID() OptID { + return s.ID +} + +// GetName returns the value of Name. +func (s *User) GetName() OptString { + return s.Name +} + +// GetEmail returns the value of Email. +func (s *User) GetEmail() OptString { + return s.Email +} + +// GetGroup returns the value of Group. +func (s *User) GetGroup() OptGroup { + return s.Group +} + +// SetID sets the value of ID. +func (s *User) SetID(val OptID) { + s.ID = val +} + +// SetName sets the value of Name. +func (s *User) SetName(val OptString) { + s.Name = val +} + +// SetEmail sets the value of Email. +func (s *User) SetEmail(val OptString) { + s.Email = val +} + +// SetGroup sets the value of Group. +func (s *User) SetGroup(val OptGroup) { + s.Group = val +} + +func (*User) usersIDGetRes() {} +func (*User) usersIDGroupPutRes() {} +func (*User) usersIDPutRes() {} + +// Ref: #/components/schemas/UserUpdate +type UserUpdate struct { + Name OptString `json:"name"` + Email OptString `json:"email"` +} + +// GetName returns the value of Name. +func (s *UserUpdate) GetName() OptString { + return s.Name +} + +// GetEmail returns the value of Email. +func (s *UserUpdate) GetEmail() OptString { + return s.Email +} + +// SetName sets the value of Name. +func (s *UserUpdate) SetName(val OptString) { + s.Name = val +} + +// SetEmail sets the value of Email. +func (s *UserUpdate) SetEmail(val OptString) { + s.Email = val +} + +type UsersIDGroupPutReq struct { + Group OptID `json:"group"` +} + +// GetGroup returns the value of Group. +func (s *UsersIDGroupPutReq) GetGroup() OptID { + return s.Group +} + +// SetGroup sets the value of Group. +func (s *UsersIDGroupPutReq) SetGroup(val OptID) { + s.Group = val +} diff --git a/pkg/api/oas_server_gen.go b/pkg/api/oas_server_gen.go new file mode 100644 index 0000000..d495602 --- /dev/null +++ b/pkg/api/oas_server_gen.go @@ -0,0 +1,104 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +import ( + "context" +) + +// Handler handles operations described by OpenAPI v3 specification. +type Handler interface { + // GroupsGet implements GET /groups operation. + // + // Get all groups. + // + // GET /groups + GroupsGet(ctx context.Context) ([]Group, error) + // GroupsIDDelete implements DELETE /groups/{id} operation. + // + // Delete group by id. + // + // DELETE /groups/{id} + GroupsIDDelete(ctx context.Context, params GroupsIDDeleteParams) (GroupsIDDeleteRes, error) + // GroupsIDGet implements GET /groups/{id} operation. + // + // Get group by id. + // + // GET /groups/{id} + GroupsIDGet(ctx context.Context, params GroupsIDGetParams) (GroupsIDGetRes, error) + // GroupsIDPut implements PUT /groups/{id} operation. + // + // Update group by id. + // + // PUT /groups/{id} + GroupsIDPut(ctx context.Context, req *GroupUpdate, params GroupsIDPutParams) (GroupsIDPutRes, error) + // GroupsPost implements POST /groups operation. + // + // Create group. + // + // POST /groups + GroupsPost(ctx context.Context, req *GroupUpdate) (*Group, error) + // HealthzGet implements GET /healthz operation. + // + // GET /healthz + HealthzGet(ctx context.Context) (*Ok, error) + // UsersGet implements GET /users operation. + // + // Get all users. + // + // GET /users + UsersGet(ctx context.Context) ([]User, error) + // UsersIDDelete implements DELETE /users/{id} operation. + // + // Delete user by id. + // + // DELETE /users/{id} + UsersIDDelete(ctx context.Context, params UsersIDDeleteParams) (UsersIDDeleteRes, error) + // UsersIDGet implements GET /users/{id} operation. + // + // Get user by id. + // + // GET /users/{id} + UsersIDGet(ctx context.Context, params UsersIDGetParams) (UsersIDGetRes, error) + // UsersIDGroupPut implements PUT /users/{id}/group operation. + // + // Update user group by id. + // + // PUT /users/{id}/group + UsersIDGroupPut(ctx context.Context, req *UsersIDGroupPutReq, params UsersIDGroupPutParams) (UsersIDGroupPutRes, error) + // UsersIDPut implements PUT /users/{id} operation. + // + // Update user by id. + // + // PUT /users/{id} + UsersIDPut(ctx context.Context, req *UserUpdate, params UsersIDPutParams) (UsersIDPutRes, error) + // UsersPost implements POST /users operation. + // + // Create user. + // + // POST /users + UsersPost(ctx context.Context, req *UserUpdate) (*User, error) + // NewError creates *ErrorStatusCode from error returned by handler. + // + // Used for common default response. + NewError(ctx context.Context, err error) *ErrorStatusCode +} + +// Server implements http server based on OpenAPI v3 specification and +// calls Handler to handle requests. +type Server struct { + h Handler + baseServer +} + +// NewServer creates new Server. +func NewServer(h Handler, opts ...ServerOption) (*Server, error) { + s, err := newServerConfig(opts...).baseServer() + if err != nil { + return nil, err + } + return &Server{ + h: h, + baseServer: s, + }, nil +} diff --git a/pkg/api/oas_unimplemented_gen.go b/pkg/api/oas_unimplemented_gen.go new file mode 100644 index 0000000..f37fdb2 --- /dev/null +++ b/pkg/api/oas_unimplemented_gen.go @@ -0,0 +1,128 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +import ( + "context" + + ht "github.com/ogen-go/ogen/http" +) + +// UnimplementedHandler is no-op Handler which returns http.ErrNotImplemented. +type UnimplementedHandler struct{} + +var _ Handler = UnimplementedHandler{} + +// GroupsGet implements GET /groups operation. +// +// Get all groups. +// +// GET /groups +func (UnimplementedHandler) GroupsGet(ctx context.Context) (r []Group, _ error) { + return r, ht.ErrNotImplemented +} + +// GroupsIDDelete implements DELETE /groups/{id} operation. +// +// Delete group by id. +// +// DELETE /groups/{id} +func (UnimplementedHandler) GroupsIDDelete(ctx context.Context, params GroupsIDDeleteParams) (r GroupsIDDeleteRes, _ error) { + return r, ht.ErrNotImplemented +} + +// GroupsIDGet implements GET /groups/{id} operation. +// +// Get group by id. +// +// GET /groups/{id} +func (UnimplementedHandler) GroupsIDGet(ctx context.Context, params GroupsIDGetParams) (r GroupsIDGetRes, _ error) { + return r, ht.ErrNotImplemented +} + +// GroupsIDPut implements PUT /groups/{id} operation. +// +// Update group by id. +// +// PUT /groups/{id} +func (UnimplementedHandler) GroupsIDPut(ctx context.Context, req *GroupUpdate, params GroupsIDPutParams) (r GroupsIDPutRes, _ error) { + return r, ht.ErrNotImplemented +} + +// GroupsPost implements POST /groups operation. +// +// Create group. +// +// POST /groups +func (UnimplementedHandler) GroupsPost(ctx context.Context, req *GroupUpdate) (r *Group, _ error) { + return r, ht.ErrNotImplemented +} + +// HealthzGet implements GET /healthz operation. +// +// GET /healthz +func (UnimplementedHandler) HealthzGet(ctx context.Context) (r *Ok, _ error) { + return r, ht.ErrNotImplemented +} + +// UsersGet implements GET /users operation. +// +// Get all users. +// +// GET /users +func (UnimplementedHandler) UsersGet(ctx context.Context) (r []User, _ error) { + return r, ht.ErrNotImplemented +} + +// UsersIDDelete implements DELETE /users/{id} operation. +// +// Delete user by id. +// +// DELETE /users/{id} +func (UnimplementedHandler) UsersIDDelete(ctx context.Context, params UsersIDDeleteParams) (r UsersIDDeleteRes, _ error) { + return r, ht.ErrNotImplemented +} + +// UsersIDGet implements GET /users/{id} operation. +// +// Get user by id. +// +// GET /users/{id} +func (UnimplementedHandler) UsersIDGet(ctx context.Context, params UsersIDGetParams) (r UsersIDGetRes, _ error) { + return r, ht.ErrNotImplemented +} + +// UsersIDGroupPut implements PUT /users/{id}/group operation. +// +// Update user group by id. +// +// PUT /users/{id}/group +func (UnimplementedHandler) UsersIDGroupPut(ctx context.Context, req *UsersIDGroupPutReq, params UsersIDGroupPutParams) (r UsersIDGroupPutRes, _ error) { + return r, ht.ErrNotImplemented +} + +// UsersIDPut implements PUT /users/{id} operation. +// +// Update user by id. +// +// PUT /users/{id} +func (UnimplementedHandler) UsersIDPut(ctx context.Context, req *UserUpdate, params UsersIDPutParams) (r UsersIDPutRes, _ error) { + return r, ht.ErrNotImplemented +} + +// UsersPost implements POST /users operation. +// +// Create user. +// +// POST /users +func (UnimplementedHandler) UsersPost(ctx context.Context, req *UserUpdate) (r *User, _ error) { + return r, ht.ErrNotImplemented +} + +// NewError creates *ErrorStatusCode from error returned by handler. +// +// Used for common default response. +func (UnimplementedHandler) NewError(ctx context.Context, err error) (r *ErrorStatusCode) { + r = new(ErrorStatusCode) + return r +} diff --git a/pkg/groups.go b/pkg/groups.go new file mode 100644 index 0000000..b2685ba --- /dev/null +++ b/pkg/groups.go @@ -0,0 +1,18 @@ +package groups + +import ( + "context" + "github.com/mentos1386/golang-rest-example/pkg/api" +) + +type groupServer struct { + groups map[int64]*api.Group +} + +func (u *groupServer) groupsGet(ctx context.Context) ([]api.Group, error) { + var groups []api.Group + for _, group := range u.groups { + groups = append(groups, *group) + } + return groups, nil +} diff --git a/pkg/users.go b/pkg/users.go new file mode 100644 index 0000000..e69de29 diff --git a/tools/generate.go b/tools/generate.go new file mode 100644 index 0000000..0b4eb31 --- /dev/null +++ b/tools/generate.go @@ -0,0 +1,3 @@ +package tools + +//go:generate go run github.com/ogen-go/ogen/cmd/ogen@latest --target ../pkg/api -package api --clean ../api/openapi.yaml