- 
                Notifications
    You must be signed in to change notification settings 
- Fork 56
Convert DecodingErrors thrown from request handling code to HTTP 400 … #161
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
base: main
Are you sure you want to change the base?
Convert DecodingErrors thrown from request handling code to HTTP 400 … #161
Conversation
| underlyingError: any Error | ||
| underlyingError: any Error, | ||
| httpStatus: HTTPResponse.Status, | ||
| httpHeaderFields: HTTPTypes.HTTPFields, | 
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.
These two will need to be optional and default to nil to avoid an API break.
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.
Ah good catch thank you
| underlyingError: any Error, | ||
| httpStatus: HTTPResponse.Status, | ||
| httpHeaderFields: HTTPTypes.HTTPFields, | ||
| httpBody: OpenAPIRuntime.HTTPBody? | 
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.
| httpBody: OpenAPIRuntime.HTTPBody? | |
| httpBody: OpenAPIRuntime.HTTPBody? = nil | 
| self.underlyingError = underlyingError | ||
| self.httpStatus = httpStatus | ||
| self.httpHeaderFields = httpHeaderFields | ||
| self.httpBody = httpBody | 
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.
Technically, adding parameters to an existing public initializer is an API break as well, so can you add a second initializer with all the properties, and call from the existing unchanged one to the new one?
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.
Instead of making these new properties nullable, how about setting them with sensible default values from the existing initializer? That way we can leave ServerError conforming to HTTPResponseConvertible and we don't have to deal with unwrapping them down the line.
| httpStatus: .internalServerError, | ||
| httpHeaderFields: [:], | ||
| httpBody: nil | 
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.
@czechboy0 Thoughts?
Motivation
The library does not gracefully handle when clients send requests with malformed request bodies, parameters, etc. If a client sends a request that for example is missing a required field or has a field that cannot be converted to the correct type, the server should respond with a
400indicating to the client that they have done something wrong. Instead, the library throws aDecodingErrorwhich propagates all the way up resulting in a500response which incorrectly tells the client that something went wrong on the server.Modifications
DecodingErrorsintoRuntimeErrors.ServerErrorconform toHTTPResponseConvertibleErrorHandlingMiddlewareto first check if the underlying error conforms toHTTPResponseConvertibleand if not use the values fromServerError. This allows theHTTPResponseConvertiblevalues set in aRuntimeErrorto be honoured after theRuntimeErroris transformed into aServerError.Result
Since
RuntimeErrorconforms toHTTPResponseConvertiblethese errors will get converted to400responses by theErrorHandlingMiddleware. This isn't a perfect solution because consumers of the library have to opt-in to theErrorHandlingMiddlewareto avoid returning500.Test Plan
400responses.