My understanding of REST is that a resource endpoint should expose the same schema, irrespective of the HTTP VERB. E.g. the same JSON schema is used for:
PUT /foo/
GET /foo/{id}
POST /foo/{id}
How do I handle fields that should only be populated by the server. E.g. created_on, created_by, id.
Should I use separate schema per endpoint?
Do nothing and ignore the created_on value if it's sent by the client?
Return an error if the client tries to send created_on?
My understanding of REST is that a resource endpoint should expose the same schema, irrespective of the HTTP VERB.
That's not quite right. We would normally expect GET and PUT to use similar representations. POST can use the same representations, but frequently doesn't.
For example: on the web we GET HTML documents, but we POST key/value pairs (application/x-www-form-urlencoded).
How do I handle fields that should only be populated by the server. E.g. created_on, created_by, id.
Treat them as optional fields in your schema is the common answer, I think.
Also, keep in mind that the server is not constrained by the semantics of the request. PUT means "make the resource look like the body of the request", but it is perfectly reasonable for the server to make changes of its own to the resource.
Do nothing and ignore the created_on value if it's sent by the client?
Just so.
You need to be a little bit careful not to imply that you've accepted the provided representation as is, see RFC 7231.
Related
As an example I have an order where the invoicing address can be modified. The change might trigger various additional actions (i.e. create a cancellation invoice and a new invoice with the updated address).
As recommended by various sources (see below) I don't want to have a PATCH on the order resource, because it has many other properties, but want to expose a dedicated endpoint, also called "intent" resource or subresource according to the web links below:
/orders/{orderId}/invoicing-address
Should I use a POST or a PATCH against this subresource?
The invoicing address itself has no ID. In the domain layer it is represented as a value object that is part of the order entity.
What ETag should be used for the subresource?
The address is part of the order and together with the items they form an aggregate in the domain layer. When the aggregate is updated it gets a new version number in the database. That version number is used as an ETag for optimistic locking.
Should a GET on invoicing-address respond with the order aggregate version number or a hash value of the address DTO in the ETag header?
What payload should be returned after updating the address?
Since the resource is the invoicing address it seems natural to return the updated address object (maybe with server side added fields). Should the body also include the ID/URI and the ETag of the order resource?
None of the examples I found with subresources showed any server responses or considered optimistic locking.
https://rclayton.silvrback.com/case-against-generic-use-of-patch-and-put
https://www.thoughtworks.com/insights/blog/rest-api-design-resource-modeling
https://softwareengineering.stackexchange.com/questions/371273/design-update-properties-on-an-entity-in-a-restful-resource-based-api (see provided answer)
https://www.youtube.com/watch?v=aQVSzMV8DWc&t=188s (Jim Webber at about about 31 mins)
As far as REST is concerned, "subresources" aren't a thing. /orders/12345/invoicing-address identifies a resource. The fact that this resource has a relationship with another resource identified by /orders/12345 is irrelevant.
Thus, the invoicing-address resource should understand HTTP methods exactly the same way as every other resource on the web.
Should I use a POST or a PATCH against this subresource?
Use PUT/PATCH if you are proposing a direct change to the representation of the resource. For example, these are the HTTP methods we would use if we were trying to fix a spelling error in an HTML document (PUT if we were sending a complete copy of the HTML document; PATCH if we were sending a diff).
PUT /orders/12345/invoicing-address
Content-Type: text/plain
1060 W Addison St.
Chicago, IL
60613
On the other hand, if you are proposing an indirect change to the representation of the resource (the request shows some information to the server, and the server is expected to compute a new representation itself)... well, we don't have a standardized method that means exactly that; therefore, we use POST
POST serves many useful purposes in HTTP, including the general purpose of “this action isn’t worth standardizing.” -- Fielding, 2009
What ETag should be used for the subresource?
You should first give some thought to whether you want to use a strong-validator or a weak validator
A strong validator is representation metadata that changes value whenever a change occurs to the representation data that would be observable in the content of a 200 (OK) response to GET.
...
In contrast, a weak validator is representation metadata that might
not change for every change to the representation data.
...
a weak entity-tag ought to change whenever the origin server wants caches to invalidate old responses.
I might use a weak validator if the representation included volatile but insignificant information; I don't need clients to refresh their copy of a document because it doesn't have the latest timestamp metadata. But I probably wouldn't use an "aggregate version number" if I expected the aggregate to be changing more frequently than the invoicing-address itself changes.
What payload should be returned after updating the address?
See 200 OK.
In the case of a POST request, sending the current representation of the resource (after changes have been made to it) is nice because the response is cacheable (assuming you include the appropriate metadata signals in the response headers).
Responses to PATCH have similar rules to POST (see RFC 5789).
PUT is the odd man out, here
Responses to the PUT method are not cacheable.
Should the body also include the ID/URI and the ETag of the order resource?
Entirely up to you - HTTP components aren't going to be paying attention to the representation, so you can design that representation as makes sense to you. On the web, it's perfectly normal to return HTML documents with links to other HTML documents.
We are exposing an endpoint that will return a large data set. There is a background process which runs once per hour and generates the data. The data will be different after each run.
The requester can ask for either the full set of data or a subset. The sub set is determined via a set of parameters but the parameters are too long to fit into a uri which has a max length of 2,083 characters. https://www.google.co.uk/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=uri%20max%20length
The parameters can easily be sent in the request body but which which is the correct HTTP verb to use?
GET would be ideal but use of a body 'has no semantic meaning to a GET request' HTTP GET with request body
PUT is not appropriate because there is no ID and no data is being updated or replaced.
POST is not appropriate because a new resource is not being replaced and more importantly the server is not generating and Id.
http://www.restapitutorial.com/lessons/httpmethods.html
GET (read) would seem to be the most appropriate but how can we include the complex set of parameters to determine the response?
Many thanks
John
POST is the correct method. POST should be used for any operation that's not standardized by HTTP, which is your case, since there's no standard for a GET operation with a body. The reference you linked is just directly mapping HTTP methods to CRUD, which is a REST anti-pattern.
You are right that GET with body is to be avoided. You can experiment with other safe methods that take a request body (such as REPORT or SEARCH), or you can indeed use POST. I see no reason why the latter is wrong; what you're citing is just an opinion, not the spec.
Assuming that the queries against that big dataset are not totally random, you should consider adding stored queries to your API. This way clients can add, remove, update queries (through request body) using POST DELETE PUT. Maybe you can call them "reports".
This way the GET requests need only a reference as query parameter to these queries/reports, you don't have to send all the details with every requests.
But only if not all the requests from clients are unique.
When designing a RESTful API, what to do if a GET request only makes sense if there are specific parameters associated with the request? Should the parameters be passed as a query string, and if so, what to do when all the parameters aren't specified or are formatted incorrectly?
For example, lets say i have a Post resource, which can be accessed by `api/posts` endpoint. Each post has a geographical location, and posts can be retrieved ONLY when specifying an area that the posts may reside in. Thus, 3 parameters are required: latitude, longitude and radius.
I can think of 2 options in this case:
1. Putting the parameters in query string: api/posts/?lat=5.54158&lng=71.5486&radius=10
2. Putting the parameters in the URL: api/posts/lat/5.54158/lng/71.5486/radius/10
Which of these would be the correct approach? It seems wrong to put required parameters in the query string, but the latter approach feels somewhat 'uglier'.
PS. I'm aware there are many discussion on this topic already (for example: REST API Best practices: Where to put parameters?), but my question is specifically addressed to the case when parameters are required, not optional.
The first approach is better.
api/posts/?lat=5.54158&lng=71.5486&radius=10
The second approach is a little misleading.
api/posts/lat/5.54158/lng/71.5486/radius/10
You should think of each of your directories as resources. In this cause, sub-resources (for example: "api/posts/lat/5.54158") are not really resources and thus misleading. There are cases where this pattern is a better solution, but looking at what's given, I'd go with using the query string. Unless you have some entity linking to link you directly to this URL, I don't really like it.
You should put everything in the query string and set the server to return an error code when not receiving the 3 required parameters.
Because it's a group of parameter that identify an object.
Taking the example:
lat=5.54158; lng=71.5486 radius=10
It would be very unlikely to this url make sense:
api/posts/lat/5.54158/lng/yyyy/radius/zz
It's different than:
api/memb/35/..
because the member with id 35 can have a lot of functions ( so, valid urls ) as:
api/memb/35/status or
api/memb/35/lastlogin
When designing a RESTful API, what to do if a GET request only makes
sense if there are specific parameters associated with the request?
Should the parameters be passed as a query string, and if so, what to
do when all the parameters aren't specified or are formatted
incorrectly?
By REST your API must fulfill the REST constraints, which are described in the Fielding dissertation. One of these constraints is the uniform interface constraint, which includes the HATEOAS constraint. According to the HATEOAS constraint your API must serve a standard hypermedia format as response. This hypermedia contains hyperlinks (e.g. HTML links, forms) annotated with metadata (e.g. link relation or RDF annotation). The clients check the metadata, which explains to them what the hyperlink does. After that they can decide whether they want to follow the link or not. When they follow the link, they can build the HTTP request based on the URI template, parameters, etc... and send it to the REST service.
In your case it does not matter which URI structure you use, it is for service usage only, since the client always uses the given URI template and the client does not care what is in that template until it is a valid URI template which it can fill with parameters.
In most of the cases your client has enough validation information to test whether the params are incorrect or missing. In that case it does not send a HTTP request, so you have nothing to do in the service. If an invalid param gets through, then in your case your service sends back a 404 - not found, since the URI is the resource identifier, and no resource belongs to an invalid URI (generated from the given URI template and invalid params).
According to the HTTP 1.1. spec:
If the Request-URI does not point to an existing resource, and that
URI is capable of being defined as a new resource by the requesting
user agent, the origin server can create the resource with that URI.
So in other words, PUT can be used to create & update. More specifically, if I do a PUT request e.g.
PUT /users/1
and that user does not exist, I would expect the result of this request to create a user with this ID. However, how would this work if your backend is using an auto-increment key? Would it be a case of simply ignoring it if it's not feasible (e.g. auto-increment is at 6 and I request 10) & creating if it is possible (e.g. request 7)?
From the snippet I have extracted above it does appear to give you this flexibility, just looking for some clarification.
I'd suggest that you use POST, not PUT, for an auto-increment key, or do not use the auto-increment key in the resource ID.
If you use POST, then you'd POST to /users rather than to /users/1. The reply might redirect you to /users/1 or whatever the ID is.
If you use PUT, then you might PUT to /users/10292829 where the number is a unique resource key generated on the client. This key can be time-generated, or it can be a hash of time, session ID, and some other factors to guarantee uniqueness of the value across your client audience. The server can then generate its own auto-incremented index, distinct from 10292829 or whatever.
For more on that, see PUT vs POST in REST
Following up. . .
In the case of allowing PUT to /users/XXXXXXX, for all users, you'd end up with two distinct unique keys that refer to the same resource. (10292829 and 1 might refer to the same user). You'd need to decide how to allow the use of each of these different keys in a REST-style URL. Because of the need to reconcile the use of these two distinct ids, I'd prefer to use the first option, POSTing to /users and getting a unique REST url of the created resource in the response.
I just re-read the relevant section of RFC 2616, and saw a return code specifically designed for this in REST applications:
10.2.2 201 Created
The request has been fulfilled and resulted in a new resource being created. The newly created resource can be referenced by the URI(s) returned in the entity of the response, with the most specific URI for the resource given by a Location header field. The response SHOULD include an entity containing a list of resource characteristics and location(s) from which the user or user agent can choose the one most appropriate. The entity format is specified by the media type given in the Content-Type header field. The origin server MUST create the resource before returning the 201 status code. If the action cannot be carried out immediately, the server SHOULD respond with 202 (Accepted) response instead.
So, the RESTful way to go is to POST to /users and return a 201 Created, with a Location: header specifying /users/1.
You should be using POST to create resources while the PUT should only be used for updating. Actually REST semantics forces you to do so.
I'm building a collection of RESTful resources that work like the following: (I'll use "people" as an example):
GET /people/{key}
- returns a person object (JSON)
GET /people?first_name=Bob
- returns a list of person objects who's "first_name" is "Bob" (JSON)
PUT /people/{key}
- expects a person object in the payload (JSON), updates the person in the
datastore with the {key} found in the URL parameter to match the payload.
If it is a new object, the client specifies the key of the new object.
I feel pretty comfortable with the design so far (although any input/criticism is welcome).
I'd also like to be able to PUT a list of people, however I'm not confident in the RESTfulness of my design. This is what I have in mind:
PUT /people
- expects a list of objects in JSON form with keys included in the object
("key":"32948"). Updates all of the corresponding objects in the datastore.
This operation will be idempotent, so I'd like to use "PUT". However its breaking a rule because a GET request to this same resource will not return the equivalent of what the client just PUT, but would rather return all "people" objects (since there would be no filters on the query). I suspect there are also a few other rules that might be being broken here.
Someone mentioned the use of a "PATCH" request in an earlier question that I had: REST resource with a List property
"PATCH" sounds fantastic, but I don't want to use it because its not in wide use yet and is not compatible with a lot of programs and APIs yet.
I'd prefer not to use POST because POST implies that the request is not idempotent.
Does anyone have any comments / suggestions?
Follow-up:::
While I hesitated to use POST because it seems to be the least-common-denominator, catch-all for RESTful operations and more can be said about this operation (specifically that it is idempotent), PUT cannot be used because its requirements are too narrow. Specifically: the resource is not being completely re-written and the equivalent resource is not being sent back from a GET request to the same resource. Using a PUT with properties outside of it's specifications can cause problems when applications, api's, and/or programmers attempt to work with the resource and are met with unexpected behavior from the resource.
In addition to the accepted answer, Darrel Miller had an excellent suggestion if the operation absolutely had to be a PUT and that was to append a UUID onto the end of the resource path so an equivalent GET request will return the equivalent resource.
POST indicates a generic action other than GET, PUT, and DELETE (the generic hashtable actions). Because the generic hashtable actions are inappropriate, use POST. The semantics of POST are determined by the resource to which an entity is POSTed. This is unlike the semantics of the generic hashtable methods, which are well-known.
POST /people/add-many HTTP/1.1
Host: example.com
Content-Type: application/json
[
{ "name": "Bob" },
{ "name": "Robert" }
]
Using PUT is definitely the wrong verb in this case. POST is meant to do exactly what you are asking. From the HTTP specification:
The fundamental difference between the POST and PUT requests is reflected in the different meaning of the Request-URI. The URI in a POST request identifies the resource that will handle the enclosed entity. That resource might be a data-accepting process, a gateway to some other protocol, or a separate entity that accepts annotations. In contrast, the URI in a PUT request identifies the entity enclosed with the request -- the user agent knows what URI is intended and the server MUST NOT attempt to apply the request to some other resource...
As such, if you want to update multiple resources in a single call, you have to use POST.
Just be cause PUT is required to be idempotent and POST is not, does not mean that POST cannot be idempotent. Your choice of HTTP verb should not be based on that, but based on the relationship of the requested resource and the resource acted upon. If your application is directly handling the resource requested, use PUT. If it is acting on some other resource (or resources, as in your case), use POST.
I really don't see any easy way you could use PUT to create an arbitrary set of people. Unless, you are prepared to have the client generate a GUID and do something like,
PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
On the server side you could take the people from the list and add them to the /People resource.
A slight variation to this approach would be to get the server to include a link such as
<link rel="AddList" href="/PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}"/>
in the People resource. The client would need to know that it needs to PUT a list of people to the AddList link. The server would need to make sure that each time it renders the /People resource it creates a new url for the AddList link.
Regarding Darren Miller's suggestion of using PUT to a GUID (I can't comment...), the point of using PUT would be to achieve idempotency for the operation. The litmus test if idempotency would be this conversation between the client and server:
PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
204 NO CONTENT (indicates that it all went well)
client loses connection and doesn't see the 204
client automatically retries
PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
How would the server differentiate the two? If the GUID is "used up" so to speak then the server would have to respond 404 or 410. This introduces a tiny bit of conversational state on the server to remember all the GUIDs that have been used.
Two clients would often see the same I guess, because of caching or simply keeping stale responses around.
I think a smart solution is to use POST to create an (initially empty, short lived) holding area for a resource to which you can PUT, i.e. clients need to POST to create the GUID resource instead of discovering it via a link:
POST /PeopleList/CreateHoldingArea
201 CREATED and Location: /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
This would mean that the lost idempotency would not result in much overhead; clients simply create new GUIDs (by POSTing) if they didn't see the initial 201 CREATED response. The "tiny bit of conversational state" would now only be the created but not yet used holding areas.
The ideal solution would of course not require any conversational state on the server, but it eludes me.