I'm designing RESTful API for trip planner application and don't know how to enforce foreign key constraint on resource creation. I have two resources: Trip and User. Trip resource looks like this:
{
"id": 1,
//some other attributes
"tripParticipants":[
{
"id": 1
}
]
}
where tripParticipants is collection of User ids. TripParticipants should only contain created Users (by created I mean stored in database).
I have trouble with endpoint POST /trips/{id}/tripParticipants to add elements to the collection.
What should I return when User with given id doesn't exist in my database? Returning HTTP 404 status code for POST operation looks weird. Does REST standard defines some solutions to this use case?
There are two HTTP status codes that can be used in this situation:
422 Unprocessable entity
409 Conflict
Both are correct for your scenario. Personally I'd go with 422.
For Rest you follow the Http standard status codes, so 404 is the appropriate code for Rest.
These are the status codes you could be using https://www.restapitutorial.com/httpstatuscodes.html
Related
I want to know how to design a RESTFUL api for creating a resource and its related resources at once.
For example, I want to create an order which contains a list of items using my RESTFUL API, for example:
{
order_id:1,
description: "XXX",
items: [
{item_id:1, price:30, ...},
{item_id:2, price:40, ...}
]
}
One way is giving two api
post: api/orders => create a new order and return the order id
post: api/orders/id/items => create related items using the order_id
However, the order and items should be created together. So if the second api failed, it will create an order without any item inside and it is the situation I don't want to see. Actually, I want the backend server to do a transaction and create the order and items at once, it should be succeeded or failed together.
So, is it a good way to put the items in the body of request, and post only once to api/orders ? Or is there other better design for this situation?
Thank you!
I want to know how to design a RESTFUL api for creating a resource and its related resources at once.
Perfectly reasonable thing to do. Concentrate your attention on how to describe to the client how to create the appropriate request, and how to interpret the document describing the result.
The clue is in the definition of the 201 Created status code
The 201 (Created) status code indicates that the request has been fulfilled and has resulted in one or more new resources being created.
The 201 response payload typically describes and links to the resource(s) created.
(emphasis added)
In the case of the web, the way we would do this is to have a form; the client would provide information in the form and submit it. The browser, following the standard for form processing, would generate a POST (because the semantics are unsafe) request with the form data encoded within the message body and the appropriate content type defined in the header (for instance application/x-www-form-urlencoded).
The response, in term, would be an HTML document with a bunch of links to all of the interesting resources that were created.
Does it have to be HTML? No, of course not - you could use text/plain if it suited your needs. You have somewhat better long term prospects when using a media type that has built into it a notion of links that general purpose components will understand.
Definitely, creating order without items - bad idea. This will ends up with not solid API and not consistent entities. Also, you can't create items using api/orders URI, because this violates the basis of the REST principles.
For your business logic REST API may looks like:
POST api/item
{
price: 40,
name: "xxx",
...
}
<<<<< 201
{
id: 1
}
GET api/item/{id}
<<<<< 200
{
id: 4,
price: 40,
name: "xxx",
...
}
POST api/order
{
description: "xxx",
items: [
{id: 1, count: 5},
{id: 23456, count: 1}
]
}
<<<<< 201
{
id: 123442
}
I think it's unnecessary to put full items in creating order request body. Item ID's will be enough to create order-item bindings on backend.
So I have some resources in my API with foreign key relationships and these fk records (by design) cannot be created unless a POST is made to that specific resource first.
I cannot create a Country by POSTing to Wine even though Country is a foreign key.
the POST is going to /api/wine not /api/country
In other words, if I send this payload to Wine resource:
{
id: 79,
name: "Bordeaux",
country: {
id: 76,
code: "FR",
name: "France"
},
year: "2005"
}
It will fail unless that country already exists. We cannot create the country from this POST because we are POSTing to the Wine resource and not Country.
This was by design because there are other foreign key relationships in the API that the consumer should never be able to modify or create. Furthermore, letting the consumer create multiple resources from a single payload seems like it would open up the possibility of introducing typo's, duplicate records, and dirtying the data, especially as the API scales and people are writing scripts around it and getting familiar with pushing data into it.
If I have a GET endpoint that reflects a chain of foreign key relationships
/api/planet/country/state/city/postal_code/
and I make a POST to:
/api/postal_code/
I should not be able to create a planet, country, state or city, I should only be able to refer to existing records for these resources if they exist and then finally create a new postal code.
My question is simply, what is the standard practice for this? Which methodology is more commonly used. If I were to open up my API to support creating every foreign key resource from a single endpoint - it seems like it would remove some of the benefits of using foreign key relationships in the first place.
The way you have it is RESTful. To create a wine row, you do need to know all of the relevant details for that wine.
Nested routes are good when you have a use case to see all wine, versus wine just from a specific company.
Namely:
GET /api/wine/ <-- Would return all wine in the database
vs.
GET /api/countries/76/wine <-- Would return all wine just for France.
Otherwise, both ways are RESTful in that the route describes the resource, and the patterns for updating it remain the same.
Creating a parent resource when a new create child-resource api is called is not RESTful. If the parent-resource has to exist in order to create a child resource, the best way is to follow the hierarchical api structure and throw exceptions if the referred parent resource is not found.
Hierarchical API structure :
/api/countries/$country_id/wines - POST
If you follow this structure the api consumers will know that these parent resources must exist for the client apis to work properly.
On the other hand, if you feel that the api becomes lengthier, you can just throw exceptions when the parent resource(country) does not exist.
I have a situation where in my PostgreSQL database I have a user table with this row:
{
id: 1
name: 'unique name here'
}
where id is a primary key and name has a unique constraint.
If I were to do a PUT /users/2 request to the server connected to this DB and with a request payload below:
{
name: 'unique name here'
}
that has the same name, it would delete the row with id of 1 and create the row with id of 2 using an upsert function.
Using RESTful architecture, is this proper or should the database be left alone and the server return a status code like 409 indicating that the request could not be completed due to a conflict with the current state of the target resource.
As far as RESTfulness is concerned, there's nothing to prohibit PUT from overwriting existing data and/or having side effects (as long as it's idempotent of course), and implementation details about the underlying data are outside the scope of REST, so in that sense, either solution you proposed is fine.
However, deleting the old one and creating a new one with a new primary key feels like a strange implementation to me. Remember, following the guidelines of RESTful design does not guarantee that you'll end up with a sensible implementation of your server application! That's up to you.
Of course without knowing the details of your application it's impossible to say for sure what the best way is, but I think I'd lean towards disallowing this request - let the client do a PUT to the correct URI.
A word about the status code though: it wasn't clear from your question if users/2 already exists in this example. As you say, a 409 indicates a conflict with the current state of the resource, so it's not appropriate for rejecting a request to create a new resource.
I think I'd use either a 400 Bad Request or a 403 Forbidden in that case.
say we have a 'user' resource with unique constraint on 'name'. how would you design a REST API to handle a find-or-create (by name) use case? I see the following options:
option 1: multiple requests
client:
POST /user
{"name":"bob"}
server:
HTTP 409 //or something else
client:
GET /user?name=bob
server:
HTTP 200 //returns existing user
option 2: one request, two response codes
client:
POST /user
{"name":"bob"}
server:
HTTP 200 //returns existing user
(in case user is actually created, return HTTP 201 instead)
option 3: request errs but response data contains conflicting entity
client:
POST /user
{"name":"bob"}
server:
HTTP 409 //as in option1, since no CREATE took place
{"id": 1, "name":"bob"} //existing user returned
I believe the "correct" RESTful way to do this would be :
GET /user?name=bob
200: entity contains user
404: entity does not exist, so
POST /user { "name" : "bob" }
303: GET /user?name=bob
200: entity contains user
I'm also a big fan of the Post-Redirect-Get pattern, which would entail the server sending a redirect to the client with the uri of the newly created user. Your response in the POST case would then have the entity in its body with a status code of 200.
This does mean either 1 or 3 round-trips to the server. The big advantage of PRG is protecting the client from rePOSTing when a page reload occurs, but you should read more about it to decide if it's right for you.
If this is too much back-and-forth with the server, you can do option 2. This is not strictly RESTful by my reading of https://www.rfc-editor.org/rfc/rfc2616#section-9.5:
The action performed by the POST method might not result in a resource
that can be identified by a URI. In this case, either 200 (OK) or 204
(No Content) is the appropriate response status, depending on whether
or not the response includes an entity that describes the result.
If you're okay with veering away from the standard, and you're concerned about round-trips, then Option 2 is reasonable.
I am using a version of option 2. I return 201 when the resource is created, and 303 ("see other") when it is merely retrieved. I chose to do this, in part, because get_or_create doesn't seem to be a common REST idiom, and 303 is a slightly unusual response code.
I would go with Option 2 for two reasons:
First, HTTP response code, 2xx (e.g. 200 nd 201) refers to a successful operation unlike 4xx. So in both cases when find or create occurs you have a successful operation.
Second, Option 1 doubles the number of requests to the server which can be a performance hit for heavy load.
I believe a GET request which either:
returns an existing record; or
creates a new record and returns it
is the most efficient approach as discussed in my answer here: Creating user record / profile for first time sign in
It is irrelevant that the server needs to create the record before returning it in the response as explained by #Cormac Mulhall and #Blake Mitchell in REST Lazy Reference Create GET or POST?
This is also explained in Section 9.1.1 of the HTTP specification:
Naturally, it is not possible to ensure that the server does not generate side-effects as a result of performing a GET request; in fact, some dynamic resources consider that a feature. The important distinction here is that the user did not request the side-effects, so therefore cannot be held accountable for them.
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.