4 ms·
Here's an example straight from code I've rewritten at least 5 times because I'm allergic to saving myself time: export enum ErrorCode { InvalidEntit
by hardwaresofton 5y ago
Here's an example straight from code I've rewritten at least 5 times because I'm allergic to saving myself time:
export enum ErrorCode {
InvalidEntity = 1,
NotSupported = 2,
UnexpectedServerError = 3,
InvalidRequest = 4,
Validation = 5,
// ...
}
export enum ResponseStatus {
Success = "success",
Error = "error",
}
export class ResponseEnvelope<T> {
public readonly status: ResponseStatus = ResponseStatus.Success;
public readonly data: T | Pruned<T> | null = null;
public readonly error?: {
code: ErrorCode,
message: string,
details: object | string,
status: ResponseStatus,
};
constructor(opts?: Partial<ResponseEnvelope<T>>) {
if (opts) {
if (opts.status) { this.status = opts.status; }
if (opts.data) { this.data = opts.data; }
if (opts.error) { this.error = opts.error; }
}
if (!this.data) { return; }
// Prune if the thing is prunable
this.data = prune(this.data);
}
}
Hopefully this isn't too hard to grok, it's Typescript.
BTW, If you're cringing at the number scheme for the ErrorCode enum, don't worry I am too. This is why I prefer to use strings rather than numbers, and it basically just ends up being stuff like "invalid-entity", etc.
- JackFr 5y agoI completely disagree. I find envelopes to be unnecessary cruft that just junk up otherwise clear code. And I think packing metadata into an envelope along with the actual data keeps people from thinking clearly about their own APIs, mostly with respect to ambiguity surrounding the word “error”. Validation errors are errors and network failures are errors, but they’re very different animals and should never be conflated. I don’t want to check for a status code in metadata ever, when an HTTP status is provided. I don’t want to read a time stamp if that time stamp is simply a property of the request. However if the time stamp is a property of the data, then I care - but then it shouldn’t be part of the metadata.
- hardwaresofton 5y agoWell I imagine this is why sages like uncle bob and sam newman will always be needed. > Validation errors are errors and network failures are errors, but they’re very different animals and should never be conflated. > I don’t want to check for a status code in metadata ever, when an HTTP status is provided. These seem like conflicting views. If the HTTP status is all you check you must be conflating application/operation status and network status. > I don’t want to read a time stamp if that time stamp is simply a property of the request. However if the time stamp is a property of the data, then I care - but then it shouldn’t be part of the metadata. Sure -- I'd like to say that I think the disagreement here boils down to this question: should metadata be represented in data responses. Correct me if I'm reading you incorrectly, but it seems like you're arguing that metadata should not be represented in the response, only data. I'd argue that the in-practice and academic standards dictate the opposite, with standards like hypermedia, json schema, HAL, JSON:API, OpenAPI, etc. If it's just a question about the degree of metadata that should be present then that's one thing, but it sounds like you're against it in general. Once you have any metadata you must have an envelope of some sort, by definition (whether it's a good or bad one), as far as I can see.
- deleted 5y ago[deleted]
- kortex 5y agoI think I'm with Jack on this one, at least when it comes to REST interfaces. When I query GET /bar/123, I want an object with a Bar protocol/content-type. I don't want a Envelope[Bar]. What if it's any data type other than json-isomorphic, e.g. image or video? Is /videos/123.mp4 going to return a json object like {"data": <base64_encoded_video>, "status": "whatever"} Of course not! You already have an envelope, it's the HTTP protocol. The real trick is generically mapping data structures to HTTP responses with headers. In fact HTTP-response-shaped-objects make halfway decent general purpose envelopes in the business logic itself. They are basically Result[T, E] but with even more metadata available.
- deleted 5y ago[deleted]
- deleted 5y ago[deleted]
- bcrosby95 5y agoWe wrap the response body because it's important to give clients of an API endpoint, something that they will use to query/modify data, a clear indicator of the application response status. We do this in the response body because http status codes aren't good enough, and people tend to miss headers. It's hard to miss it when it's part of the body. And no, we don't do that for static content for a simple reason: static content isn't served from our API servers.
- deleted 5y ago[deleted]