diff --git a/.air.toml b/.air.toml new file mode 100644 index 0000000..9a0cf83 --- /dev/null +++ b/.air.toml @@ -0,0 +1,46 @@ +root = "." +testdata_dir = "testdata" +tmp_dir = "/tmp" + +[build] + args_bin = [] + bin = "/tmp/main" + cmd = "go build -o /tmp/main cmd/server.go" + delay = 1000 + exclude_dir = ["assets", "tmp", "vendor", "testdata"] + exclude_file = [] + exclude_regex = ["_test.go"] + exclude_unchanged = false + follow_symlink = false + full_bin = "" + include_dir = [] + include_ext = ["go", "tpl", "tmpl", "html"] + include_file = [] + kill_delay = "0s" + log = "build-errors.log" + poll = false + poll_interval = 0 + post_cmd = [] + pre_cmd = [] + rerun = false + rerun_delay = 500 + send_interrupt = false + stop_on_error = false + +[color] + app = "" + build = "yellow" + main = "magenta" + runner = "green" + watcher = "cyan" + +[log] + main_only = false + time = false + +[misc] + clean_on_exit = false + +[screen] + clear_on_rebuild = false + keep_scroll = true diff --git a/.spectral.yaml b/.spectral.yaml deleted file mode 100644 index 1cac3b3..0000000 --- a/.spectral.yaml +++ /dev/null @@ -1 +0,0 @@ -extends: ["spectral:oas", "spectral:asyncapi"] diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d5959dc --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +# Base +ARG GO_VERSION=1.21 +FROM golang:${GO_VERSION} as base +WORKDIR /app +COPY . . +RUN go mod download + +# Development +FROM base as dev +RUN curl -sSfL https://raw.githubusercontent.com/cosmtrek/air/master/install.sh | sh -s -- -b $(go env GOPATH)/bin +CMD ["air"] + +# Build +FROM base as build +RUN go build cmd/server.go + +# Production +FROM gcr.io/distroless/static-debian12 as prod +COPY --from=build /app/server / +ENTRYPOINT ["/server"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..ba567ac --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# `mentos1386/golang-rest-example` + +### Development + +Tools required: + * Justfile + * Docker and Docker Compose + +```sh +just run + +curl -v localhost:1234/healthz +``` diff --git a/api/openapi.yaml b/api/openapi.yaml index 33dbc36..06b17ab 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -289,12 +289,17 @@ components: schemas: Ok: type: object + required: + - message properties: message: type: string example: OK Error: type: object + required: + - message + - code properties: message: type: string @@ -308,6 +313,11 @@ components: example: 1 User: type: object + required: + - id + - name + - email + - group properties: id: $ref: '#/components/schemas/Id' @@ -321,6 +331,9 @@ components: $ref: '#/components/schemas/Group' UserUpdate: type: object + required: + - name + - email properties: name: type: string @@ -330,6 +343,10 @@ components: example: john@example.com Group: type: object + required: + - id + - name + - users properties: id: $ref: '#/components/schemas/Id' @@ -342,6 +359,8 @@ components: $ref: '#/components/schemas/User' GroupUpdate: type: object + required: + - name properties: name: type: string diff --git a/cmd/server.go b/cmd/server.go index 824af55..b222b0f 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -5,16 +5,19 @@ import ( "net/http" "github.com/mentos1386/golang-rest-example/pkg/api" + "github.com/mentos1386/golang-rest-example/pkg/openapi" ) func main() { + service := &api.ApiService{} - srv, err := api.NewServer() + srv, err := openapi.NewServer(service) if err != nil { log.Fatal(err) } - if err := http.ListenAndServe(":8080", srv); err != nil { + log.Println("Starting server on :1234") + if err := http.ListenAndServe(":1234", srv); err != nil { log.Fatal(err) } } diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..a2ea3d2 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,21 @@ +version: "3.9" +services: + db: + image: postgres + restart: always + environment: + POSTGRES_PASSWORD: example + + app: + build: + dockerfile: Dockerfile + context: . + target: dev + args: + - GO_VERSION=${GO_VERSION} + ports: + - 1234:1234 + volumes: + - .:/app + environment: + - DATABASE_URL=postgresql://postgres:example@db:5432/postgres diff --git a/go.mod b/go.mod index 84fe531..ae3afd7 100644 --- a/go.mod +++ b/go.mod @@ -3,14 +3,31 @@ 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/go-faster/errors v0.7.1 + github.com/go-faster/jx v1.1.0 + github.com/ogen-go/ogen v0.81.2 + go.opentelemetry.io/otel v1.22.0 + go.opentelemetry.io/otel/metric v1.22.0 + go.opentelemetry.io/otel/trace v1.22.0 + go.uber.org/multierr v1.11.0 +) + +require ( + github.com/dlclark/regexp2 v1.10.0 // indirect + github.com/fatih/color v1.16.0 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-faster/yaml v0.4.6 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.5.0 // 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 + github.com/segmentio/asm v1.2.0 // indirect + go.uber.org/zap v1.26.0 // indirect + golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/sync v0.6.0 // indirect + golang.org/x/sys v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 453ca6f..db4b19b 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,73 @@ -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/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0= +github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg= +github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo= +github.com/go-faster/jx v1.1.0 h1:ZsW3wD+snOdmTDy9eIVgQdjUpXRRV4rqW8NS3t+20bg= +github.com/go-faster/jx v1.1.0/go.mod h1:vKDNikrKoyUmpzaJ0OkIkRQClNHFX/nF3dnTJZb3skg= +github.com/go-faster/yaml v0.4.6 h1:lOK/EhI04gCpPgPhgt0bChS6bvw7G3WwI8xxVe0sw9I= +github.com/go-faster/yaml v0.4.6/go.mod h1:390dRIvV4zbnO7qC9FGo6YYutc+wyyUSHBgbXL52eXk= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= +github.com/ogen-go/ogen v0.81.2 h1:Dj5vSgC/1oqLE5t0T5qd4ARgsKTupJWsh3rW9/C7Lvk= +github.com/ogen-go/ogen v0.81.2/go.mod h1:10Ch7SIzBMSLB8TVEt8KclMKkRyJ5qCh4Cfs0pdeoh8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= +github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y= +go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= +go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg= +go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= +go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0= +go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 h1:Di6/M8l0O2lCLc6VVRWhgCiApHV8MnQurBnFSHsQtNY= +golang.org/x/exp v0.0.0-20230725093048-515e97ebf090/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.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= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/justfile b/justfile index 416a924..3d02bb9 100644 --- a/justfile +++ b/justfile @@ -1,5 +1,20 @@ -run: - go run cmd/server.go +export GO_VERSION := "1.21" +_default: + @just --list + +# Run the app in development mode +run: + docker compose up --build app + +# Generate OpenAPI files gen: - go generate ./... + docker compose run --rm app \ + go generate ./... + +# Build production image +build: + docker build \ + --build-arg GO_VERSION=$(GO_VERSION) \ + -t golang-rest-example \ + . diff --git a/pkg/api/api.go b/pkg/api/api.go new file mode 100644 index 0000000..1ff07a4 --- /dev/null +++ b/pkg/api/api.go @@ -0,0 +1,11 @@ +package api + +import ( + "github.com/mentos1386/golang-rest-example/pkg/openapi" +) + +type ApiService struct { + groups []*openapi.Group + + openapi.UnimplementedHandler +} diff --git a/pkg/api/groups.go b/pkg/api/groups.go new file mode 100644 index 0000000..bf0b483 --- /dev/null +++ b/pkg/api/groups.go @@ -0,0 +1,15 @@ +package api + +import ( + "context" + "github.com/mentos1386/golang-rest-example/pkg/openapi" +) + +func (u *ApiService) GroupsGet(ctx context.Context) ([]openapi.Group, error) { + var groups []openapi.Group + for _, group := range u.groups { + groups = append(groups, *group) + } + groups = append(groups, openapi.Group{ID: openapi.ID(1), Name: "Admins"}) + return groups, nil +} diff --git a/pkg/api/users.go b/pkg/api/users.go new file mode 100644 index 0000000..86a91b8 --- /dev/null +++ b/pkg/api/users.go @@ -0,0 +1,3 @@ +package api + +type UserServer struct{} diff --git a/pkg/groups.go b/pkg/groups.go deleted file mode 100644 index b2685ba..0000000 --- a/pkg/groups.go +++ /dev/null @@ -1,18 +0,0 @@ -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/api/oas_cfg_gen.go b/pkg/openapi/oas_cfg_gen.go similarity index 99% rename from pkg/api/oas_cfg_gen.go rename to pkg/openapi/oas_cfg_gen.go index e7311e7..2db2256 100644 --- a/pkg/api/oas_cfg_gen.go +++ b/pkg/openapi/oas_cfg_gen.go @@ -1,6 +1,6 @@ // Code generated by ogen, DO NOT EDIT. -package api +package openapi import ( "net/http" diff --git a/pkg/api/oas_client_gen.go b/pkg/openapi/oas_client_gen.go similarity index 99% rename from pkg/api/oas_client_gen.go rename to pkg/openapi/oas_client_gen.go index f35a520..740b6fa 100644 --- a/pkg/api/oas_client_gen.go +++ b/pkg/openapi/oas_client_gen.go @@ -1,6 +1,6 @@ // Code generated by ogen, DO NOT EDIT. -package api +package openapi import ( "context" diff --git a/pkg/api/oas_handlers_gen.go b/pkg/openapi/oas_handlers_gen.go similarity index 99% rename from pkg/api/oas_handlers_gen.go rename to pkg/openapi/oas_handlers_gen.go index 9bf3564..79715bb 100644 --- a/pkg/api/oas_handlers_gen.go +++ b/pkg/openapi/oas_handlers_gen.go @@ -1,6 +1,6 @@ // Code generated by ogen, DO NOT EDIT. -package api +package openapi import ( "context" diff --git a/pkg/api/oas_interfaces_gen.go b/pkg/openapi/oas_interfaces_gen.go similarity index 96% rename from pkg/api/oas_interfaces_gen.go rename to pkg/openapi/oas_interfaces_gen.go index aae4046..4813ef1 100644 --- a/pkg/api/oas_interfaces_gen.go +++ b/pkg/openapi/oas_interfaces_gen.go @@ -1,5 +1,5 @@ // Code generated by ogen, DO NOT EDIT. -package api +package openapi type GroupsIDDeleteRes interface { groupsIDDeleteRes() diff --git a/pkg/api/oas_json_gen.go b/pkg/openapi/oas_json_gen.go similarity index 59% rename from pkg/api/oas_json_gen.go rename to pkg/openapi/oas_json_gen.go index adfe890..35d3f5c 100644 --- a/pkg/api/oas_json_gen.go +++ b/pkg/openapi/oas_json_gen.go @@ -1,10 +1,15 @@ // Code generated by ogen, DO NOT EDIT. -package api +package openapi import ( + "math/bits" + "strconv" + "github.com/go-faster/errors" "github.com/go-faster/jx" + + "github.com/ogen-go/ogen/validate" ) // Encode implements json.Marshaler. @@ -17,16 +22,12 @@ func (s *Error) Encode(e *jx.Encoder) { // encodeFields encodes fields. func (s *Error) encodeFields(e *jx.Encoder) { { - if s.Message.Set { - e.FieldStart("message") - s.Message.Encode(e) - } + e.FieldStart("message") + e.Str(s.Message) } { - if s.Code.Set { - e.FieldStart("code") - s.Code.Encode(e) - } + e.FieldStart("code") + e.Int(s.Code) } } @@ -40,13 +41,16 @@ func (s *Error) Decode(d *jx.Decoder) error { if s == nil { return errors.New("invalid: unable to decode Error to nil") } + var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { case "message": + requiredBitSet[0] |= 1 << 0 if err := func() error { - s.Message.Reset() - if err := s.Message.Decode(d); err != nil { + v, err := d.Str() + s.Message = string(v) + if err != nil { return err } return nil @@ -54,9 +58,11 @@ func (s *Error) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"message\"") } case "code": + requiredBitSet[0] |= 1 << 1 if err := func() error { - s.Code.Reset() - if err := s.Code.Decode(d); err != nil { + v, err := d.Int() + s.Code = int(v) + if err != nil { return err } return nil @@ -70,6 +76,38 @@ func (s *Error) Decode(d *jx.Decoder) error { }); err != nil { return errors.Wrap(err, "decode Error") } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000011, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfError) { + name = jsonFieldsNameOfError[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } return nil } @@ -97,26 +135,20 @@ func (s *Group) Encode(e *jx.Encoder) { // encodeFields encodes fields. func (s *Group) encodeFields(e *jx.Encoder) { { - if s.ID.Set { - e.FieldStart("id") - s.ID.Encode(e) - } + e.FieldStart("id") + s.ID.Encode(e) } { - if s.Name.Set { - e.FieldStart("name") - s.Name.Encode(e) - } + e.FieldStart("name") + e.Str(s.Name) } { - if s.Users != nil { - e.FieldStart("users") - e.ArrStart() - for _, elem := range s.Users { - elem.Encode(e) - } - e.ArrEnd() + e.FieldStart("users") + e.ArrStart() + for _, elem := range s.Users { + elem.Encode(e) } + e.ArrEnd() } } @@ -131,12 +163,13 @@ func (s *Group) Decode(d *jx.Decoder) error { if s == nil { return errors.New("invalid: unable to decode Group to nil") } + var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { case "id": + requiredBitSet[0] |= 1 << 0 if err := func() error { - s.ID.Reset() if err := s.ID.Decode(d); err != nil { return err } @@ -145,9 +178,11 @@ func (s *Group) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"id\"") } case "name": + requiredBitSet[0] |= 1 << 1 if err := func() error { - s.Name.Reset() - if err := s.Name.Decode(d); err != nil { + v, err := d.Str() + s.Name = string(v) + if err != nil { return err } return nil @@ -155,6 +190,7 @@ func (s *Group) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"name\"") } case "users": + requiredBitSet[0] |= 1 << 2 if err := func() error { s.Users = make([]User, 0) if err := d.Arr(func(d *jx.Decoder) error { @@ -178,6 +214,38 @@ func (s *Group) Decode(d *jx.Decoder) error { }); err != nil { return errors.Wrap(err, "decode Group") } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000111, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfGroup) { + name = jsonFieldsNameOfGroup[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } return nil } @@ -205,10 +273,8 @@ func (s *GroupUpdate) Encode(e *jx.Encoder) { // encodeFields encodes fields. func (s *GroupUpdate) encodeFields(e *jx.Encoder) { { - if s.Name.Set { - e.FieldStart("name") - s.Name.Encode(e) - } + e.FieldStart("name") + e.Str(s.Name) } } @@ -221,13 +287,16 @@ func (s *GroupUpdate) Decode(d *jx.Decoder) error { if s == nil { return errors.New("invalid: unable to decode GroupUpdate to nil") } + var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { case "name": + requiredBitSet[0] |= 1 << 0 if err := func() error { - s.Name.Reset() - if err := s.Name.Decode(d); err != nil { + v, err := d.Str() + s.Name = string(v) + if err != nil { return err } return nil @@ -241,6 +310,38 @@ func (s *GroupUpdate) Decode(d *jx.Decoder) error { }); err != nil { return errors.Wrap(err, "decode GroupUpdate") } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000001, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfGroupUpdate) { + name = jsonFieldsNameOfGroupUpdate[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } return nil } @@ -308,10 +409,8 @@ func (s *Ok) Encode(e *jx.Encoder) { // encodeFields encodes fields. func (s *Ok) encodeFields(e *jx.Encoder) { { - if s.Message.Set { - e.FieldStart("message") - s.Message.Encode(e) - } + e.FieldStart("message") + e.Str(s.Message) } } @@ -324,13 +423,16 @@ func (s *Ok) Decode(d *jx.Decoder) error { if s == nil { return errors.New("invalid: unable to decode Ok to nil") } + var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { case "message": + requiredBitSet[0] |= 1 << 0 if err := func() error { - s.Message.Reset() - if err := s.Message.Decode(d); err != nil { + v, err := d.Str() + s.Message = string(v) + if err != nil { return err } return nil @@ -344,6 +446,38 @@ func (s *Ok) Decode(d *jx.Decoder) error { }); err != nil { return errors.Wrap(err, "decode Ok") } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000001, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfOk) { + name = jsonFieldsNameOfOk[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } return nil } @@ -361,39 +495,6 @@ func (s *Ok) UnmarshalJSON(data []byte) error { 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 { @@ -427,76 +528,6 @@ func (s *OptID) UnmarshalJSON(data []byte) error { 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() @@ -507,28 +538,20 @@ func (s *User) Encode(e *jx.Encoder) { // encodeFields encodes fields. func (s *User) encodeFields(e *jx.Encoder) { { - if s.ID.Set { - e.FieldStart("id") - s.ID.Encode(e) - } + e.FieldStart("id") + s.ID.Encode(e) } { - if s.Name.Set { - e.FieldStart("name") - s.Name.Encode(e) - } + e.FieldStart("name") + e.Str(s.Name) } { - if s.Email.Set { - e.FieldStart("email") - s.Email.Encode(e) - } + e.FieldStart("email") + e.Str(s.Email) } { - if s.Group.Set { - e.FieldStart("group") - s.Group.Encode(e) - } + e.FieldStart("group") + s.Group.Encode(e) } } @@ -544,12 +567,13 @@ func (s *User) Decode(d *jx.Decoder) error { if s == nil { return errors.New("invalid: unable to decode User to nil") } + var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { case "id": + requiredBitSet[0] |= 1 << 0 if err := func() error { - s.ID.Reset() if err := s.ID.Decode(d); err != nil { return err } @@ -558,9 +582,11 @@ func (s *User) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"id\"") } case "name": + requiredBitSet[0] |= 1 << 1 if err := func() error { - s.Name.Reset() - if err := s.Name.Decode(d); err != nil { + v, err := d.Str() + s.Name = string(v) + if err != nil { return err } return nil @@ -568,9 +594,11 @@ func (s *User) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"name\"") } case "email": + requiredBitSet[0] |= 1 << 2 if err := func() error { - s.Email.Reset() - if err := s.Email.Decode(d); err != nil { + v, err := d.Str() + s.Email = string(v) + if err != nil { return err } return nil @@ -578,8 +606,8 @@ func (s *User) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"email\"") } case "group": + requiredBitSet[0] |= 1 << 3 if err := func() error { - s.Group.Reset() if err := s.Group.Decode(d); err != nil { return err } @@ -594,6 +622,38 @@ func (s *User) Decode(d *jx.Decoder) error { }); err != nil { return errors.Wrap(err, "decode User") } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00001111, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfUser) { + name = jsonFieldsNameOfUser[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } return nil } @@ -621,16 +681,12 @@ func (s *UserUpdate) Encode(e *jx.Encoder) { // encodeFields encodes fields. func (s *UserUpdate) encodeFields(e *jx.Encoder) { { - if s.Name.Set { - e.FieldStart("name") - s.Name.Encode(e) - } + e.FieldStart("name") + e.Str(s.Name) } { - if s.Email.Set { - e.FieldStart("email") - s.Email.Encode(e) - } + e.FieldStart("email") + e.Str(s.Email) } } @@ -644,13 +700,16 @@ func (s *UserUpdate) Decode(d *jx.Decoder) error { if s == nil { return errors.New("invalid: unable to decode UserUpdate to nil") } + var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { case "name": + requiredBitSet[0] |= 1 << 0 if err := func() error { - s.Name.Reset() - if err := s.Name.Decode(d); err != nil { + v, err := d.Str() + s.Name = string(v) + if err != nil { return err } return nil @@ -658,9 +717,11 @@ func (s *UserUpdate) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"name\"") } case "email": + requiredBitSet[0] |= 1 << 1 if err := func() error { - s.Email.Reset() - if err := s.Email.Decode(d); err != nil { + v, err := d.Str() + s.Email = string(v) + if err != nil { return err } return nil @@ -674,6 +735,38 @@ func (s *UserUpdate) Decode(d *jx.Decoder) error { }); err != nil { return errors.Wrap(err, "decode UserUpdate") } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000011, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfUserUpdate) { + name = jsonFieldsNameOfUserUpdate[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } return nil } diff --git a/pkg/api/oas_middleware_gen.go b/pkg/openapi/oas_middleware_gen.go similarity index 91% rename from pkg/api/oas_middleware_gen.go rename to pkg/openapi/oas_middleware_gen.go index 6f58a1a..083fe0e 100644 --- a/pkg/api/oas_middleware_gen.go +++ b/pkg/openapi/oas_middleware_gen.go @@ -1,6 +1,6 @@ // Code generated by ogen, DO NOT EDIT. -package api +package openapi import ( "github.com/ogen-go/ogen/middleware" diff --git a/pkg/api/oas_parameters_gen.go b/pkg/openapi/oas_parameters_gen.go similarity index 99% rename from pkg/api/oas_parameters_gen.go rename to pkg/openapi/oas_parameters_gen.go index 5e6351d..8eb5f1d 100644 --- a/pkg/api/oas_parameters_gen.go +++ b/pkg/openapi/oas_parameters_gen.go @@ -1,6 +1,6 @@ // Code generated by ogen, DO NOT EDIT. -package api +package openapi import ( "net/http" diff --git a/pkg/api/oas_request_decoders_gen.go b/pkg/openapi/oas_request_decoders_gen.go similarity index 99% rename from pkg/api/oas_request_decoders_gen.go rename to pkg/openapi/oas_request_decoders_gen.go index cea7e00..f324b99 100644 --- a/pkg/api/oas_request_decoders_gen.go +++ b/pkg/openapi/oas_request_decoders_gen.go @@ -1,6 +1,6 @@ // Code generated by ogen, DO NOT EDIT. -package api +package openapi import ( "io" diff --git a/pkg/api/oas_request_encoders_gen.go b/pkg/openapi/oas_request_encoders_gen.go similarity index 98% rename from pkg/api/oas_request_encoders_gen.go rename to pkg/openapi/oas_request_encoders_gen.go index 3003827..ee19408 100644 --- a/pkg/api/oas_request_encoders_gen.go +++ b/pkg/openapi/oas_request_encoders_gen.go @@ -1,6 +1,6 @@ // Code generated by ogen, DO NOT EDIT. -package api +package openapi import ( "bytes" diff --git a/pkg/api/oas_response_decoders_gen.go b/pkg/openapi/oas_response_decoders_gen.go similarity index 92% rename from pkg/api/oas_response_decoders_gen.go rename to pkg/openapi/oas_response_decoders_gen.go index ead0fac..3a42d70 100644 --- a/pkg/api/oas_response_decoders_gen.go +++ b/pkg/openapi/oas_response_decoders_gen.go @@ -1,8 +1,9 @@ // Code generated by ogen, DO NOT EDIT. -package api +package openapi import ( + "fmt" "io" "mime" "net/http" @@ -60,6 +61,23 @@ func decodeGroupsGetResponse(resp *http.Response) (res []Group, _ error) { if response == nil { return errors.New("nil is invalid value") } + var failures []validate.FieldError + for i, elem := range response { + if err := func() error { + if err := elem.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: fmt.Sprintf("[%d]", i), + Error: err, + }) + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } return nil }(); err != nil { return res, errors.Wrap(err, "validate") @@ -265,6 +283,15 @@ func decodeGroupsIDGetResponse(resp *http.Response) (res GroupsIDGetRes, _ error } return res, err } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } return &response, nil default: return res, validate.InvalidContentType(ct) @@ -383,6 +410,15 @@ func decodeGroupsIDPutResponse(resp *http.Response) (res GroupsIDPutRes, _ error } return res, err } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } return &response, nil default: return res, validate.InvalidContentType(ct) @@ -501,6 +537,15 @@ func decodeGroupsPostResponse(resp *http.Response) (res *Group, _ error) { } return res, err } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } return &response, nil default: return res, validate.InvalidContentType(ct) @@ -680,6 +725,23 @@ func decodeUsersGetResponse(resp *http.Response) (res []User, _ error) { if response == nil { return errors.New("nil is invalid value") } + var failures []validate.FieldError + for i, elem := range response { + if err := func() error { + if err := elem.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: fmt.Sprintf("[%d]", i), + Error: err, + }) + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } return nil }(); err != nil { return res, errors.Wrap(err, "validate") @@ -885,6 +947,15 @@ func decodeUsersIDGetResponse(resp *http.Response) (res UsersIDGetRes, _ error) } return res, err } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } return &response, nil default: return res, validate.InvalidContentType(ct) @@ -1003,6 +1074,15 @@ func decodeUsersIDGroupPutResponse(resp *http.Response) (res UsersIDGroupPutRes, } return res, err } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } return &response, nil default: return res, validate.InvalidContentType(ct) @@ -1121,6 +1201,15 @@ func decodeUsersIDPutResponse(resp *http.Response) (res UsersIDPutRes, _ error) } return res, err } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } return &response, nil default: return res, validate.InvalidContentType(ct) @@ -1239,6 +1328,15 @@ func decodeUsersPostResponse(resp *http.Response) (res *User, _ error) { } return res, err } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } return &response, nil default: return res, validate.InvalidContentType(ct) diff --git a/pkg/api/oas_response_encoders_gen.go b/pkg/openapi/oas_response_encoders_gen.go similarity index 99% rename from pkg/api/oas_response_encoders_gen.go rename to pkg/openapi/oas_response_encoders_gen.go index bc4eed5..e587f19 100644 --- a/pkg/api/oas_response_encoders_gen.go +++ b/pkg/openapi/oas_response_encoders_gen.go @@ -1,6 +1,6 @@ // Code generated by ogen, DO NOT EDIT. -package api +package openapi import ( "net/http" diff --git a/pkg/api/oas_router_gen.go b/pkg/openapi/oas_router_gen.go similarity index 99% rename from pkg/api/oas_router_gen.go rename to pkg/openapi/oas_router_gen.go index f5d102b..68627ce 100644 --- a/pkg/api/oas_router_gen.go +++ b/pkg/openapi/oas_router_gen.go @@ -1,6 +1,6 @@ // Code generated by ogen, DO NOT EDIT. -package api +package openapi import ( "net/http" diff --git a/pkg/api/oas_schemas_gen.go b/pkg/openapi/oas_schemas_gen.go similarity index 52% rename from pkg/api/oas_schemas_gen.go rename to pkg/openapi/oas_schemas_gen.go index 269f8f9..9a7737d 100644 --- a/pkg/api/oas_schemas_gen.go +++ b/pkg/openapi/oas_schemas_gen.go @@ -1,6 +1,6 @@ // Code generated by ogen, DO NOT EDIT. -package api +package openapi import ( "fmt" @@ -12,27 +12,27 @@ func (s *ErrorStatusCode) Error() string { // Ref: #/components/schemas/Error type Error struct { - Message OptString `json:"message"` - Code OptInt `json:"code"` + Message string `json:"message"` + Code int `json:"code"` } // GetMessage returns the value of Message. -func (s *Error) GetMessage() OptString { +func (s *Error) GetMessage() string { return s.Message } // GetCode returns the value of Code. -func (s *Error) GetCode() OptInt { +func (s *Error) GetCode() int { return s.Code } // SetMessage sets the value of Message. -func (s *Error) SetMessage(val OptString) { +func (s *Error) SetMessage(val string) { s.Message = val } // SetCode sets the value of Code. -func (s *Error) SetCode(val OptInt) { +func (s *Error) SetCode(val int) { s.Code = val } @@ -72,18 +72,18 @@ func (s *ErrorStatusCode) SetResponse(val Error) { // Ref: #/components/schemas/Group type Group struct { - ID OptID `json:"id"` - Name OptString `json:"name"` - Users []User `json:"users"` + ID ID `json:"id"` + Name string `json:"name"` + Users []User `json:"users"` } // GetID returns the value of ID. -func (s *Group) GetID() OptID { +func (s *Group) GetID() ID { return s.ID } // GetName returns the value of Name. -func (s *Group) GetName() OptString { +func (s *Group) GetName() string { return s.Name } @@ -93,12 +93,12 @@ func (s *Group) GetUsers() []User { } // SetID sets the value of ID. -func (s *Group) SetID(val OptID) { +func (s *Group) SetID(val ID) { s.ID = val } // SetName sets the value of Name. -func (s *Group) SetName(val OptString) { +func (s *Group) SetName(val string) { s.Name = val } @@ -112,16 +112,16 @@ func (*Group) groupsIDPutRes() {} // Ref: #/components/schemas/GroupUpdate type GroupUpdate struct { - Name OptString `json:"name"` + Name string `json:"name"` } // GetName returns the value of Name. -func (s *GroupUpdate) GetName() OptString { +func (s *GroupUpdate) GetName() string { return s.Name } // SetName sets the value of Name. -func (s *GroupUpdate) SetName(val OptString) { +func (s *GroupUpdate) SetName(val string) { s.Name = val } @@ -129,68 +129,22 @@ type ID int64 // Ref: #/components/schemas/Ok type Ok struct { - Message OptString `json:"message"` + Message string `json:"message"` } // GetMessage returns the value of Message. -func (s *Ok) GetMessage() OptString { +func (s *Ok) GetMessage() string { return s.Message } // SetMessage sets the value of Message. -func (s *Ok) SetMessage(val OptString) { +func (s *Ok) SetMessage(val string) { 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{ @@ -237,143 +191,51 @@ func (o OptID) Or(d ID) ID { 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"` + ID ID `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + Group Group `json:"group"` } // GetID returns the value of ID. -func (s *User) GetID() OptID { +func (s *User) GetID() ID { return s.ID } // GetName returns the value of Name. -func (s *User) GetName() OptString { +func (s *User) GetName() string { return s.Name } // GetEmail returns the value of Email. -func (s *User) GetEmail() OptString { +func (s *User) GetEmail() string { return s.Email } // GetGroup returns the value of Group. -func (s *User) GetGroup() OptGroup { +func (s *User) GetGroup() Group { return s.Group } // SetID sets the value of ID. -func (s *User) SetID(val OptID) { +func (s *User) SetID(val ID) { s.ID = val } // SetName sets the value of Name. -func (s *User) SetName(val OptString) { +func (s *User) SetName(val string) { s.Name = val } // SetEmail sets the value of Email. -func (s *User) SetEmail(val OptString) { +func (s *User) SetEmail(val string) { s.Email = val } // SetGroup sets the value of Group. -func (s *User) SetGroup(val OptGroup) { +func (s *User) SetGroup(val Group) { s.Group = val } @@ -383,27 +245,27 @@ func (*User) usersIDPutRes() {} // Ref: #/components/schemas/UserUpdate type UserUpdate struct { - Name OptString `json:"name"` - Email OptString `json:"email"` + Name string `json:"name"` + Email string `json:"email"` } // GetName returns the value of Name. -func (s *UserUpdate) GetName() OptString { +func (s *UserUpdate) GetName() string { return s.Name } // GetEmail returns the value of Email. -func (s *UserUpdate) GetEmail() OptString { +func (s *UserUpdate) GetEmail() string { return s.Email } // SetName sets the value of Name. -func (s *UserUpdate) SetName(val OptString) { +func (s *UserUpdate) SetName(val string) { s.Name = val } // SetEmail sets the value of Email. -func (s *UserUpdate) SetEmail(val OptString) { +func (s *UserUpdate) SetEmail(val string) { s.Email = val } diff --git a/pkg/api/oas_server_gen.go b/pkg/openapi/oas_server_gen.go similarity index 99% rename from pkg/api/oas_server_gen.go rename to pkg/openapi/oas_server_gen.go index d495602..f2042fe 100644 --- a/pkg/api/oas_server_gen.go +++ b/pkg/openapi/oas_server_gen.go @@ -1,6 +1,6 @@ // Code generated by ogen, DO NOT EDIT. -package api +package openapi import ( "context" diff --git a/pkg/api/oas_unimplemented_gen.go b/pkg/openapi/oas_unimplemented_gen.go similarity index 99% rename from pkg/api/oas_unimplemented_gen.go rename to pkg/openapi/oas_unimplemented_gen.go index f37fdb2..edaa9e1 100644 --- a/pkg/api/oas_unimplemented_gen.go +++ b/pkg/openapi/oas_unimplemented_gen.go @@ -1,6 +1,6 @@ // Code generated by ogen, DO NOT EDIT. -package api +package openapi import ( "context" diff --git a/pkg/openapi/oas_validators_gen.go b/pkg/openapi/oas_validators_gen.go new file mode 100644 index 0000000..1f2a673 --- /dev/null +++ b/pkg/openapi/oas_validators_gen.go @@ -0,0 +1,74 @@ +// Code generated by ogen, DO NOT EDIT. + +package openapi + +import ( + "fmt" + + "github.com/go-faster/errors" + + "github.com/ogen-go/ogen/validate" +) + +func (s *Group) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if s.Users == nil { + return errors.New("nil is invalid value") + } + var failures []validate.FieldError + for i, elem := range s.Users { + if err := func() error { + if err := elem.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: fmt.Sprintf("[%d]", i), + Error: err, + }) + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "users", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + +func (s *User) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if err := s.Group.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "group", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} diff --git a/pkg/users.go b/pkg/users.go deleted file mode 100644 index e69de29..0000000 diff --git a/tools/generate.go b/tools/generate.go index 0b4eb31..e32e682 100644 --- a/tools/generate.go +++ b/tools/generate.go @@ -1,3 +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 +//go:generate go run github.com/ogen-go/ogen/cmd/ogen@latest --target ../pkg/openapi -package openapi --clean ../api/openapi.yaml