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
Related
We have a REST API to fetch binary files from the server.
The requests look like
GET /documents/e62dd3f6-18b0-4661-92c6-51c7258f9550 HTTP/1.1
Accept: application/octet-stream
For every response indicating an error, we'd like to give a reason in JSON.
The problem is now, that as the response is not of the same content type as the client requested.
But what kind of response should the server produce?
Currently, it responds with a
HTTP / 1.1 406 Not Acceptable
Content-Type: application/json
{
reason: "blabla"
...
}
Which seems wrong to me, as the underlying issue is, that the resource is not existing and not the client requesting the wrong content type.
But the question is, what would be the right way to deal with such situations?
Is it ok, to respond with 404 + application/json although application/octet-stream was requested
Is it ok, to respond with 406 + application/json, as the client did not specify an application/json as an acceptable type
Should spec been extended so that the client should use the q-param - for example, application/octet-stream, application/json;q=0.1
Other options?
If no representation can be found for the requested resource (because it doesn't exist or because the server wishes to "hide" its existence), the server should return 404.
If the client requests a particular representation in the Accept header and the server is not available to provide such representation, the server could either:
Return 406 along with a list of the available representations. (see note** below)
Simply ignore the Accept header and return a default representation of the resource.
See the following quote from the RFC 7231, the document the defines the content and semantics of the HTTP/1.1 protocol:
A request without any Accept header field implies that the user agent will accept any media type in response. If the header field is present in a request and none of the available representations for the response have a media type that is listed as acceptable, the origin server can either honor the header field by sending a 406 (Not Acceptable) response or disregard the header field by treating the response as if it is not subject to content negotiation.
Mozilla also recommends the following regarding 406:
In practice, this error is very rarely used. Instead of responding using this error code, which would be cryptic for the end user and difficult to fix, servers ignore the relevant header and serve an actual page to the user. It is assumed that even if the user won't be completely happy, they will prefer this to an error code.
** Regarding the list of available representations, see this answer.
I have a simple question that I cannot find the answer to.
My colleague is currently making a REST Api for an application, and we have a call that simply checks some information, and returns either true or false. However, we do not know what to call this type of request, as it does not retrive any resources or insert anyhing, it simply checks some information passed into the query. As far as I can understand, a GET has to retrive a resource, which this call isn't doing
What I understand is, resource in this case is either true or false. While calling the API you will expect response either true or false on the basis of information processed by API server (status will be always 200). So a GET method is still suitable for this case.
If you are not interested in response body and you want data like response code and header details, go with HEAD.
There might be a different way to express 'checking some information', and it's important to be a bit more specific as to what that means.
So lets take an arbitrary example. You're modelling blog posts and want to know if some blog post is set to 'draft'.
The 'draft' status can be its own resource, for example:
/posts/hello-world/is-draft
Doing a GET request on the is-draft resource can yield:
{
"is-draft": true
}
So to model arbitrary things as resources, the best way to think about this is to look at the result of the operation as the 'representation' and the 'thing you want to know' as the URI.
As far as I can understand, a GET has to retrive a resource, which this call isn't doing
Technically, it is retrieving a resource; see Fielding
The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (e.g. "today's weather in Los Angeles"), a collection of other resources, a non-virtual object (e.g. a person), and so on. In other words, any concept that might be the target of an author's hypertext reference must fit within the definition of a resource.
The resource, in this case, might not load an entity in your data model, but that's OK. Not all resources have to.
Technically, I think what you have there is a "function"; all of the information that you need to compute the result is present within the URI itself? Which would mean that, if the client knew how to do the computation (and had the compute resources available), then the client would be capable of doing the work for itself.
But there's nothing wrong with having a resource that is "the result of a function".
In some API, you'll see predicates (functions that return true/false) implemented as resources that only exist (more precisely, only have "representations") if the evaluation is true.
GET /predicate?true
204 No Content
GET /predicate?false
404 Not Found
The fact that you don't need to consider the resources "state" to compute the correct response to the query is an implementation detail hidden behind the uniform interface.
It's hard to tell by the level of details you provided your question. But if you need to check whether a resource exists or not, you can use HEAD. It's identical to GET, but it doesn't return a representation in the response payload: it returns just the status code and the response headers.
Consider the following request HEAD request:
HEAD /postal-codes/10001 HTTP/1.1
Host: example.org
Content-Type: application/json
It should return 200 for a resource that exists:
HTTP/1.1 200 OK
Content-Type: application/json
And 404 for a resource that doesn't exists:
HTTP/1.1 404 Not Found
Content-Type: application/json
Depending on your needs, you could address it with POST, which can be seen as a catch all verb.
For example, consider the following request and responses:
POST /postal-codes/validation HTTP/1.1
Host: example.org
Content-Type: application/json
{ "postal-code": "10001" }
HTTP/1.1 200 OK
Content-Type: application/json
{ "postal-code": "10001", "status": "valid" }
HTTP/1.1 200 OK
Content-Type: application/json
{ "postal-code": "10001", "status": "invalid" }
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
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.
Given the service:
> GET /hotel
< HTTP/1.1 200 OK
< <hotel>
< <a>aaa</a>
< <b>aaa</b>
> <c>aaa</c>
< </hotel>
Should one reference a DTD in the XML returned from the server?
Would this better allow a client to validate the response?
Considering the markup you have chosen appears to be custom to your requirements then I would expect to see a media-type such as
application/vnd.yourcompany.hotel+xml
in your content-type HTTP header. Based on this content-type, the client will know whether it has the knowledge to process this representation.
The media-type header can help your client know what kind of document to use. It can also help you version the service by having different document types for each version.
application/vnd.yourcompany.hotelv1+xml
application/vnd.yourcompany.hotelv2+xml
etc.
The client can also specify which kind of document it would like back in the Accepts header.
It's certainly good practice to reference your DTD/schema, and yes, it will allow clients to validate the response, if they choose to. They often won't.