As title: Why is aggregation function bad idea for RESTful? Although I know CRUD is good for RESTful.
For example, the resource is 'employee', and client needs to retrive sum of total 'salary' of all employees. Shouldn't RESTful service provide such sum function?
Further question: if aggregation function is bad for RESTful, how can a client get sum of total salary? To retrieve all 'employee' records and sum up itself?
I wouldn't say that exposing the results of operations (i.e. an aggregation function) as resources in REST has to be considered as bad.
From the RESTful Webservices Cookbook (O'Reilly):
One of the most common perceptions of REST’s architectural constraints is that they
only apply to resources that are “things” or “entities” in the application domain. Although
this may be true in a number of cases, scenarios that involve processing functions
challenge that perception.
It is quite common to treat a processing function as a resource, and use HTTP GET to fetch a representation containing the output of the processing function. You can also use query parameters to supply inputs to the processing function.
So why not provide the result of a salary aggregation of a number of employees as a resource, i.e. like this:
GET /employees/aggregation?data=salary
or more general:
GET /aggregator?resource=employee&data=salary
You could even filter the group of employees for which the salaries should be aggregated, i.e. like this:
GET /employees/aggregation?data=salary&divison=sales
Related
I've seen many examples of HATEOAS where every resource has links to related resources. An API that returns N items of a certain resource per page, the client would probably need N calls to fetch any nested resource by consuming HATEOAS. For example:
GET city/documents:
[{
id: 1,
city: {
self: 'http://service.com/cities?filter=id==1'
},
document: { ... }
...
}, {
id: 2,
city: {
self: 'http://service.com/cities?filter=id==2'
},
document: { ... }
...
}]
FYI, the query parameter uses the FIQL syntax to define the filters.
Now, if the client was to fetch the city details for each document (to show on UI), it will probably need N additional calls. However in my case, the /cities API can additionally take multiple city ids like this: /cities?filter=id=in=(1,2) that can reduce N calls to one. Is there a way to articulate something like this using HATEOAS? I've read about the templates but not sure how should the template look like and how would client consume it?
I've seen many examples of HATEOAS where every resource has links to related resources. An API that returns N items of a certain resource per page, the client would probably need N calls to fetch any nested resource by consuming HATEOAS.
Yes. Less true in a world with Server-Push, where the server can proactively provide multiple resources in response to a query. If you imagine asking for a web page, and getting the html, and then also the images and the java script resources too, then you've got the right sort of idea.
API can additionally take multiple city ids like this: /cities?filter=id=in=(1,2) that can reduce N calls to one. Is there a way to articulate something like this using HATEOAS?
Yes.
Let's walk through it carefully. What you've done here is introduced a new resource, with identifier /cities?filter=id=in=(1,2). You might have another resource /cities?filter=id=in=(1,20) and another resource /cities?filter=id=in=(1,2000). In your implementation, these might be a "single endpoint" that extracts parameters from the identifier and uses them to generate the correct representation.
So what you get is something like a data transfer object - a large grained resource fetched in a single go.
I've read about the templates but not sure how should the template look like and how would client consume it?
The simplest example, which you have likely seen already, is a web form. You allow the client to provide the start and end elements, and the form processing takes that information and creates the specified URI from it.
/filtered-cities?start=1&end=2000
So the client needs to understand what the form is for, and how to identify the semantics of the different elements in the form. The agent needs to understand the processing rules that transfer the form data into the URI.
URI Templates are the same basic idea; they give you a domain agnostic language with which to describe where the parameters go in a resource identifier. The basic pattern is the same - there needs to be agreement about the semantics of the parameters, the server provides a URI, the client provides a parameter map, and the generic code can take care of the merge
uri = template.apply(parameterMap)
URI Templates aren't quite as powerful as forms; with a form, you can introduce a default value for a parameter, but there is no analogous capability in URI templates.
HAL-Forms may give you a better sense of how a form based approach might work in JSON.
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.
I have read that it best practice to use method in REST as an indicator of operation performed on the resource.Lets say i have 5 operation,I am using below resource and methods:
Resource /customer- POST- CreateCustomer
DELETE-delete customer
PUT-update customer
Now I have 2 more operations of query : findCustomer and queryCustomer.
I can use GET method for one of them only.What is the best practice to handle such scenario because passing an explicit HTTP header or extra query string for identifying 1 exceptional opertaion doesnt seem like a good alternative !
I have 2 more operations of query: findCustomer and queryCustomer. I can use GET method for one of them only.
The GET method is suitable for both operations, however you must use different URIs.
Use the following to retrieve a representation of a collection of customers (the operation you define as query):
GET /customers
The collections can be filtered with query parameters.
And use the following to retrieve a representation of a single customer (the operation you define as find):
GET /customers/{id}
{id} is a unique identifier for your customer.
Related: See this answer for some insights on which status code can be returned in each situation.
I found question about subset of REST when display resource by GET /task/ID and as row in collection GET /task.
REST - Resource and Collection Representations
I'm using Apigility.
I know REST is not official, but want to hold as strict as could with overall best practice/standard.
Can i have others fields in collection and resource. Of cource part will be the same, but for collection i need some extra information for filtering and in resource there is now need for them.
Is this will breaking in any way some rules?
It is not uncommon to return partial representations of resources in a REST collection response, while the full representation is returned when the singleton endpoint is requested.
Read for example here (one of the first links I found with this search on Google, there are many more).
Getting a collection
Getting a collection, like "members" may return
1) the entire list of resources as a list of links,
2) partial representations of each resource, or
3) full representations of all the resources in the collection.
So it is not uncommon that a resource representation in a collection differs from the singleton representation, but I would say you would rather have less then more data.
What particular fields were you thinking about adding to the response in your collection? Can you give an example?
That would certainly be unusual, it's better to be consistent, why have 2 models for the same thing? Looking at the Richardson Maturity Model level 1, one would expect a service endpoint mapped to a (single) resource. And what do you mean by extra information for filtering?
If that's a frequent scenario, you might want to handle it on the server through templated URIs (query string) like so:
GET /task?type={type}&property2={value2}
Otherwise, you could just fetch them all and do the filtering on the client (in which case you'll surely need those properties).
My understanding of REST is that anything that does not change state to the underlying system (e.g. query) should be a GET request. This also means that query parameters have to be put into the URI like so:
api/SomeMethod/Parameter1/{P1:double}/Parameter2/{P1:double}
or as query strings as discussed here:
REST API Best practice: How to accept list of parameter values as input
Sometimes the query may require a lengthy vector (number of x/y points). How do I overcome the length problem of URIs here? Should I just use a POST? Thanks.
If the vector really is big enough to start worrying about you should really consider moving it out of the query params and represent it as a RESTful resource.
For example, create a collection at:
api/Vector
Then your API clients can POST their large vectors and then in another request refer to it by a single id number.
This reduces the size of the query length drastically, abides by REST, and allows for these vectors to be easily reused. If you are worried about storage you can expire vectors after 30 minutes or longer.
Another option is to go down the JSON-LD road which is similar except you don‘t host the vectors. You just provide an #context object and API clients will host the vector on their own server and reference it to your API by URL in a query parameter.