How do I name API endpoints that serve the same entity in different ways and still adhere to the RESTful API guidelines?
Let's consider I'd like to get a customer with ALL his details.
- I just expose a
GET
endpoint at address"/customer"
.
Now I'd like to check if a customer with a particular customerId
exists.
- What do I do now? How do I name the endpoint?
Possible solutions I've thought:
I expose another
GET
endpoint at address"/customerNameCheck"
. This feels SOAP-y.I keep the
GET
endpoint at address"/customer"
which accepts an extra parameter calledtype
which could take valuestype="check"/type="fullCustomer"
which will determine the flow of events on the server and serve the appropriate response.
Both of my solutions feel like violations of general naming conventions.
Any ideas?
4 Answers 4
As per comments, the URL to get details of a customer is /customer/{customerId}
.
To check if a customer ID already in use without retrieving all the details, you can query the same URL using a HEAD
request.
A fields
parameter can take care of this.
In the example given in the question we could simply ask for the
customerID
field.If the response provides a result then it exists.
From Best Practices for Designing a Pragmatic RESTful API
Limiting which fields are returned by the API
The API consumer doesn't always need the full representation of a resource. The ability to select and choose returned fields goes a long way in letting the API consumer minimize network traffic and speed up their own usage of the API.
Use a fields query parameter that takes a comma separated list of fields to include.
Example:
GET /customer?fields=id,subject,customer_name,updated_at
Now, I suppose you could go the extra step and HEAD
it, instead of GET
HEAD /customer?fields=id,subject,customer_name,updated_at
which should return a 204
if it exists & a 404
if not.
Now I'd like to check if a customer with a particular customerId exists. What do I do now? How do I name the endpoint?
You don't.
REST is about state transfer. You transfer a representation of the resource between the client and server (REpresentational State Transfer).
You don't put domain specific logic into your URL scheme. A resource has a URL, and that is. You don't use URLs to start running procedures on the sever (eg hey server check if this customer exists)
That is moving into RPC territory, and is the opposite of what REST is trying to give you.
Why would i want ALL the details of the customer if all I want to know is if he exists or not?
REST doesn't concern itself with "why" the client wants the resource. That isn't for the URL scheme to manage. The client might want the resource just to see if it exists, it might want to see if the customer is from Washington, it might want the resource to see if the customer joined in the last year, etc etc
Your URL scheme doesn't care. This is on purpose, cause imagine if your URL scheme did care. You would end up with URL scheme expressing some sort of domain specific query language.
It is far easier to just get the resource and let the client figure out what conclusion it draws from the current state of the resource.
If you have a resource that is massive and your client would like the representation of this resource in another format, you can use the Accept
and Content-Type
headers to negotiate between the client and the server a format that the client wants. For example you might have a representation of the Customer that has the entire customer data, and one that just has ID and name. The client can say it accepts this short format and the server can return it.
Though to be honest unless your resource is massive I wouldn't even bother with that.
Normally in REST your would get:
/customers -> List of customers (We include links here in HATEOS so in this JSON you will find link to /customers/123)
/customers/123 -> Full details of customer 123 (you can limit fields if you want)
/customers/9999 -> If this customer does not exist return error 404
So as you see you would never get a link to /customers/9999 in /customers because it does not exist. So you would not encounter a missing customer a lot of times.
It can happen though, for example if you cached a link to customer 100 and it gets deleted. In that case the API client receives an error 404 which is a permanent error and it will clear it's cache so it will not happen again.
Your question:
How do I name API endpoints that serve the same entity in different ways and still adhere to the RESTful API guidelines?
In general you won't. What you have is a resource, let's say a customer in this case. That resource can be represented in multiple ways. For example you could do:
/customers/123.json
/customers/123.xml
/customers/123.pdf
Same customer, same url, but different representation. You can do this by using content-type detection so you don't have to use extensions if you want.
For the same customer you only want a single url. Not multiple endpoints, that's not a strategy for the future. REST strongly works with error codes to respond the right answer to your client. That's what prevents the need for things like:
I keep the GET endpoint at address "/customer" which accepts an extra parameter called type which could take values type="check"/type="fullCustomer" which will determine the flow of events on the server and serve the appropriate response.
You just don't need that in REST.
-
I was wrong in my comment above - sorry and thanks:)nicholaswmin– nicholaswmin2016年06月30日 10:47:43 +00:00Commented Jun 30, 2016 at 10:47
GET /customer/{customerId}
. If it exists you see all their details, if not the customer doesn't exist.