I'm developing the search functionality of my REST API and currently URI's structured as:
api/items?type=egg,potato
Let's say each item resource has 4 properties:
Id, Name, Type, Rating
What would be the most restful way to design my URI and return a subset of properties of each resource, e.g. only names of these resources?
--
The reason I ask this is I often want a less heavy duty result-set. For instance, I may build an AJAX search with dynamically populated names as dropdowns - but I do not want extra bloat coming back with each request.
REST isn't really a set of rock-solid standards, but there are some nice practices.
In this particular case I would recommend using the query parameter of an existing resource field as you are now, to select items which have the type value of egg or potato. But to select only a subset, you can introduce a field query parameter. So you can call your API like api/items?type=egg&fields=name, to get only the name field of all the resources with the egg type.
P.S
This is not my invention, I already seen this in other API's, somewhere called select. As far as I know, Facebook has this feature in its API's.
Related
I'm thinking about a REST API design. There are several tables in my database. For example Customer and Order.
Of course - each Order has its Customer (and every customer can have many Orders).
I've decided to provide such an interface
/api/v1/Customers/ -- get list of Customers, add new Customer
/api/v1/Customers/:id: -- get Customer with id=:id:
/api/v1/Orders/ -- get list of Orders, add new Order
/api/v1/Orders/:id: -- get Order with id=:id:
It works flawlessly. But my frontend has to display a list of orders with customer names. With this interface, I will have to make a single call to /api/v1/Orders/ and then another call to /api/v1/Customer/:id: for each record from the previous call. Or perform two calls to /api/v1/Orders/ and /api/v1/Customers/ and combine them on the frontend side.
It looks like overkill, this kind of operation should be done at the database level. But how can/should I provide an appropriate interface?
/api/v1/OrdersWithCustomers
/api/v1/OrdersWithCustomers/:id:
Seems weir. Is it a right way to go
There's no rule that says you cannot "extend" the data being returned from a REST API call. So instead of returning "just" the Order entity (as stored in the backend), you could of course return an OrderResponseDTO which includes all (revelant) fields of the Order entity - plus some from the Customer entity that might are relevant in your use case.
The data model for your REST API does not have to be an exact 1:1 match to your underlying database schema - it does give you the freedom to leave out some fields, or add some additional information that the consumers of your API will find helpful.
Great question, and any API design will tend to hit pragmatic reality at some point like this.
One option is to include a larger object graph for each resource (ie include the customer linked to each order) but use filter query parameters to allow users to specify what properties they require or don't require.
Personally I think that request parameters on a restful GET are fine for either search semantics when retrieving a list of resources, or filtering what is presented for each resource as in this case
Another option for your use case might be to look into a GraphQL approach.
How would you do it on the web?
You've got a web site, and that website serves documents about Customers, and documents about Orders. But your clients aren't happy, because its too much boring, mistake-prone work to aggregate information in the two kinds of documents.
Can we please have a document, they ask, with the boring work already done?
And so you generate a bunch of these new reports, and stick them on your web server, and create links to make it easier to navigate between related documents. TA-DA.
A "REST-API" is a facade that makes your information look and act like a web site. The fact that you are generating your representations from a database is an implementation details, deliberately hidden behind the "uniform interface".
Lets assume that we have some sort of users collection. Each user (single resource) has some sort of stats - number of comments, number of calls, number of anything. And each users collection may also have some sort of stats - global stats.
These stats can be anything from number of comments to something more complicated.
Currently I am thinking of two main ways of "integrating" stats to my RESTful API:
For each single resource user add special computed field - balance, mediumAgeOfMaleFriends etc. When performing GET request to user resource I'll loop for each field in query parameter fields and calculate corresponding values. Example: .../user/123?fields=balance,name,email,mediumAgeOfFemaleFriends
Under each resource create subresource called reports (or something like that), create report resource templates (with predefined configurations) and perform same GET requests like so: .../users/123/reports/1?from=...&to=...
But these two ways don't look like true RESTful ways.
I don't think there's a RESTful convention per-se for stats or reports. Both your options seem reasonable to me (leaning more towards Option 2 though).
Another alternative is to have a root resource for 'reports', e.g. /reports/user/123. This might come in handy in the future if you decide to extend reports to another resource, other than 'user'.
You can also have a look at HubSpots Analytics - Reports API for inspiration.
Suppose there's USERS and ORDERS
for a specific user's order list
You could do
/user/3/order_list
/order/?user=3
Which one is prefered and why?
Optional parameters tend to be easier to put in the query string.
If you want to return a 404 error when the parameter value does not correspond to an existing resource then I would tend towards a path segment parameter. e.g. /customer/232 where 232 is not a valid customer id.
If however you want to return an empty list then when the parameter is not found then query string parameters. e.g. /contacts?name=dave
If a parameter affects an entire URI structure then use a path e.g. a language parameter /en/document/foo.txt versus /document/foo.txt?language=en
If unique identifiers to be in a path rather than a query parameter.
Path is friendly for search engine/browser history/ Navigation.
When I started to create an API, I was thinking about the same question.
Video from apigee. help me a lot.
In a nutshell when you decide to build an API, you should decide which entity is independent and which is only related to someone.
For example, if you have a specific endpoint for orders with create/update/delete operations, then it will be fine to use a second approach /order/?user=3.
In the other way, if orders have only one representation, depends on a user and they don't have any special interaction then you could first approach.
There is also nice article about best practice
The whole point of REST is resources. You should try and map them as closely as possible to the actual requests you're going to get. I'd definitely not call it order_list because that looks like an action (you're "listing" the orders, while GET should be enough to tell you that you're getting something)
So, first of all I think you should have /users instead of /user, Then consider it as a tree structure:
A seller (for lack of a better name) can have multiple users
A user can have multiple orders
An order can have multiple items
So, I'd go for something like:
The seller can see its users with yourdomain.com/my/users
The details of a single user can be seen with yourdomain.com/my/users/3
The orders of a single user can be seen with yourdomain.com/my/users/3/orders
The items of a single order can be seen with yourdomain.com/my/users/3/orders/5
This question is about optimal REST API design and a problem I'm facing to choose between nested resources and root level collections.
To demonstrate the concept, suppose I have collections City, Business, and Employees. A typical API may be constructed as follows. Imagine that ABC, X7N and WWW are keys, e.g. guids:
GET Api/City/ABC/Businesses (returns all Businesses in City ABC)
GET Api/City/ABC/Businesses/X7N (returns business X7N)
GET Api/City/ABC/Businesses/X7N/Employees (returns all employees at business X7N)
PUT Api/City/ABC/Businesses/X7N/Employees/WWW (updates employee WWW)
This appears clean because it follows the original domain structure - business are in a city, and employees are at a business. Individual items are accessible via key under the collection (e.g. ../Businesses returns all businesses, while ../Businesses/X7N returns the individual business).
Here is what the API consumer needs to be able to do:
Get businesses in a city (GET Api/City/ABC/Businesses)
Get all employees at a business (GET Api/City/ABC/Businesses/X7N/Employees)
Update individual employee information (PUT Api/City/ABC/Businesses/X7N/Employees/WWW)
That second and third call, while appearing to be in the right place, use a lot of parameters that are actually unnecessary.
To get employees at a business, the only parameter needed is the key of the business (X7N).
To update an individual employee, the only parameter needed it the key of the employee (WWW)
Nothing in the backend code requires non-key information to look up the business or update the employee. So, instead, the following endpoints appear better:
GET Api/City/ABC/Businesses (returns all Businesses in City ABC)
GET Api/Businesses/X7N (returns business X7N)
GET Api/Businesses/X7N/Employees (returns all employees at business X7N)
PUT Api/Employees/WWW (updates employee WWW)
As you can see, I've created a new root for businesses and employees, even though from a domain perspective they are a sub/sub-sub-collection.
Neither solution appears very clean to me.
The first example asks for unnecessary information, but is structured in a way that appears "natural" to the consumer (individual items from a collection are retrieved via lower leafs)
The second example only asks for necessary information, but isn't structured in a "natural" way - subcollections are accessible via roots
The individual employee root would not work when adding a new employee, as we need to know which business to add the employee to, which means that call would at least have to reside under the Business root, such as POST Api/Businesses/X7N7/Employees, which makes everything even more confusing.
Is there a cleaner, third way that I'm not thinking of?
I don't see how REST adds a constraint that two resources could not have the same value. The resourceType/ID is just an example of the easiest use case rather than the best way to go from a RESTful point of view.
If you read paragraph 5.2.1.1 of Roy Fielding's dissertation carefully, you will notice that Fielding makes the disctinction between a value and a resource. Now a resource should have a unique URI, that's true. But nothing prevents two resources from having the same value:
For example, the "authors' preferred version" of an academic paper is a mapping whose value changes over time, whereas a mapping to "the paper published in the proceedings of conference X" is static. These are two distinct resources, even if they both map to the same value at some point in time. The distinction is necessary so that both resources can be identified and referenced independently. A similar example from software engineering is the separate identification of a version-controlled source code file when referring to the "latest revision", "revision number 1.2.7", or "revision included with the Orange release."
So nothing prevents you from, as you say, changing the root. In your example, a Business is a value not a resource. It is perfectly RESTful to create a resource which is a list of "every business located in a city" (just like Roy's example, "revisions included with the Orange release"), while having a "business which ID is x" resource as well (like "revision number x").
For Employees, I would keep API/Businesses/X7N/Employees as the relation between a business and its employees is a composition relationship, and thus as you say, Employees can and should only be accessed through the Businesses class root. But this is not a REST requirement, and the other alternative is perfectly RESTful as well.
Note that this goes in pair with the application of the HATEAOS principle. In your API, the list of Businesses located in a city could (and perhaps should from a theoretical point of view) be just a list of links to the API/Businesses. But this would mean that the clients would have to do one round-trip to the server for each of the items in the list. This is not efficient and, to stay pragmatic, what I do is embed the representation of the business in the list along with the self link to the URI that would be in this example API/Businesses.
You should not confuse REST with the application of a specific URI naming convention.
HOW the resources are named is entirely secondary. You are trying to use HTTP resource naming conventions - this has nothing to do with REST. Roy Fielding himself states so repeatedly in the documents quoted above by others. REST is not a protocol, it is an architectural style.
In fact, Roy Fielding states in his 2008 blog comment (http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven 6/20/2012):
"A REST API must not define fixed resource names or hierarchies (an obvious coupling of
client and server). Servers must have the freedom to control their own namespace. Instead,
allow servers to instruct clients on how to construct appropriate URIs, such as is done in
HTML forms and URI templates, by defining those instructions within media types and link relations."
So in essence:
The problem you describe is not actually a problem of REST - conceptually, it is a problem of HIERARCHY STRUCTURES versus RELATIONAL STRUCTURES.
While a business is "in" a city and so can be considered to be part of the city "hierarchy" - what about international companies which have offices in 75 cities. Then the city suddenly becomes the junior element in a hierarchy with the business name at the senior level of the structure.
The point is, you can view data from various angles, and depending on the viewpoint you take, it may be simplest to see it as a hierarchy. But the same data can be seen as a hierarchy with different levels. When you are using HTTP type resource names, then you have entered a hierarchy structure defined by HTTP. This is a constraint, yes, but it's not a REST constraint, it's a HTTP constraint.
From that angle, you can chose the solution which fits better to your scenario. If your customer cannot supply the city name when he supplies the company name (he may not know), then it would be better to have the key with only city name. As I said, it's up to you, and REST won't stand in your way ...
More to the point:
The only real REST constraints you have, if you have already decided to use HTTP with GET
PUT and so on, are:
Thou shalt not presumeth any prior ("out of band") knowledge between client and servers. *
Look at your proposal #1 above in that light. You assume that customers know the keys for the cities which are contained in your system? Wrong - that's not restful. So the server has to give the list of cities as a list of choices in some way. So are you going to list every city in the world here?
I guess not, but then you'll have to do some work on how you are planning to do this, which brings us to:
A REST API should spend almost all of its descriptive effort in defining the media type(s) used for representing resources and driving application state ...
I think, reading the mentioned Roy Fielding blog will help you out considerably.
In a RESTful-API URL design should be quite unimportant - or at least a side issue since the discoverability is encoded in the hypertext and not in the URL path. Have a look at the resources linked in the REST tag wiki here on StackOverflow.
But if you want to design human readable URLs for your UC, I would suggest the following:
Use the resource type you are creating/updating/querying as the first part of the URL (after your API prefix). So when somebody sees the URL he immediately knows to which resources this URL points. GET /Api/Employees... is the only only way to receive Employee resources from the API.
Use Unique IDs for each resource independent of the relations they are in. So GET /Api/<CollectionType>/UniqueKey should return a valid resource representation. Nobody should have to worry where the Employee is located. (But the returned Employee should have the links to the Business (and for convenience sake City) he belongs to.) GET /Api/Employees/Z6W returns the Employee with this ID no matter where is is located.
If you want to get a specific resource: Put your query parameter at the end (instead in the hierarchical order described in the question). You can use the URL query string (GET /Api/Employees?City=X7N) or a matrix parameter expression (GET /Api/Employees;City=X7N;Business=A4X,A5Y). This will allow you to easily express a collection of all Employees in a specific City - independent of the Business they are in.
Side node:
In my experience an initial hierarchical domain data model seldom survives additional requirements that come up during a project. In your case: Consider a business located in two Cities. You could create a workaround by modelling it as two separate businesses but what about the employee who works half his time in one place and the other half at the other location? Or even worse: It's only clear for which business he works but it's undefined, in which city?
The third way that I see is to make Businesses and Employees root resources and use query parameters to filter collections:
GET Api/Businesses?city=ABC (returns all Businesses in City ABC)
GET Api/Businesses/X7N (returns business X7N)
GET Api/Employees?businesses=X7N (returns all employees at business X7N)
PUT Api/Employees/WWW (updates employee WWW)
Your both solutions use concept of REST sub-resources which requires that subresource is included in parent resource so:
GET Api/City/ABC/Businesses
in response should also return data provided by:
GET Api/City/ABC/Businesses/X7N
GET Api/City/ABC/Businesses/X7N/Employees
similar for:
GET Api/Businesses/X7N
which should return data provided by:
GET Api/Businesses/X7N/Employees
It will make size of the response huge and time required to generate will increase.
To make REST API clean each resource should have only one bounded URI which fallow below patterns:
GET /resources
GET /resources/{id}
POST /resources
PUT /resources/{id}
If you need to make links between resources use HATEOAS
Go with example 1. I wouldn't worry about unnecessary information from the point of view of the server. A URL should clearly identify a resource in a unique fashion from the point of view of the client. If the client would not know what /Employee/12 means without first knowing that it is actually /Businesses/X7N/Employees/12 then the first URL seems redundant.
The client should be dealing with URLs rather than the individual parameters that make up the URLs, so there is nothing wrong with long URLs. To the client they are just strings. The server should be telling the client the URL to do what it needs to do, not the individual parameters that then require the client to construct the URL.
GET https://api.website.com/v1/project/employee;company-id={company-id},
title={title-id}?non-smoker={true|false}&<name1>=<value1>&<name2>=<value2>&<name3>=<value3>
where:
company-id is mandatory,
title is optional
name/value can be any filter criteria.
Is there a better way to define the interface?
This API is not supposed to create an employee object. It is for getting an array of employee objects that belongs to a particular company and has a particular title and the other filter criteria.
I don't know if there is a better way, because it depends often on the technology you use and its idioms.
However, here is two different URI designs that I like (and why)
#1 GET https://api.website.com/v1/project/employee/{company-id}?title={title-id}&non-smoker={true|false}&<name1>=<value1>&<name2>=<value2>&<name3>=<value3>
#2 GET https://api.website.com/v1/project/company/{company-id}/employee?title={title-id}&non-smoker={true|false}&<name1>=<value1>&<name2>=<value2>&<name3>=<value3>
As you can see in both example I extracted company-id from the query string. I prefer to add mandatory parameters in the path info to distinguish them. Then, in the second URI, the employee ressource is nested in the company. That way you can easily guess that you can retrieve all employee from a specific company, which is not obvious in the first example.
This api is supposed to GET employee objects that satisfy the given criteria of belonging to a particular company, having particular job title and some other filter criteria.
Personally I would just design your URI as http://acme.com/employee/?company=X&title=Y&non-smoker=Z&T=U. I wouldn't write "in stone" that the company is mandatory: your API will be easier to change.
However, you should consider that few "big" requests are far faster than plenty of small ones. Moreover, URI representations can be effectively cached. Therefore it is often better to have URIs based on IDs (since there are more chances that they will be asked again).
So you could get the complete employee list of a company (plus other data about the company itself) with http://acme.com/company/X and then filter it client-side.
Are you creating a new employee object? If so then a POST (create) is more appropriate. A good clue is all the data you're pushing in the URL. All that should be in the body of the POST object.