It is a trivial question but I cannot find an answer. Lets say I have an endpoint that simply checks if a user exists within a certain group and returns a boolean. What should the RestAPI path look like?
/api/user/{id}/exists/{group}
/api/user/{id}/in/{group}
/api/user/{id}/is_assigned/{group}
/api/user/{id}/exists_within/{group}
I feel like the API path name should read organically, but I also don't like using an underscore. What do you guys suggest?
REST doesn't care what spellings you use for your identifiers.
PUT /abff1822-71aa-4147-9b91-18a8a4f1bf6c
Content-Type: application/json
true
PUT /abff1822-71aa-4147-9b91-18a8a4f1bf6c
Content-Type: application/json
false
GET /abff1822-71aa-4147-9b91-18a8a4f1bf6c
Old school POST also "just works"
POST /abff1822-71aa-4147-9b91-18a8a4f1bf6c
Content-Type:application/x-www-form-urlencoded
value=true
URI are a lot like variable names - the machines don't care, and because they don't care you can follow whatever local spelling conventions make sense.
Related
Is there a standard to where and how to expose the schema of API endpoints?
For example, let's say the following API endpoints are available:
api/companies/
api/companies/{id}/employees/
Where should the schema for the company and employee resources be exposed?
api/company-schema.json and api/employee-schema.json?
api/schemas/company.json and api/schemas/employee.json?
You can setup your schema endpoints any way you like, but you should use one of the recommended correlation methods. The idea is that there is no universal rule for accessing schemas. Instead, the resource itself identifies the schema that describes it.
So, feel free to expose your schemas any way you like. And then feel free to change it if you need to without fear of breaking client implementations. Just change your response headers to point to the new schema and clients should be able to handle the change dynamically.
The most straightforward correlation method is to include a describedby Link header.
HTTP/1.1 200 OK
Content-Type: application/json
Link: </schema/companies>; rel="describedby"
{ ... }
The other option is to use the schema content-type parameter. (Note: Previous versions of JSON Schema used profile instead of schema).
HTTP/1.1 200 OK
Content-Type: application/json; schema="/schema/companies"
{ ... }
However, the schema parameter is not actually defined for the application/json media-type, so there are potential interoperability issues with that method. That's one reason why the application/schema-instance+json media type was introduced. It works just like application/json, but defines a few capabilities that the normal JSON media-type doesn't.
HTTP/1.1 200 OK
Content-Type: application/schema-instance+json; schema="/schema/companies"
{ ... }
EDIT 2020/24/01: Fix broken link and update answer to reflect changes in recent drafts.
Why not expose it on where it is called?
For example
schema/companies
schema/companies/10/employees
Change the api to schema
I'm going with the Link header with these as the urls
/api/companies.schema
/api/companies/{id}/employees.schema
I am designing a REST API and am running into a design issue. I have alerts that I'd like the user to be able to export to one of a handful of file formats. So we're already getting into actions/commands with export, which feels like RPC and not REST.
Moreover, I don't want to assume a default file format. Instead, I'd like to require it to be provided. I don't know how to design the API to do that, and I also don't know what response code to return if the required parameter isn't provided.
So here's my first crack at it:
POST /api/alerts/export?format=csv
OR
POST /api/alerts/export/csv
Is this endpoint set up the way you would? And is it set up in the right way to require the file format? And if the required file format isn't provided, what's the correct status code to return?
Thanks.
In fact you should consider HTTP content negotiation (or CONNEG) to do this. This leverages the Accept header (see the HTTP specification: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1) that specifies which is the expected media type for the response.
For example, for CSV, you could have something like that:
GET /api/alerts
Accept: text/csv
If you want to specify additional hints (file name, ...), the server could return the Content-Disposition header (see the HTTP specification: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1) in the response, as described below:
GET /api/alerts
Accept: text/csv
HTTP/1.1 200 OK
Content-Disposition: attachment; filename="alerts.csv"
(...)
Hope it helps you,
Thierry
If I have very simple data to send to the server, is it okay to set up a URI scheme where all of it can be sent on the URI instead of in the body? For example, suppose I'm setting user preferences. I envision something like this:
PUT
/preferences/{setting-name}/{setting-value}
This allows my client code to be very simple because I can put the entirety of the message in the URI. Is that okay? Or should I be doing something more like:
PUT
/preferences/{setting-name}
...with the value in the content? Thanks!
Your first URI implies that ther is a (sub-)resource at
/preferences/{setting-name}/{setting-value}
But there is not resource, only a value. Using such an URI is not RESTful since it does not address a resource.
Your second URI is slightly better since it addresses a subresource {setting-name} of the preferences resource.
But I would prefer a third approach:
POST /preferences
Content-Type: application/json
{
"setting-name": "setting-value",
}
to put one preference. Note the usage of POST instead of PUT. PUT is generally interpreted as containing a complete representation of the resource in the request body. Such a request should overwrite all settings. Using POST is generally interpreted as overwriting only the setting specified in the body. Other settings are meant to be unchanged.
Note:
What makes me wonder is the front of your URI. Is there really only one set of preferences? Can and should all clients access the same set of preferences? If, for example, the preferences are user-based, you should use URIs like
/user/{user-id}/preferences/{setting-name}
to access the {setting-name} preference value of user {user-id}.
I've read through RFC 2617 and can't find there or anywhere else what the delimiter is if multiple schemes are supported. For example, suppose both Basic and Digest are supported. I understand that it may appear this way:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic
WWW-Authenticate: Digest
But I've also read that both can be listed as one line, but no one ever shows an example or describes what delimiter to use. I've seen cautions that commas can be used within a single scheme:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Digest param1="foo", param2="bar"
I've also read that if commas are used within a scheme, that other schemes must be placed on separate lines. So I imagine in the above case if we added Basic it would appear like this:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Digest param1="foo", param2="bar"
WWW-Authenticate: Basic
That's simple enough. But now suppose you just have one line
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Scheme stuff, morestuff, more stuff
Which is that? Is that a comma-delimited list of schemes, or is that one scheme, with a few parameters?
As far as I can tell, the spec punts on the issue. Section 1.2 states:
Note: User agents will need to take special care in parsing the WWW-
Authenticate or Proxy-Authenticate header field value if it contains
more than one challenge, or if more than one WWW-Authenticate header
field is provided, since the contents of a challenge may itself
contain a comma-separated list of authentication parameters.
I think we can translate special care to best of luck chap.
Pragmatism
As a practical matter, I suspect multiple schemes means one should use multiple wwww-authenticate headers. Schemes are extensible; e.g., I can come up with a scheme called "strawberry" or "opaque" if I want to be sinister. Given this, there isn't really a good way to parse a one liner without some sort of 'scheme termination' delimiter.
W3C Discussion
You aren't the first person with this question. There was a discussion on the W3C mailing list. The poster stated :
I wasn't questioning the need to provide multiple challenges in a
single response. I was only questioning the wisdom in allowing
multiple challenges in a single header field, given the odd
combination of separators it creates.
Some other threads discussing current issues & future action that may be of interest:
root of above thread
Backwards definition of authentication header
#342 WWW-Authenticate ABNF slightly ambiguous
WWW-Authenticate ABNF is ambiguous
future http 2 - Multi-legged Authentication for HTTP Multiplexing
If only ...
Not that I have the stomach for it, but one could dig through the chromimum, firefox & webkit code to see how those communities have handled the issue.
Every single resource I'va come across on Internet always describes very well what you can do with the GET operation, how it works and so on, bu it never explains the POST/PUT/DELETE and particularly the format of the data you pass in the HTTP body (I'm using JSON). It always says "you can make a post request and pass the appropriate data in the body".
I am struggling with what I can do and not. For example I want to know if it is possible to update one field of one entry by just sending the updated value, and not the entire object.
Is there any document that explains clearly the possibilities and limitations?
Thanks a lot.
Easy to read documentation is here: http://www.odata.org/developers/protocols
If you want all the dirty details and a strict language you can read this document: http://msdn.microsoft.com/en-us/library/dd541188(PROT.10).aspx
You can modify a value of a single property by sending a PUT request.
For example if you send a GET to this URL:
http://services.odata.org/(S(kupqbta5wqnfz2cln1qk052x))/OData/OData.svc/Products(0)/Name
And you request JSON (through an Accept header) the response will be:
{
"d" : {
"Name": "Bread"
}
}
The "d" wrapper is there only to avoid XSS attacks so that must not be included in the requests, but the rest stays the same, so if you then send a PUT request like this:
PUT http://services.odata.org/(S(kupqbta5wqnfz2cln1qk052x))/OData/OData.svc/Products(0)/Name HTTP/1.1
Host: services.odata.org
Content-Type: application/json
Content-Length: 20
{
"Name": "Meat"
}
It will update the property Name to value Meat. You can also send a PUT to the value itself, in which case the URL would end with $value (denotes the raw value of the property) like this:
PUT http://services.odata.org/(S(kupqbta5wqnfz2cln1qk052x))/OData/OData.svc/Products(0)/Name/$value HTTP/1.1
Host: services.odata.org
Content-Type: text/plain
Content-Length: 4
Meat
Note that this only works on primitive properties though.
The sample service on the odata.org allows you to make modifications (guarded by the session key in the URL), so can play with it there.
Google for the HTTP 1.1 specification.