-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
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
[Spring] can't handle multiple responses #1096
Comments
I wonder that this issue has such a low activity. Is there any recommended workaround, or do you plan to fix it in an upcoming release? |
Is there any update on this issue? we are facing the same problem where we have to return different objects depending on the status of the response.... |
Any news on it? |
Would be nice to support OrderResponseOK:
description: OK
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/Order"
properties:
message:
readOnly: true
type: string
example: "OK" |
Hello, I was coming back here to see if there is any progress on that. If that can help, our workaround so far is to add a type 'object' to all of the possible response types so that the API end-point takes ResponseEntity as the default returned type. We do it this way: The end-point definition:
And:
This does not look good, but we did not find a better work-around... |
One workaround is to define all responses as SuccessResponse:
type: object
properties:
message:
type: string
ErrorResponse:
type: object
properties:
errors:
type: array
items:
type: string
Response:
oneOf:
- $ref: '#/components/schemas/SuccessResponse'
- $ref: '#/components/schemas/ErrorResponse' SuccessResponse and ErrorResponse models will implement Response, generated as an empty interface. |
So I guess the controller method is typed based on what it thinks is the primary response. You can trick it to return something else because of generics type erasure: return (ResponseEntity<ApiExampleObject>)(ResponseEntity<?>) differentResponse; I'm curious, why did the project owners not answer this? It's been open since 2018 and is a very important use-case with a simple answer. |
@davidmoten why the thumbs down? Is there a problem with the workaround? |
No it's a valid workaround, I removed the thumbs down. Easier and generally more practical just to learn the casting trick but I do like the extra type safety your workaround gives. Not practical to rework large complex third-party apis just to get that feature though. It could be done by the openapi-generator generator where it creates a oneOf type class that also checks validity of type codes (without you having to do it). |
Up Does this have preview of planning/release? This feature is useful for good design, code and api. |
To solve the problems of being able to return multiple type of object while keeping the existing logic, we could take advantage of the fact that, other response than 200 are related to a problem (aka an Exception.) Therefore we could use the java native extension system to be able to return the type corresponding to the code we want. For example give
In the current generator we generate something like @Override
public ResponseEntity<ValidResponse> getDummy() {
// our implementation
} Using java exception, for example, the openapi generator could generate a class public class GetDummyException extends Exception {
public GetDummyException(WrongResponse) { /*handle*/ }
public GetDummyException(NotFoundResponse) { /*handle*/ }
} This would for example change the signature of our
What do you think @davidmoten |
I like that @axel7083. It's like the oneOf return but isolated to the non-2xx responses.
|
Thanks for the anwser! Glad to see it got some interest. In our team, we face very frequently the issue of dealing with returning something for non-2XX response, aiming to provide more informations to the api clients when something got wrong. I would be interested to contribute on it, as we would benefits from it! |
@davidmoten I gave it a try! Based on the discussion I took a look at the api.mustache for JavaSpring (version 6.5.0). First I created a custom Exception class inside the interface (why not) public class {{classname}}Exception extends Exception {
HttpStatus status;
Object res;
public ResponseEntity<?> getResponseEntity() {
return new ResponseEntity(res, status);
}
{{#responses}}
public {{classname}}Exception({{{baseType}}} response) {
status = HttpStatus.resolve({{code}});
res = response;
}
{{/responses}}
} The idea mainly is to use the E.g.Given a very basic endpoint paths:
/test:
get:
summary: test
operationId: test
parameters:
- $ref: "#/components/parameters/TestCode"
responses:
"200":
$ref: "#/components/responses/Test200"
"404":
$ref: "#/components/responses/Test404"
"500":
$ref: "#/components/responses/Test500" TestApiExceptionWe generate a public class TestApiException extends Exception {
HttpStatus status;
Object res;
public ResponseEntity<?> getResponseEntity() {
return new ResponseEntity(res, status);
}
public TestApiException(S200Test response) {
status = HttpStatus.resolve(200);
res = response;
}
public TestApiException(S404Test response) {
status = HttpStatus.resolve(404);
res = response;
}
public TestApiException(S500Test response) {
status = HttpStatus.resolve(500);
res = response;
}
} TestApi methodsThe delegate method DelegateThe big change is that the ResponseEntity has generic parameter ? to ensure no issue while returning specific type. .... header
default ResponseEntity<?> _test(
@NotNull @Parameter(name = "code", description = "", required = true, in = ParameterIn.QUERY) @Valid @RequestParam(value = "code", required = true) Integer code
) throws Exception {
try {
return test(code);
} catch (TestApiException e) {
return e.getResponseEntity();
}
} Method to override by userThe base method to override keep the type of the 200 response code. This is to avoid regression and keep logic the use of exception for non-200 response code. // Override this method
default ResponseEntity<S200Test> test(Integer code) throws Exception {
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
} Here is on our example the user can thrown exception, and the proper http code will be used.
|
Will 2024 be the year they resolve this defect? 🤔 |
See it in 2025 🙂 (i hope) |
Hi everyone, I also had this problem. after a day working on that issue I think the openApi vision was to create an interface with return value "Strict". For the case with error => you must use ControllerAdvices. And the fact is that it is simpler to do that for an app. For example : `@ControllerAdvice
}`
I test all exception and they all work. If you don't understand spring exception management you can also watch this video : https://www.youtube.com/watch?v=PzK4ZXa2Tbc |
Description
We have an OpenAPI spec file where we've defined multiple possible responses for an operation, however when the Spring code is generated the generated @RequestMapping method is only capable of returning the first response defined.
openapi-generator version
3.2.3
OpenAPI declaration file content or url
Command line used for generation
Steps to reproduce
Generate the Spring code using the specified spec file and maven configuration.
The following @RequestMapping is generated:
The return type is of ResponseEntity<ApiExampleObject> which means I can't return an ApiErrors object.
Related issues/PRs
Sounds similar to #316
Suggest a fix/enhancement
Get the method to return an object that can encapsulate one of the types defined in the response.
Or a simpler option is to get the method to return a ResponseEntity<Object>.
The text was updated successfully, but these errors were encountered: