Below is the error response that my API is returning to the client:
{
"statusCode": "400",
"errors": [
{
"errorCode": "50009",
"fieldName": "bookingDate",
"errorMsg": "Input bookingDate must lie in the bracket: 20 Jan - 27 Jan, 2018"
}
]
}
Client cannot show the errorMsg returned by the API in the UI, but it needs bracket information i.e. (20 Jan - 27 Jan, 2018) while forming some more meaning errorMsg. So, client has to extract bracket information from the API response.
But, this can break the client's functionality if the text of the errorMsg is changed.
So, to make client's life easy, I would like to change the error response slightly like this:
{
"statusCode": "400",
"errors": [
{
"errorCode": "50009",
"fieldName": "bookingDate",
"errorMsg": "Input bookingDate must lie in the bracket: 20 Jan - 27 Jan, 2018",
"startDate": "20 Jan 2018",
"endDate": "27 Jan 2018"
}
]
}
So, is it the right way to add startDate and endDate into the error response (just for the client's benefit) or is there any other better way?
Thanks in advance.
You are free whatever information you want to add to your error response. If you it's really useful to you, there is no reason not to. Facebook does so. On the other hand I would try to not bloat an error response.
A well designed and decoupled REST API implies most of the error reasons with the help of the standard definitions of the HTTP error codes, which still should be documented within the API documentation. Given this, a developer of a client is able to know the exact error only by parsing the error status.
This also means that a client developer needs to check whatever he can, straight away, without sending any request to the back end. For example if the given date range is valid.
Stating this, if a returning error code cannot be used to figure out the exact problem of the request, the design of the API interface might be not optimal.
Although as REST is only a concept, it's nearly impossible to implement a perfect RESTfull API, therefor there are always exceptions, IMHO.
Although this question tends to attract opinion-based answers, I will try to give some perhaps helpful hints.
Your API seems to validate user input. This input may be invalid for various reasons (e.g. no parseable date, date in the past etc.). This can never be reflected only via HTTP status codes and as such, returning an HTTP 400 and a validation error message, as you already do, is good practice.
This validation error message should be human-readable and it should be okay for the client to display it to the user. If a field name is included (as it is in your example), the client can even highlight the associated input field and display the error message next to it.
If the consumer of your API is not a UI, but some kind of automated service, then error related technical fields may fit the needs more. (And this is where opinions come into play: Many people say that the API should be agnostic of the consuming client types). But I think in your case, you should rather investigate why the client is unable to display the errorMsg - this should be the best and most flexible way to go to add additional validations in the future.
Related
Which one is best for Rest API response ?
In here I return some meta information with actual data. Although I am not sure they need to use those meta information or not.
{
"version": "1.0.0",
"isError": false,
"statusCode": 200,
"message": "Permission Object",
"data": {
"id": 1,
"name": "user create",
"created_at": "2022-11-30T10:18:20.000000Z"
}
}
In second example I am returning only the relevant data.
{
"id": 1,
"name": "user create",
"created_at": "2022-11-30T10:18:20.000000Z"
}
Give me suggestion if there are other better way.
I noticed you've used the tag REST, so I assume you are thinking about a RESTful API implementation and have some knowledge about RESTful API design.
If you need some best practices, a couple of them I think are useful. here and here.
Looking at your examples, I would prefer the second option, the reasons are:
IsError can be determined by the HTTP response, e.g. 400, 500, 200, 201, so it's redundant.
Status and Message are also redundant when the response is successful but could be useful in an error state, like in ASP.NET, you can use the ProblemDetails response (you can customize the way you want).
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "Unable to create a new user due to missing name",
"status": 400,
"traceId": "00-0aa7d64ad154a1e1853c413a0def982d-195d3558c90f7876-00"
}
version is an interesting one. Usually, it can be included in the request header or URL. If the API cannot handle the version requested, then it should return an error in the problem details.
Thus, I prefer the second option and send a problem details response when there is an error.
An open source CRM with more than 18K start on github uses Laravel-default api resource
Project Link
Code Example link
Pay attention to status codes
Reference
This one is super important. If there's one thing you need to remember from this article, this is probably it:
The worst thing your API could do is return an error response with a
200 OK status code.
It's simply bad semantics. Instead, return a meaningful status code that correctly describes the type of error.
Still, you might wonder, "But I'm sending error details in the response body as you recommended, so what's wrong with that?"
Let me tell you a story.
I once had to use an API that returned 200 OK for every response and indicated whether the request had succeeded via a status field:
{
"status": "success",
"data": {}
}
So even though the status was 200 OK, I could not be absolutely sure it didn't fail to process my request.
This kind of design is a real no-no because it breaks the trust between the API and their users. You come to fear that the API could be lying to you.
All of this is extremely un-RESTful. What should you do instead?
Make use of the status code and only use the response body to provide error details.
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "Expected at least two items in list."
}
JSON API is a format that works with HTTP. It delineates how clients should request or edit data from a server, and how the server should respond to said requests.
I'm adding a new REST service to our API, and wanted to canvas a few opinions on the best REST API. The service is used to retrieve the user's email address in case they have forgotten what their username is. The service requires three parameters:
Account number (this is a number that is on their printed statement)
Surname
Date of birth
If we find a match for these three pieces of info, the service returns JSON contained a masked version of the user's registered email address (eg. jo******#gmail.com) so that the UI can present a message something like "We are going to send your username to j******#g******.com. Is that OK?"
Note that the service doesn't actually change anything within their account or send an email (it is purely fetching info so that the user can confirm the next step), so it seems to me that a GET request is the way to go. The question is how to represent it? It strikes me that /users is a reasonable place to start(?), but then what? Using the URL path, I might end up with something like:
/users/accountEmail/accountNumber/123456/surname/Smith/dateOfBirth/25-12-1970
This seems icky as, ordinarily, our /users URLs contain the username (eg. /users/john/transactions), but clearly for this API call we don't actually know who the user is yet. I'm also not sure it really indicates what the service actually does. Alternatively, I could use URL query params:
/users/accountEmail?accountNumber=123456&surname=Smith&dateOfBirth=25-12-1970
This feels a bit more natural, but I'm unsure that stringing all those input parameters into the URL is a good idea. Then again, maybe /users is the wrong noun. Maybe it should be like:
/accountEmail/...
Having said all that, maybe given the service's idempotence, I could actually use a PUT request and encode the parameters into the HTTP body. Not sure about using PUT for read-only requests though... it seems a bit like heading down the RPC path. The one nice thing about the PUT approach though is that it doesn't log this relatively sensitive user input into any web server logs.
I'd be interested in opinions or hearing what other API developers did in a similar situation. Thanks.
First of all, don't use method GET with sensitive information in URL parameters or in a URL path, because that information can be stored in web server access log files, browser's history, HTTP proxy log files, etc.
Security wise you need to use method POST in this case. In regard of URL to use, I'm not that sure, probably something like /accounts and put all parameters to the request body.
Your second approach is what I would use. Logically, the URLS are build following these steps.
Collection Resource of Users
The URL
GET /users
returns a list of all users including all user properties.
[
12345: {
"surname": "Smith",
"firstname": "John",
"dateOfBirth": "1970-12-25",
"accountEmail": "john.smith#example.com"
},
6789 : {
"surname": "Hallow",
"firstname": "Jane",
"dateOfBirth": "1981-02-15",
"accountEmail": "jane.hallowh#example.com"
}
]
Sub-Collection Resource of User Emails
The URL
GET /users/accountEmail
returns al list alf all emails for all users.
[
12345: {
"accountEmail": "john.smith#example.com"
},
"accountEmail": "jane.hallowh#example.com"
}
]
Filter this Resource
The URL
GET /users/accountEmail?accountNumber=123456&surname=Smith&dateOfBirth=25-12-1970
returns a filtered list of emails for the users that match the query parameters.
[
12345: {
"accountEmail": "john.smith#example.com"
}
]
My final aim is to allow user to upload some content on to a google drive word document in their individual account.
I am using the PHP example provided on https://developers.google.com/drive/v2/reference/files/insert#examples. When uploading a simple text file, it works fine.
Then (after wasting almost 8 hours with mimetype application/msword. Not sure why the docs don't make it easier to find such common details.) I changed the mimetype to application/vnd.google-apps.document with empty data, and it worked absolutely fine.
Then, I created a doc file on google drive web interface and then exported it to my machine. It was saved as docx. Then in the example, this file is used as the source for data, I keep getting Error calling POST https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart: (400) Bad Request error.
The error message does not even provide any more details as to what is wrong with the request.
[responseBody:protected] => {
"error": {
"errors": [
{
"domain": "global",
"reason": "badRequest",
"message": "Bad Request"
}
],
"code": 400,
"message": "Bad Request"
}
}
You probably have to put the Word file's content as a string into the $request['content']
If it's .DOCX the proper MIME-type is a:
application/vnd.openxmlformats-officedocument.wordprocessingml.document
Reference: MSDN Library
Well, how shall one tell what's wrong by the response, but not the request which produces it?
You probably could have just written "HTTP400 - the crap is not working" instead,
which would provide about an equal amount of information.
HTTP Response-Code #400 in general means,
That the HTTP request was malformed (e.g. is missing parameters, wasn't properly escaped, etc).
^ ...and this is certainly the correct answer - according to the sample response.
And this is exactly the reason why the information provided isn't sufficient to provide you with a straight answer. I'd also wish the API to have a little more details in the responses (especially on occasional file validation errors) - because sometimes one can only guess what's wrong "on the other side".
Best practice is to start from a very simple working version and add some complexity then.
If you'd wish to have the issue reviewed/resolved, you should add a sample request.
Doesn't even matter how the code looks like - when the request is obviously malformed.
Ordinary I offer web-scripting as a service, just currently kinda out-of-resources.
I have a collection resource called Columns. A GET with Accept: application/json can't directly return a collection, so my representation needs to nest it in a property:-
{ "propertyName": [
{ "Id": "Column1", "Description": "Description 1" },
{ "Id": "Column2", "Description": "Description 2" }
]
}
Questions:
what is the best name to use for the identifier propertyName above? should it be:
d (i.e. is d an established convention or is it specific to some particular frameworks (MS WCF and MS ASP.NET AJAX ?)
results (i.e. is results an established convention or is it specific to some particular specifications (MS OData)?)
Columns (i.e. the top level property should have a clear name and it helps to disambiguate my usage of generic application/json as the Media Type)
NB I feel pretty comfortable that there should be something wrapping it, and as pointed out by #tuespetre, XML or any other representation would force you to wrap it to some degree anyway
when PUTting the content back, should the same wrapping in said property be retained [given that it's not actually necessary for security reasons and perhaps conventional JSON usage idioms might be to drop such nesting for PUT and POST given that they're not necessary to guard against scripting attacks] ?
my gut tells me it should be symmetric as for every other representation but there may be prior art for dropping the d/*results** [assuming that's the answer to part 1]*
... Or should a PUT-back (or POST) drop the need for a wrapping property and just go with:-
[
{ "Id": "Column1", "Description": "Description 1" },
{ "Id": "Column2", "Description": "Description 2" }
]
Where would any root-level metadata go if one wished to add that?
How/would a person crafting a POST Just Know that it needs to be symmetric?
EDIT: I'm specifically interested in an answer that with a reasoned rationale that specifically takes into account the impacts on client usage with JSON. For example, HAL takes care to define a binding that makes sense for both target representations.
EDIT 2: Not accepted yet, why? The answers so far don't have citations or anything that makes them stand out over me doing a search and picking something out of the top 20 hits that seem reasonable. Am I just too picky? I guess I am (or more likely I just can't ask questions properly :D). Its a bit mad that a week and 3 days even with an )admittedly measly) bonus on still only gets 123 views (from which 3 answers ain't bad)
Updated Answer
Addressing your questions (as opposed than going off on a bit of a tangent in my original answer :D), here's my opinions:
1) My main opinion on this is that I dislike d. As a client consuming the API I would find it confusing. What does it even stand for anyway? data?
The other options look good. Columns is nice because it mirrors back to the user what they requested.
If you are doing pagination, then another option might be something like page or slice as it makes it clear to the client, that they are not receiving the entire contents of the collection.
{
"offset": 0,
"limit": 100,
"page" : [
...
]
}
2) TBH, I don't think it makes that much difference which way you go for this, however if it was me, I probably wouldn't bother sending back the envelope, as I don't think there is any need (see below) and why make the request structure any more complicated than it needs to be?
I think POSTing back the envelope would be odd. POST should let you add items into the collection, so why would the client need to post the envelope to do this?
PUTing the envelope back could make sense from a RESTful standpoint as it could be seen as updating metadata associated with the collection as a whole. I think it is worth thinking about the sort of meta data you will be exposing in the envelope. All the stuff I think would fit well in this envelope (like pagination, aggregations, search facets and similar meta data) is all read only, so it doesn't make sense for the client to send this back to the server. If you find yourself with a lot of data in the envelope that the client is able to mutate - then it could be a sign to break that data out into a separate resource with the list as a sub collection. Rubbish example:
/animals
{
"farmName": "farm",
"paging": {},
"animals": [
...
]
}
Could be broken up into:
/farm/1
{
"id": 1,
"farmName": "farm"
}
and
/farm/1/animals
{
"paging": {},
"animals": [
...
]
}
Note: Even with this split, you could still return both combined as a single response using something like Facebook's or LinkedIn's field expansion syntax. E.g. http://example.com/api/farm/1?field=animals.offset(0).limit(10)
In response, to your question about how the client should know what the JSON payload they are POSTing and PUTing should look like - this should be reflected in your API documentation. I'm not sure if there is a better tool for this, but Swagger provides a spec that allows you to document what your request bodies should look like using JSON Schema - check out this page for how to define your schemas and this page for how to reference them as a parameter of type body. Unfortunately, Swagger doesn't visualise the request bodies in it's fancy web UI yet, but it's is open source, so you could always add something to do this.
Original Answer
Check out William's comment in the discussion thread on that page - he suggests a way to avoid the exploit altogether which means you can safely use a JSON array at the root of your response and then you need not worry about either of you questions.
The exploit you link to relies on your API using a Cookie to authenticate a user's session - just use a query string parameter instead and you remove the exploit. It's probably worth doing this anyway since using Cookies for authentication on an API isn't very RESTful - some of your clients may not be web browsers and may not want to deal with cookies.
Why Does this fix work?
The exploit is a form of CSRF attack which relies on the attacker being able to add a script tag on his/her own page to a sensitive resource on your API.
<script src="http://mysite.com/api/columns"></script>
The victims web browser will send all Cookies stored under mysite.com to your server and to your servers this will look like a legitimate request - you will check the session_id cookie (or whatever your server-side framework calls the cookie) and see the user is authenticated. The request will look like this:
GET http://mysite.com/api/columns
Cookie: session_id=123456789;
If you change your API you ignore Cookies and use a session_id query string parameter instead, the attacker will have no way of tricking the victims web browser into sending the session_id to your API.
A valid request will now look like this:
GET http://mysite.com/api/columns?session_id=123456789
If using a JavaScript client to make the above request, you could get the session_id from a cookie. An attacker using JavaScript from another domain will not be able to do this, as you cannot get cookies for other domains (see here).
Now we have fixed the issue and are ignoring session_id cookies, the script tag on the attackers website will still send a similar request with a GET line like this:
GET http://mysite.com/api/columns
But your server will respond with a 403 Forbidden since the GET is missing the required session_id query string parameter.
What if I'm not authenticating users for this API?
If you are not authenticating users, then your data cannot be sensitive and anyone can call the URI. CSRF should be a non-issue since with no authentication, even if you prevent CSRF attacks, an attacker could just call your API server side to get your data and use it in anyway he/she wants.
I would go for 'd' because it clearly separates the 'envelope' of your resource from its content. This would also make it easier for consumers to parse your responses, as opposed to 'guessing' the name of the wrapping property of a given resource before being able to access what it holds.
I think you're talking about two different things:
POST request should be sent in application/x-www-form-urlencoded. Your response should basically mirror a GET if you choose to include a representation of the newly created resource in your reply. (not mandatory in HTTP).
PUTs should definitely be symmetric to GETs. The purpose of a PUT request is to replace an existing resource representation with another. It just makes sense to have both requests share the same conventions, doesn't it?
Go with 'Columns' because it is semantically meaningful. It helps to think of how JSON and XML could mirror each other.
If you would PUT the collection back, you might as well use the same media type (syntax, format, what you will call it.)
I stumbled over a practice that I found to be quite widespread. I even found a web page that gave this a name, but I forgot the name and am not able to find that page on google anymore.
The practice is that every JSON response from a REST service should have the following structure:
{
"status": "ok",
"data": { ... }
}
or in an error case:
{
"status": "error",
"message": "Something went wrong"
}
My question: What is the point why such a "status" property should be required in the JSON? In my opinion that is what HTTP status codes were made for.
REST uses the HTTP means of communication between client and server, for example the "DELETE" verb should be used for deleting. In the same way, 404 should be used if a resource is not found, etc. So inline with that thinking, any error cases should be encoded properly in the HTTP status.
Are there specific reasons to return a HTTP 200 status code in an error case and have the error in the JSON instead? It just seems to make the javascript conditional branches more complex when processing the response.
I found some cases where status could be "redirect" to tell the application to redirect to a certain URL. But if the proper HTTP status code was used, the browser would perform the redirection "for free", maintaining the browsing history properly.
I picture mainly two possible answers from you:
Either there are two quarreling communities with their favorite approach each (use HTTP status always vs. use HTTP status never)
or I am missing an important point and you'll tell me that although the HTTP status should be used for some cases, there are specific cases where a HTTP status does not fit and the "status" JSON property comes into play.
You are right. I think what you are seeing is a side-effect of people not doing REST correctly. Or just not doing REST at all. Using REST is not a pre-requisite for a well-designed application; there is no rule that webapps have to be REST-ful.
On the other hand, for the error condition, sometimes apps want to return a 200 code but an error to represent a business logic failure. The HTTP error codes don't always match the semantics of application business errors.
You are mixing two different Layers here:
HTTP is for establishing (high-level) connections and transferring data. The HTTP status codes thus informs you if and how the connection was established or why it was not. On a successful connection the body of the HTTP request could then contain anything (e.g. XML, JSON, etc.), thus these status code have to define a general meaning. It does not inform you about the correctness or type (e.g. error message or data) of the response.
When using JSON for interchanging data you could certainly omit the status property, however it is easier for you to parse the JSON, if you know if it includes the object you were requesting or an error message by just reading one property.
So, yes, it is perfectly normal to return a 200 status code and have a "status": "error" property in your JSON.
HTTP status codes can be caused by a lot of things, including load balancers, proxies, caches, firewalls, etc. None of these are going to modify your JSON output, unless they completely break it, which can also be treated as an error.
Bottom line: it's more reliable to do it via JSON.