-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
How to properly document status codes and data structures in endpoints? #36513
Comments
Based on @come-nc's idea I created the following: https://psalm.dev/r/681f33c842. I like it a lot since it helps the static analysis and is clear for the generator. The two downsides I see are:
|
I disagree on this. I believe that a separation of code and comment (API spec) is not ideal, because someone has to ensure these two stay in sync. That is why I would prefer to only have one way of expressing our API design, and make that as idiomatic as possible. I support the idea of #36355 and typed responses. They allow us to express the types of a controller method and its returned data structure with PHP/PHPDoc. There is no new markup or syntax required. The tricky parts are the errors, like you've shown above. PHPDoc doesn't allow multiple return types. What if we go the PHP native path and use exceptions for those? E.g. a fully generic Writte as an example /**
* @param string $bar
* @throws ClientException<IFoo> If the …
* @return JsonResponse<IUser>
*/
public function foo(string $bar): Response {
if ($bar === 'err') {
throw new ClientException($this->foo, 200);
}
return new JsonResponse($this->service->getUser();
} |
I agree with you, I meant that we don't want to refactor a lot of code. Adding extra support code e.g. for typed responses is of course very good.
I already handle all the What do you think about the code snippet I sent above? |
Do you handle how the thrown exceptions are converted into HTTP responses? Is that even possible at the moment? I don't like mixing types with data and documentation to be honest. Status code is not a type, it's a value. Putting that into a template parameter feels wrong. And the documentation is also duplicated between PHPDoc and method body, which means they have to be kept in sync. I think having alternative types in |
This is kind of hardcoded. Only exceptions that extend OCSException can have a status code. All other ones return 500. Then I match the status code based on the name of the exception. The returned data is always a plain text string.
Technically yes, the status code is an integer, but it also indicates the type of the response, so it's some kind of type, right?
I also dislike this, as I said above, but I haven't found a solution for that yet (probably not possible because of more/less specific data types in psalm).
Agreed, I just had to do this for the cloud_federation_api which doesn't use exceptions because it's more complicated and returns complex data structures instead of a simple error string. |
https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/README.md#swashbuckleaspnetcoreannotations might be worth checking what other languages with comparable type systems do. |
Not sure what I can take from that doc. |
I had some serious issues with psalm and type resolving. In theory it looked very good, but psalm just handles stuff differently than I want. I decided for the descriptions we will just have a comment line like |
#36666 implements this approach. Psalm finally passes 🎉 |
There's gonna be a lot of classes needed to cover any possible status code: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes. This doesn't scale. Let's rather use the status as template parameter. I am still not fan of it but it's better than one class per status code. |
As I explained above that doesn't work because psalm collapses the types, but I agree that this solution is not the best. |
|
With classes as the returned data it works, but with type aliases the types just appear as I had a stupid idea that could also work: Just have a few dummy classes like |
To me this is a problem with psalm and type aliases, but I don't think we can change much about it. |
If I read https://psalm.dev/docs/annotating_code/typing_in_psalm/#docblock-type-syntax correctly this is unexpected because you used union types, not intersection types 🤔 What about https://psalm.dev/r/8d4547dd06? |
OTOH I'm not using type aliases, I spec the types directly. |
Uh that looks like the expected behaviour?! Maybe it is really something with type aliases or imported type aliases. The handling around those is definitely not great as I learned from reading many psalm issues. |
I got a different error than I described above, but I've also seen this one already: https://psalm.dev/r/ac772774e8 |
Yeah, looks a like a Psalm bug with type imports :s If there is no existing ticket it might be worth a report. The Psalm devs are fairly responsive to reported issues. |
Will do :) |
How does it work with updating psalm after this is fixed? We are currently one major version behind... |
Someone has to do the update 😬 |
Let's see: vimeo/psalm#9305 |
Branch/PR is updated, except for the psalm bug everything should be working. |
We want to document what status codes and data types are returned from endpoints. This needs to be done in order to be able to generate OpenAPI specs.
None to very little code changes should be required, so updating comments/type annotations is the way we want to do this.
The comments should also help static analysis to validate the returned data.
My current approach:
This way it is clear what data is returned (see the arrow brackets of DataResponse) under which status code. It also makes it possible to have a description, which is not required, but very useful.
The problem is that multiple
@return
annotations are not allowed, so we can't go with this.Our best idea right now is something like this:
This is valid, but has the problem that the status codes are not validated against the code (just like in the first snippet) and also that people might forget to update the lower comments.
Another idea was to have more response classes like
JSONResponseXXX
for every status code. Then the annotations could look something like this:It makes static analysis stronger, but also requires code changes which we really want to avoid. It also requires some more changes than just replacing the response class, because some pieces of code set the status code dynamically (e.g. from a service response).
Neither of those solutions is great, so we really want to have something better.
The text was updated successfully, but these errors were encountered: