New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Strict server generation #499
Conversation
…est and response bodies, meaning less manual code and forced schema compliance
… generated code, fixed content type in RequestBody's comment
# Conflicts: # go.sum # pkg/codegen/templates/templates.gen.go
# Conflicts: # pkg/codegen/schema.go
Oh wow, this is a large, impressive PR. I'm slowly going through it. I think that "Strict" is a good word for it. Our code in here is intentionally more permissive, since at the beginning, we had many more limitations and wanted to fail open and leave more difficult validation to the handler code itself. I do like the idea of putting it behind a flag, however, I have to dig through more and understand what effect this might have on current schemas. It looks like it won't be breaking anything, which is good. I wish I had spent more time on conformance tests of some kind! |
# Conflicts: # cmd/oapi-codegen/oapi-codegen.go # examples/authenticated-api/echo/api/api.gen.go # examples/petstore-expanded/chi/api/petstore.gen.go # examples/petstore-expanded/echo/api/petstore-types.gen.go # examples/petstore-expanded/petstore-client.gen.go # internal/test/client/client.gen.go # internal/test/components/components.gen.go # internal/test/issues/issue-312/issue.gen.go # internal/test/schemas/schemas.gen.go # internal/test/server/server.gen.go # pkg/codegen/codegen.go # pkg/codegen/templates/request-bodies.tmpl
An update on the state of this PR. Most of the work is done,I just need to deal with some bugs with and additional properties, complete client implementation and write some documentation. |
…irst one will use an alias, all others will generate new structs
Ok, wow, nice changes here. I originally intended for oapi-codegen to be more like what you have written, however, I decided not to go that route because of lots of edge cases that are difficult to deal with, in terms of interpreting multiple types. To that end, I've built everything in layers, with really flexible, and verbose on the bottom, and nicer to use built on top of that. For instnace, we generate helpers to generate any kind of request, but on top of that, we build a client which makes that easier, etc. You have made a number of simplifying assumptions about encoding responses, which limit what the server can do, in exchange for having a cleaner interface, so if I may make a proposal, call this What your server can not do is handle unsupported content types - where the more generic Because you built this as an adapter around the existing ServerInterface, it's optional to the user, which is great. I think that the README.md needs some more info on the simplifying assumptions, but then I'm happy to merge this. this is the most complex work anyone has done in oapi-codegen outside of me, thank you. |
# Conflicts: # cmd/oapi-codegen/oapi-codegen.go # pkg/codegen/codegen.go # pkg/codegen/configuration.go # pkg/codegen/operations.go
Thanks, @deepmap-marcinr, but I have a few corrections:
The idea behind strict server is to always give user code an ability to get the required data, if permitted by schema. Thats why I bothered with
It won't break, |
Oh, I didn't notice the part about unhandled request types, nice. There are still other things which are blocked. For example, in |
It is possible with all 3 servers - all unsupported content types in responses will generate |
Hmm. So, do you consider this ready to go in as-is? |
I see it now. Yeah. I was looking through generated code to get an idea of what things work, and it's a lot to sift through. |
It needs documentation and some little touch ups on the binding side. It is something like 98% complete right now. I will try to finish it ASAP, but I don't have a lot of free time, so I would guess it will take me a month to get it to a fully complete state |
# Conflicts: # internal/test/components/components.gen.go
@deepmap-marcinr The PR is ready for review, I've fixed some small errors and added short documentation. I don't have a lot of free time to complete some optional stuff (like multipart binding for client), so it is going to come later, in a separate PR (or maybe someone else can do it). |
* Added strict server generation that does automatic marshaling of request and response bodies, meaning less manual code and forced schema compliance * Support any content type by using io.Reader * removed generating marshalling code from client for content types other than JSON * Multipart and formdata are now passed as forms without any binding * run make generate to fix the build * added sorting of request bodies to reduce number of random changes in generated code, fixed content type in RequestBody's comment * Implemented basic formdata binder (not yet integrated into strict server) * Added tests for strict generation, support for form marshalling, client improvements * Fixed incorrect referencing of request bodies, added sorting of response definitions * Added sorting of content types in responses * Support multipart responses using callback function, added header example * Added sorting of headers in response objects * Added proper testing to strict servers * Fix after master merge * Reuse responses defined in components section, moved strict test to tests * When multiple responses ref to a single reusable response, only the first one will use an alias, all others will generate new structs * Update generated code after merge * Some documentation for strict server * Support for AdditionalProperties when binding forms Co-authored-by: ilya.bogdanov <ilya.bogdanov@ispringsolutions.com> Co-authored-by: ilya.bogdanov <ilya.bogdanov@ispring.com>
Allows generating code that will automatically parse the request and response bodies. The advantages are:
How it works and how to use it:
strict-server
to generate parameter among one of existing servers (echo, gin and chi are supported)StrictServerInterface
and server-specificstrictHandler
, that implements vanillaServerInterface
. That way we reuse all of the code of existing services without need of duplicationStrictServerInterface
uses request and response structures. This makes it easy to pass them to middlewares, log them, etc. A structure is generated for each request, that contains all params (including path params), content type (if it is ambiguous) and all the bodies (if request supports multiple content types only one body field will be initialized). Structures are also generated for all response body combinations, so for example, returningAddPet200JSONResponse
sets the content type to "application/json", status code to 200 and marshals the body structure. Response headers, custom content types (if not fixed), custom response codes (if not fixed) are also supported.StrictServerInterface
methods returninterface{}
that can be one of response structures,nil
orerror
. Unfortunately go doesn't support union types, so we can't clearly declare what can be returned in the interface itselfapplication/json
,text/plain
,multipart/form-data
andapplication/x-www-form-urlencoded
content types are supported. Anything else is passed as anio.Reader
.multipart/form-data
andapplication/x-www-form-urlencoded
require additional data from request, so we have to support them.application/x-www-form-urlencoded
are now can be marhsalled to ajson
-tagged struct, whilemultipart/form-data
is being passed as amultipart.Reader
(because you may want to go through parts manually for perfomance reasons. You can still call a binder from runtime to bind it to the struct in your code)type: string, format: binary
now transforms into*multipart.FileHeader
. Required for formdata binding.Why is this a draft and what is not complete:
json
tags.File
wrapper.application/x-www-form-urlencoded
is working fine now, and I decided to not add multipart support to client for now, since server doesn't automatically bind multipart values, so client doesn't have to support it. I will probably do it in a separate PR later.Small example of a single method from petstore:
Thats all, would love to hear your thoughts and suggestions on this. Is anyone interested?