As it will become quickly apparent, I have never seriously written a webserver before
Here is the current scenario:
My endpoint is written with Express in TypeScript
class ChatRequest {
public uid: string;
public message: string;
}
export const register = (app: express.Application, deps: dependencies.IDependencies) => {
app.post("/sendChat", (req: express.Request, res: express.Response) => {
transformAndValidate(ChatRequest, req.body)
.then((sendGlobalChatRequest: SendGlobalChatRequest) => {
const payload = {
message: sendGlobalChatRequest.message,
uid: sendGlobalChatRequest.uid
};
//Check if uid is banned here
//Check if payload passes language filter here
//Save Payload here
res.sendStatus(200);
}, (err) => {
deps.logger.error(err);
res.sendStatus(503);
});
});
I have been using this article for reference: https://hackernoon.com/the-request-sent-bad-data-whats-the-response-94088bd290a
But I think my conclusion is that they are discussing something slightly different.
So from my understanding, I can just make up HTTP codes...
so I could just do res.sendStatus(499);
if the uid is banned, and maybe res.sendStatus(498);
if the payload doesn't pass language filter
Then my client can just read the Int
statusCode
and quickly determine the failure.
But even though I think I can do that, and it would work, it doesn't seem right?
Should I instead be using a standard HTTP Response Code? https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
And then add in the body of the response, a String
or something that my client can parse to determine the error?
The String parsing seems way harder to maintain, but technically seems more "legal" if that makes sense?
What is the best way for me to have a client determine the type of server-side error?
I decided to return 400 with a JSON mapping errors to bools
if (isProfane(message)) {
res.status(400).json({messageContentBlocked: true});
}
In this way the client can receive multiple errors for the request at once, and it's more explicit
And in case anyone is googling around, I am using RxSwift/RxCocoa
Here is how I handle the error on the client:
extension Error {
var chatMessageBlockedURLError: Bool {
guard let rxCocoaURLError = self as? RxCocoaURLError else {return false}
switch rxCocoaURLError {
case let .httpRequestFailed(response, data):
guard response.statusCode == 400, let data = data else {return false}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .millisecondsSince1970
guard let errors = try? decoder.decode([String:Bool].self, from: data) else {return false}
return errors["messageContentBlocked"] == true
default:
return false
}
}
}