papsign / Ktor-OpenAPI-Generator

Ktor OpenAPI/Swagger 3 Generator
Apache License 2.0
241 stars 42 forks source link

Make it possible to specify HTTP response code without using annotations #60

Closed sigmanil closed 4 years ago

sigmanil commented 4 years ago

We've recently started using this project, and we find it provides great value. One issue we're having, however, is code duplication (or alternatively the need for wrappers etc) in our "DTO" classes due to the fact that Ktor-OpenAPI-Generator seems to require HTTP response codes to be specified using the Response-annotation. Very often, the structures we want to return from GET, PUT and POST are the same, except for the http response code - a CRUD-api will want 201 for the POST, but 200 for the GET and PUT, for instance. The only way we've found around this is by having generic wrapper DTOs, but that means we can't have documentation that's specific to the endpoint.

It would be nice if the success status code for an endpoint could be passed as an argument to the post,get,put,etc functions - maybe as an argument to the info()-method?

Wicpar commented 4 years ago

Indeed it is sub-optimal as the status code can only be changed through the annotation. You have two options for a "quick" fix:

If I were to implement this i would do option 2, and have the annotation provided status code modules as default module, overridden by any other module specified in the module provider. If you wish to contribute that by implementing this behaviour in the current ResponseHandlerModule it would be great, else I can get to it in a few days.

Wicpar commented 4 years ago

Turns out the change is minimal, i'm on it, ETC: 1h.

Wicpar commented 4 years ago

0.2-beta.8 is out. I also changed the Module provider behaviour to guarantee insertion order in order to be usable as a stack as well, and changed KClass to KTypes to allow for generic specialisation. It might break some code, i explained how to fix it in the release notes.


                route("status/codes") {
                    route("201").status(201) {
                        // all endpoints in this block respond a 201 status code unless specified otherwise

                        get<StringParam, StringResponse>(
                            info("201 String Param Endpoint", "This is a String Param Endpoint that has a 201 status code"),
                            example = StringResponse("Hi")
                        ) { params ->
                            respond(StringResponse(params.a))
                        }

                        route("reset").get<StringParam, StringResponse>(
                            info("String Param Endpoint with @response based status code", "This is a String Param Endpoint that resets the status code back to the one provided by @Response"),
                            responseAnnotationStatus(),
                            example = StringResponse("Hi")
                        ) { params ->
                            respond(StringResponse(params.a))
                        }
                    }

                    route("202").get<StringParam, StringResponse>(
                        info("String Param Endpoint with inline 202 response", "This is a String Param Endpoint that has a 202 response code"),
                        status(HttpStatusCode.Accepted),
                        example = StringResponse("Hi")
                    ) { params ->
                        respond(StringResponse(params.a))
                    }
                }
sigmanil commented 4 years ago

Awesome, thank you very much! We'll try it out ASAP! :-)