-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
204 response enhancements #5090
base: master
Are you sure you want to change the base?
Conversation
New document generator setting to allow for certain response codes to be treated as a nullable response, even if the response type is void. On the client generation side, we treat all 2xx responses with the same response type as the 200 response as success responses. Expanded that to include responses with the same type but nullable. During client generation, if there are multiple success responses where some are nullable, we set the whole method return type as nullable.
@RicoSuter & @lahma I took a stab at addressing part of the problem in the linked issue. Please review and let me know your thoughts. Happy to make any changes needed. |
@@ -102,21 +102,28 @@ public string UnwrappedResultType | |||
{ | |||
get | |||
{ | |||
var response = GetSuccessResponse(); | |||
if (response.Value == null || response.Value.IsEmpty(_operation)) | |||
TResponseModel response = GetSuccessResponseModel(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is calling a new method. Other call sites still use the original unchanged GetSuccessResponse
method.
if (!isNullable) | ||
{ | ||
// If one of the success types is nullable, we set the method return type to nullable as well. | ||
isNullable = Responses.Any(r => r.IsSuccess && r.Type == response.Type + "?" && r.IsNullable); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new method call gives us access to the response type to see if we have additional success responses with the same underlying type that are null. Which means we would want to mark the operation as a whole nullable.
This change would solve the issues I've been running into and I'd love to see this integrated sooner rather than later. |
@@ -110,9 +112,11 @@ public bool IsSuccess | |||
} | |||
|
|||
var primarySuccessResponse = _operationModel.Responses.FirstOrDefault(r => r.IsPrimarySuccessResponse); | |||
|
|||
// We should ignore nullability when evaluating if both responses have the same return type. | |||
return HttpUtilities.IsSuccessStatusCode(StatusCode) && ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO, this check is factually incorrect.
A response is a success, when the status code is between 200 and 300 (400), no?
A 204 has by design no content, which means Data?
is wrong as response type.
It should be void.
Also, if someone would want to send a string on 201, but an object on 200, this check would still mark the response as failure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that more changes should be made here. I am trying to make this particular PR be minimally impactful so we could potentially do this as a minor version change with no behavior changes for existing consumers of NSwag unless they opt in by using the new functionality. Changing this check in general would be more of a major version change, which may take much longer to get published. I would suggest we tackle that part separately unless you can find a way to keep it backwards compatible without a behavior change for existing users.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess, we could introduce an option which says to treat only the same response types as success which is true by default. Not sure, if this class can have easy access to the options
Purpose of change
Partially addresses issues from #1259
204 is a valid response type and it is valid to potentially return a 200 or a 204 from the same route. Currently nswag generates a server error for 204 results. In addition, this covers the situation where one of the success response types may return a null, but not all.
Change Summary
New document generator setting
ResponseStatusCodesToTreatAsNullable
to allow for certain response codes to be treated as a nullable response, even if the response type is void. This means that we don't have to decorate everything that can return a 204 with theCanBeNull
attribute.On the client generation side, we treat all 2xx responses with the same response type as the 200 response as success responses. Expanded that to include responses with the same type but nullable. e.g. a 200 with
MyClass
and a 204 withMyClass?
would both return true whenIsSuccessStatusCode
is checked. A void type on the 204 would still not return true. That could be another enhancement to make later.During client generation, if there are multiple success responses (as defined by the result of
IsSuccessStatusCode
) where some are nullable, we set the whole method return type as nullable.Usage Example
In Program.cs we tell the document generator that we want all 204 methods that do not have a
NotNull
attribute to be treated as nullable response types. We also give the response type the same class as the 200 result to pass checks in the generator library that only treat results as successful if they have the same return type as the 200. That part is existing behavior.We have an example method in a .net web api.
Note that the 200 is not a nullable response and the 204 is nullable due to the setting in Program.cs. They both use the same return type.
Using this example open api spec and
generateNullableReferenceTypes
set to true.We would previously have generated something like this:
Now we get this: