What is a good strategy for adding additional information in a GET query over REST? - rest

Given that we provide a restful api that serves book entities listening at
/books
And a client can get a book at the usual
GET /books/{id}
Suppose that we want to begin offering discounts on books to only our most vigilant buyers. These buyers would be given a discount code, and that code will reduce the price of the book.
Thus, a generic response may be
GET /books/4
{"id":4, "price":"24.95"}
Where a response to a query with a discount code may be
GET /books/4
{"id":4, "price":"24.95", "yourPrice":"19.95"}
The back-end processing we can get figured out, but what is the best practice for a client submitting a discount code over a restful api?
Certain books will be eligible for discounts while others will not. Discounts will not be broad (20% off everything), but instead will map to a specific price for that particular code (or client/code combo).
We've considered:
kludging the url
GET /codes/{someCode}/books/{id}
Adding the code in a header value
Using a query string
GET /books?code=myCode
anything else?
EDIT: Our goal is not to implement single-use codes. Instead, these discount codes could be used some fixed number of times for some fixed set of books.

I like using query variables. I just looked at the RESTful Web Services book, my main reference in this area, and they say:
Use query variables only to suggest
arguments being plugged into an
algorithm... If two URIs differ only
in their query variables, it implies
they're the different sets of inputs
into the same underlying algorithm.
It seems to me your discount codes are inputs to a discounting algorithm.
Charles

If you're going to be submitting anything that's not idempotent, I would suggest using POST instead of GET. You wouldn't want a client to be able to use their code more than once.

Anything you add in the URL or header values are open to be intercepted, and possibly allowing other users to 'fake' their discount ID. 1 approach would be to introduce a new POST call, that will allow the ID to be encrypted with simple HTTPS. The POSTed data could be as simple as the discountID or customerID.
Added - Sorry Michael, you already said that :)

You can register the code in a table so when the user retrieves that book automatically returns that book with the proper discount, for example:
The user can add some code
POST /register/{code}
This will add an entry to a table {user} - {code} so when the user retrieves by
GET /books/{id}
will use that entry to apply the discount. I'm guessing that you already have some relation between {code}-{book} so wont get into that.

Related

How should I design a REST API

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".

Rest: url endpoint for extract similar data

I have a REST syntaxe question:
what url do you give to an endpoint to extract data similar to the record which from the id passed?
By exemple : I have a class Record:
Record {id:12, phoneNumber:"+336746563"}
I want a endpoint who will return all the records who share the same phoneNumber than the record with the id 12
which url respect the most the REST protocol ?
EDIT IMPORTANT : the client DON't know the phone number when he call the url. only the 12 id.
what url do you give to an endpoint to extract data similar to the record which from the id passed?
Anything you want -- the machines don't care what spelling you use for your resource identifiers.
I want a endpoint who will return all the records who share the same phoneNumber than the record with the id 12
/all-records-with-same-phone-number-as?id=12
/all-records-with-same-phone-number-as?12
/all-records-with-same-phone-number-as/12
All of these examples are fine. They have different trade offs -- the first one is really easy to generate using an HTML form. The last once allows you do interesting things with relative references and dot-segments.
/record/12/all-records-with-same-phone-number
similar to the above, we've just juggled the order of the path segments a little bit. Might be useful if we want to have relative references to other resources under the same /record/12 stem.
If you are expecting to need to paginate, then you might want to think about how the paging parameters fit with everything else. Again, the machines don't care, but some spellings are easier to work with than others.
I am not sure if I understand the question but let me try.
You can do this in various ways which is best suited for you w.r.t. your programming language. For example, domain.com/api/records/123456 can be the end-point. 123456 is a parameter and your code will return all the records having phoneNumber=123456.
Alternatively, the end-point can be domain.com/api/records?phoneNumber=12345.
Or Even, domain.com/api/records/123456/phonenumber.
The other option is to have the request data in the body and the domain would just look like domain.com/api/records with request as {"PhoneNumber":"123456"}
AFAIK, all these URLs respect REST protocol.
I would use something like
/service/records/{id}/similar
where the service would define similarity. It depends on the usecases for when Record becomes more complex and the client should able to specify fields.
This would sooner or later result in queries that would not be based on an existing record and my look like
/service/records?foo=1&bar=2
I could also think of
/service/records/phone-number/12345
because you are really interested in records with the same phoneNumber, not similarity?
But again, as things get more complex you will be better off with a query I think.

REST url proper format

my REST API format:
http://example.com/api/v1.0/products - get all products
http://example.com/api/v1.0/products/3 - get product with id=3
Also, the products can be orginized into a product groups.
What is a proper way to get all product groups according to REST best practices:
http://example.com/api/v1.0/products/groups
or
http://example.com/api/v1.0/productgroups
...
another option ?
I can't agree with Rishabh Soni because http://example.com/api/v1.0/products/groups may lead to ambiguity.
I would put my money on http://example.com/api/v1.0/productgroups or even better http://example.com/api/v1.0/product_groups (better readability).
I've had similar discussion here: Updating RESTful resources against aggregate roots only
Question: About the thing of /products/features or /product-features,
is there any consensus on this? Do you know any good source to ensure
that it's not just a matter of taste?
Answer: I think this is misleading. I would expect to get all features
in all products rather than get all possible features. But, to be
honest, it’s hard to find any source talking directly about this
problem, but there is a bunch of articles where people don’t try to
create nested resources like /products/features, but do this
separately.
So, we can't be sure http://example.com/api/v1.0/products/groups will return all possible groups or just all groups that are connected with all existing products (what about a group that has not been connected with the product yet?).
To avoid this ambiguity, you can add some annotation in documentation. But you can just prepare http://example.com/api/v1.0/product_groups and all is clear.
If you are developing Rest API for your clients than you should not rely on id's. Instead build a meaningful abbreviation and map them to actual id on server side.
If that is not possible, instead of using
http://example.com/api/v1.0/products/3 you can use http://example.com/api/v1.0/products?product_id=3 and then you can provide "product_id" description in the documentation. basically telling the client ways to use product_id.
In short a url must be meaningful and follow a pattern.The variable part must be send by in the url query(part after ? or POST payload)
With this, method to querying the server is also important. If client is trying to get something to the server he should use "GET" http request, similar POST http request if it is uploading new info and "PUT" request if it is updating or creating a new resource.
So by this analogy http://example.com/api/v1.0/products/groups is more appropriate as it is following a pattern(groups in product) while productgroups is more like a keyword with no pattern.
A directory like pattern is more easier to understand. Like in file systems(C:\Program Files\WinRAR), every part gets us to more generalized target.
You can also customize this for specific group- http://example.com/api/v1.0/products/groups?id=3

REST where should end point go?

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

RESTful API subresource pattern

In designing a RESTful API, the following call gives us basic information on user 123 (first name, last name, etc):
/api/users/123
We have a lot of information on users so we make additional calls to get subresources on a user like their cart:
/api/users/123/cart
For an admin page we would like to see all the cart information for all the users. A big table listing each user and some details about their cart. Obviously we don't want to make a separate API call for each user (tons of requests). How would this be done using RESTful API patterns?
/api/carts/users came to mind but then you'd in theory have 2 ways to get a specific user's cart by going /api/carts/users/123.
This is generally solved by adding a deref capability to your REST server. Assuming the response from your user looks like:
{
...
cartId: "12345",
...
}
you could add a simple dereference by passing in the query string "&deref=cart" (or however you setup your syntax.)
This still leaves the problem of making a request per user. I'd posit there are two ways to generally do this. The first would be with a multiget type of resource (see [1] for an example). The problem with this approach is you must know all of the IDs and handle paging yourself. The second (which I believe is better) is to implement an index endpoint to your user resource. Indexing allows you to query a resource (generally via a query string such as firstName=X or whatever else you want to sort on.) Then you should implement basic paging so you're not passing around massive amounts of data. There are tons of examples of paging, but the simplest would be to specify a number (count=20) a start token (since=X) and a sort order (sort=-createdAt).
These implementations allow you to then ask for all users and their carts by iterating on the index endpoint. You might find this helpful as a starting point for paging [2].
[1] - How to construct a REST API that takes an array of id's for the resources
[2] - Pagination in a REST web application
For some reason I was under the assumption that having 2 URIs to the same resource was a bad thing. In my situation /api/users/123/cart and /api/carts/users/123 would return the same data. Through more research I've learned from countless sources that it's acceptable to have multiple URIs to the same resource if it makes sense to the end user.
In my case I probably wont expose /api/carts/users/123, but I'm planning on using /api/carts/users with some query parameters to return a subset of carts in the system. Similarly, I'm going to have /api/carts/orgs to search org carts.
A really good site I found with examples and clear explanations was the REST API Tutorial. I hope this helps others with planning their API URIs.