Adding information to Golang Gin HTTP error responses - mongodb

I am trying to return a custom error response when an HTTP 500 Internal Error is encountered. If I use c.JSON(http.StatusInternalServerError, CustomError{}) when a database write error occurs, Gin ignores my CustomError struct and substitutes a default "500 server Error" message.
How can I add information to the default response or return a custom response while still using the HTTP 500 Internal Server error code?
This is what I am trying to accomplish. Notifying users of a duplicate entry in the Mongo database. Gin ignores my DBErrorResponse struct and just returns the default 500 error json response.
_, err := handler.collection.InsertOne(handler.ctx, data)
if err != nil {
if mongo.IsDuplicateKeyError(err) {
dbErr := err.(mongo.WriteException)
c.JSON(
http.StatusInternalServerError,
models.DBErrorResponse{
Type: "Write Exception",
Code: dbErr.WriteErrors[0].Code,
Err: "similar record exists",
})
return
}

If the error is caused by a user providing a duplicate key, it's not an internal server error. You might want to use something like BadRequest(400), which suits duplicate value far more, if provided by the client. Thus, you should be able to return a custom error message with StatusCode 400.
Additionally, as far as I know, InternalServerError(500) is not designed to provide a 'server-side' problem feedback to the client, since, well, it's not public information. Although I'm not certainly sure if that's so and if is, why.
UPD: As Gavin mentioned, httpCode 409 is far better choice, here is the doc:
HTTP 409 error status: The HTTP 409 status code (Conflict) indicates that the request could not be processed because of conflict in the request, such as the requested resource is not in the expected state, or the result of processing the request would create a conflict within the resource.

Related

Why does `Client.Send` returns nil err when status code is != 200

I am using sendgrid go library to send an email from my go server with the following snippet:
to := mail.NewEmail("", req.ToEmail)
from := mail.NewEmail("", "xxx#gmail.com") // redacted
m := mail.NewV3MailInit(from, "", to)
m.SetTemplateID("d-xxxxx") // redacted
client := sendgrid.NewSendClient(os.Getenv("SENDGRID_API_KEY"))
resp, err := client.Send(m)
if err != nil {
log.Printf("failed to send email to %s: %v\n", req.ToEmail, err)
}
However, when I didn't set the SENDGRID_API_KEY env var, the err was still nil (and the response was as following:
{
StatusCode:401
Body:{"errors":[{"message":"The provided authorization grant is invalid, expired, or revoked","field":null,"help":null}]}
Headers:map[Access-Control-Allow-Headers:[Authorization, Content-Type, On-behalf-of, x-sg-elas-acl] Access-Control-Allow-Methods:[POST] Access-Control-Allow-Origin:[https://sendgrid.api-docs.io] Access-Control-Max-Age:[600] Connection:[keep-alive] Content-Length:[116] Content-Type:[application/json] Date:[Mon, 05 Jul 2021 19:15:31 GMT] Server:[nginx] Strict-Transport-Security:[max-age=600; includeSubDomains] X-No-Cors-Reason:[https://sendgrid.com/docs/Classroom/Basics/API/cors.html]]}
I was blindly thinking that err should be set to something something non-nil, but I guess I need to look at status code in the response as well. Is there a quick way to check if the response returned is OK ?
Twilio SendGrid developer evangelist here.
I'm not a Go developer, so I might be wrong here, but I think I know what's going on in general here.
The SendGrid Go client uses the SendGrid REST client which ultimately calls on Go's standard lib HTTP client. The HTTP docs, under the Get method, say:
An error is returned if there were too many redirects or if there was an HTTP protocol error. A non-2xx response doesn't cause an error. Any returned error will be of type *url.Error. The url.Error value's Timeout method will report true if request timed out or was canceled.
An HTTP request that returns a result is a successful request, even if the result is not something you wanted. An HTTP request that doesn't return a result, like a connection error or too many redirects, will return an error.
According to the SendGrid API docs you should be looking for a 202 response status code to indicate a successful API request.

What response code should we use on a REST reply when the response data is an error message

We have a REST service where the response to a request may be an error message. A simple example is the request is a formula to calculate and the formula might have a divide by zero. In that case the response is an error code and error message.
So the communication with the REST service is all good. The service itself is responding to the request. But the response is an error message instead of the expected result.
In this case what is the best response code to use? 200 to say the entire communication process is good and we look in the returned JSON to determine if it’s an error? 500 to say it’s an error, but then look to see if we have the expected JSON to determine it was an error in the calculation? Some other code which says we are getting a response from the server but the response is an error message?
A simple example is the request is a formula to calculate and the formula might have a divide by zero. [...] In this case what is the best response code to use?
I would use 422 Unprocessable Entity
The 422 (Unprocessable Entity) status code means the server understands the content type of the request entity (hence a 415(Unsupported Media Type) status code is inappropriate), and the syntax of the request entity is correct (thus a 400 (Bad Request) status code is inappropriate) but was unable to process the contained instructions. For example, this error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous, XML instructions.
Don't rely only on HTTP code anyway, always add a description of the error in the body. I believe it's common practice to have all your endpoints reply with a JSON with success (true or false) and something like error (with the error message) if success if false, or data (with the result) if success is true.
For error messages we can use 4XX Bad Request
Look at this post, for various status codes.
http://www.restapitutorial.com/httpstatuscodes.html

Which HTTP code should be return from REST API?

im currently working on a website which has Spring at backend and Angularjs at front side and we had discussed about back end responses to handle frontend's message dialogs and i have a question to ask:
Lets say i have an API :
GET : /getstatistics
Request params : fromTime,toTime ( in timestamp format)
And if client make a request with invalid params like a string, which response code should be returned from server ? HTTP 400 bad request and response body with a message " fromTime and toTime should be in timestamp format" or HTTP 200 with same message?
I saw some Google's APIs for example Oauth, they're returning code 200 for a request with invalid access_token but ,in our project my opinion it should be HTTP 400 because Javascript has success and error callbacks, is it better for it just pop a red color dialog with message inside rather than a HTTP 200 code then still need to check the content of the message?
Any advides and opinions are appreciated.
Thanks!
You should be returning a 400 error for bad request. Check out this reference.
The server cannot or will not process the request due to something
that is perceived to be a client error (e.g., malformed request
syntax, invalid request message framing, or deceptive request
routing).
Please have a look at RFC7231#section-6
A client MUST understand the class of any status code, as indicated by
the first digit
and,
4xx (Client Error): The request contains bad syntax or cannot be
fulfilled
Bad syntax can be something like you've mentioned in your question (making a request with invalid parameters, like a string).
I keep these two references handy whenever I'm designing RESTful APIs, might be helpful for you too:
https://httpstatuses.com/
http://www.restapitutorial.com/httpstatuscodes.html
Yes you are right, the http code should be 400 in your case. Your discussion here normally should be whether you need to return 400 or 422. For this you can check the accepted response for this SO question 400 vs 422 response to POST of data
I think it has something to do with how the parameters are used. If you use the resource, then a 404 should return. If the data is simply not valid then we decide to set a 409 Status to the request. It can't full fill it at 100% because of missing/invalid parameter.
HTTP Status Code "409 Conflict" was for us a good try because it's
definition require to include enough information for the user to
recognize the source of the conflict.
Reference: w3.org/Protocols/
Edit:
In any case, the status code 200 is incorrect here because there is an error. In response, you can then return specific information like this:
{
"errors": [
{
"userMessage": "Sorry, the parameter xxx is not valid",
"internalMessage": "Invalid Time",
"code": 34,
"more info": "http://localhost/"
}
]
}

REST API & HTTP Status Code

I have a bunch of PUT operations which execute actions on the input resource.
Let's make an example: I have a payment operation in my API which state that a credit card must be charged by a specific Amount.
In my code I first verify if there is sufficient credit on the card and then execute the operation. If there is'nt sufficient amount I simply return 400 but I am not sure it is correct.
Which is the correct HTTP Status Code in cases like this?
I can, of course send a response with HTTP 200 and attach a payload with further details explaining the error. I can also send back an HTTP 400 Bad Request or even better an HTTP 412 Precondition Failed.
Which is the correct code to send in the response in scenario like this where the validation failed? Is there any resource that I can read to understand the rationale behind HTTP Status Codes and HTTP Verbs?
Use 422 Unprocessable Entity.
The 422 status code means the server understands the content type of the request entity (hence a 415 Unsupported Media Type status code is inappropriate), and the syntax of the request entity is correct (thus a 400 Bad Request status code is inappropriate) but was unable to process the contained instructions.
Failing that, simply use 400 for any error having to do with your business domain. As of June 2004, the description for error 400 was amended to read:
The server cannot or will not process the request due to something that is perceived to be a client error
If the operation failed because of data sent by the user (it seems to be the case), you should use status codes 400 (general) or 422 (more precise but coming from the WebDAV spec). You can return back additional hints about the error within the payload (the structure is up to you) like:
{
error: {
"field": "amount",
"message": "The amount isn't correct - Sufficient credit."
}
}
I think that code 412 doesn't apply here since it must be returned when your server doesn't meet a condition specified by the client (see headers If-* like If-Match, If-Modified-Since, ...).
Hope it helps you,
Thierry
IMO: I would stick with 200 and then parse out the response and deal with that. HTTP status codes are protocol status code, not something that you should use for dealing with application logic.
{
"error": {
"field": "amount",
"message": "The amount isn't correct - Sufficient credit."
}
}
In case of the above code, the service call worked fine warranting a return code 200. However, you application logic now needs to deal with the error reported.
If we are using a HTTP status code to indicate error, we will start to get flagged in our logs etc. even though there was no technical error.

Is it correct to return 404 when a REST resource is not found?

Let's say I have a simple (Jersey) REST resource as follows:
#Path("/foos")
public class MyRestlet extends BaseRestlet
{
#GET
#Path("/{fooId}")
#Produces(MediaType.APPLICATION_XML)
public Response getFoo(#PathParam("fooId") final String fooId)
throws IOException, ParseException
{
final Foo foo = fooService.getFoo(fooId);
if (foo != null)
{
return response.status(Response.Status.OK).entity(foo).build();
}
else
{
return Response.status(Response.Status.NOT_FOUND).build();
}
}
}
Based on the code above, is it correct to return a NOT_FOUND status (404), or should I be returning 204, or some other more appropriate code?
A 404 response in this case is pretty typical and easy for API users to consume.
One problem is that it is difficult for a client to tell if they got a 404 due to the particular entity not being found, or due to a structural problem in the URI. In your example, /foos/5 might return 404 because the foo with id=5 does not exist. However, /food/1 would return 404 even if foo with id=1 exists (because foos is misspelled). In other words, 404 means either a badly constructed URI or a reference to a non-existent resource.
Another problem arises when you have a URI that references multiple resources. With a simple 404 response, the client has no idea which of the referenced resources was not found.
Both of these problems can be partially mitigated by returning additional information in the response body to let the caller know exactly what was not found.
Yes, it is pretty common to return 404 for a resource not being found. Just like a web page, when it's not found, you get a 404. It's not just REST, but an HTTP standard.
Every resource should have a URL location. URLs don't need to be static, they can be templated. So it's possible for the actual requested URL to not have a resource. It is the server's duty to break down the URL from the template to look for the resource. If they resource doesn't exist, then it's "Not Found"
Here's from the HTTP 1.1 spec
404 Not Found
The server has not found anything matching the Request-URI. No indication is given of whether the condition is temporary or permanent. The 410 (Gone) status code SHOULD be used if the server knows, through some internally configurable mechanism, that an old resource is permanently unavailable and has no forwarding address. This status code is commonly used when the server does not wish to reveal exactly why the request has been refused, or when no other response is applicable.
Here's for 204
204 No Content
The server has fulfilled the request but does not need to return an entity-body, and might want to return updated metainformation. The response MAY include new or updated metainformation in the form of entity-headers, which if present SHOULD be associated with the requested variant.
If the client is a user agent, it SHOULD NOT change its document view from that which caused the request to be sent. This response is primarily intended to allow input for actions to take place without causing a change to the user agent's active document view, although any new or updated metainformation SHOULD be applied to the document currently in the user agent's active view.
The 204 response MUST NOT include a message-body, and thus is always terminated by the first empty line after the header fields.
Normally 204 would be used when a representation has been updated or created and there's no need to send an response body back. In the case of a POST, you could send back just the Location of the newly created resource. Something like
#POST
#Path("/something")
#Consumes(...)
public Response createBuzz(Domain domain, #Context UriInfo uriInfo) {
int domainId = // create domain and get created id
UriBuilder builder = uriInfo.getAbsolutePathBuilder();
builder.path(Integer.toString(domainId)); // concatenate the id.
return Response.created(builder.build()).build();
}
The created(URI) will send back the response with the newly created URI in the Location header.
Adding to the first part. You just need to keep in mind that every request from a client is a request to access a resource, whether it's just to GET it, or update with PUT. And a resource can be anything on the server. If the resource doesn't exist, then a general response would be to tell the client we can't find that resource.
To expand on your example. Let's say FooService accsses the DB. Each row in the database can be considered a resource. And each of those rows (resources) has a unique URL, like foo/db/1 might locate a row with a primary key 1. If the id can't be found, then that resource is "Not Found"
Though this question already have an accepted answer, I believe it's really an opinionated thing. Adding my two cents to help you make a more informed decision about the response code.
404 - Not Found. (Reference)
The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
The resource may exist and you may not have permission to see the resource, will also be equivalent of Not Found. So 404 for a call where data doesn't exist is a very apt thing to do.
Now as for a non-existing URL; though 404 is a widely adapted response code 400 is a more appropriate code.
400 - Bad Request (Reference)
The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).
If you put an invalid parameter in the request, what would be the response code?
If query param has a typo, what should be response code?
Answer to both is 400.
Most of the file-servers, return 404 for invalid URL because for an invalid URL they try to look for a file, which they can't find on the storage ~= Resource Not Found
Apart from the HTTP Status Code, the response will have some info about the error details, where one can be more descriptive about the error and can clear the ambiguity.
If client is calling with an invalid URL, it's an integration issue and should be caught at least during the sanity. No-way they will push the code to production without testing and catching this. Even if they do, God bless them!
tl;dr - 404 for not-found resource; 400 for not-found URL.
A 4XX error code means error from the client side.
As you request a static resource as an image or a html page, returning a 404 response makes sense as :
The HTTP 404 Not Found client error response code indicates that the
server can't find the requested resource. Links which lead to a 404
page are often called broken or dead links, and can be subject to link
rot.
As you provide to clients some REST methods, you rely on the HTTP methods but you should not consider REST services as simple resources.
For clients, an error response in the REST method is often handled close to errors of other processings.
For example, to catch errors during REST invocations or somewhere else, clients could use catchError() of RxJS.
We could write a code (in TypeScript/Angular 2 for the sample code) in this way to delegate the error processing to a function :
return this.http
.get<Foo>("/api/foos")
.pipe(
catchError(this.handleError)
)
.map(foo => {...})
The problem is that any HTTP error (5XX or 4XXX) will terminate in the catchError() callback.
It may really make the REST API responses misleading for clients.
If we do a parallel with programming language, we could consider 5XX/4XX as exception flow.
Generally, we don't throw an exception only because a data is not found, we throw it as a data is not found and that that data would have been found.
For the REST API, we should follow the same logic.
If the entity may not be found, returning OK in the two cases is perfectly fine :
#GET
#Path("/{fooId}")
#Produces(MediaType.APPLICATION_XML)
public Response getFoo(#PathParam("fooId") final String fooId)
throws IOException, ParseException {
final Foo foo = fooService.getFoo(fooId);
if (foo != null){
return Response.status(Response.Status.OK).entity(foo).build();
}
return Response.status(Response.Status.OK).build();
}
The client could so handle the result according to the result is present or missing.
I don't think that returning 204 brings any useful value.
The HTTP 204 documentation states that :
The client doesn't need to go away from its current page.
But requesting a REST resource and more particularly by a GET method doesn't mean that the client is about terminating a workflow (that makes more sense with POST/PUT methods).
The document adds also :
The common use case is to return 204 as a result of a PUT request,
updating a resource, without changing the current content of the page
displayed to the user.
We are really not in this case.
Some specific HTTP codes for classical browsing matche finely with return codes of REST API (201, 202, 401, and so for...) but this is not always the case.
So for these cases, rather than twisting original codes, I would favor to keep them simple by using more general codes : 200, 400.