Repository navigation
Add lint for nullable request and response bodies #32
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -248,6 +248,55 @@ pub async fn device_auth_confirm( | |
| } | ||
| ``` | ||
|
|
||
| ### Nullable Bodies | ||
|
|
||
| Request and response bodies should not be nullable. Consider this handler: | ||
|
|
||
| ```rust | ||
| #[endpoint { | ||
| method = GET, | ||
| path = "/coordinator-status", | ||
| }] | ||
| pub async fn coordinator_status( | ||
| rqctx: RequestContext<Arc<ServerContext>>, | ||
| ) -> Result<HttpResponseOk<Option<CoordinatorStatus>>, HttpError> { | ||
| // ... | ||
| } | ||
| ``` | ||
|
|
||
| The corresponding OpenAPI response schema will be: | ||
|
|
||
| ```json | ||
| { | ||
| "nullable": true, | ||
| "allOf": [ | ||
| { | ||
| "$ref": "#/components/schemas/CoordinatorStatus" | ||
| } | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| A bare `null` response is valid JSON, but it is not idiomatic. Also, older | ||
| Dropshot versions did not generate correct OpenAPI documents for nullable | ||
| request and response types; see | ||
| [dropshot#1751](https://github.com/oxidecomputer/dropshot/pull/1751). | ||
|
|
||
| Instead, wrap the optional value in a struct: | ||
|
|
||
| ```rust | ||
| #[derive(Deserialize, JsonSchema, Serialize)] | ||
| pub struct CoordinatorStatusResponse { | ||
| pub status: Option<CoordinatorStatus>, | ||
| } | ||
| ``` | ||
|
|
||
| Alternatively, if `None` means that the resource doesn't exist, return a 404 Not | ||
| Found error. | ||
|
|
||
| The same applies to request bodies: rather than `TypedBody<Option<MyParams>>`, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a little interesting. Option is obviously overloaded in serde/serde_json to mean "maybe present" or "could be null", but it may not be unreasonable to have an optional POST body (even though it's not something dropshot supports well today). That said, I think this is the right restriction given the current capabilities. Also, this specific phrasing ("the same applies") may make more sense after the "make your Option a struct field" rather than after "None = 404"
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Hmm, from the openapi-lint perspective (which only works on OpenAPI documents, not Rust code) this would be represented as |
||
| accept a struct with an `Option<MyParams>` member. | ||
|
|
||
| ## External Rules | ||
|
|
||
| These rules only apply to APIs that are "external". | ||
|
|
||
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 might put this case first?
If
Noneis meant to indicate that the resource doesn't exist, consider returning404 Not Foundinstead. ...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.
Agreed, reversed the order of recommendations.