I'm designing a REST API. The part I'm working on now involves simply reading objects in the form of JSON data off of the server and modifying them.
The resource that I am thinking of using for this looks like:
/data/{table name}/{row key}
I would like to allow GET and PUT operations on this resource.
The question that I am wrestling with is that I would like to return other data along with the JSON object such as customer messages, the amount of time it took for the round trip to the data base, etc... I would also like to allow for sending query arguments with the payload in cases where the URL would be too long if they were included there.
So the resources would work like this:
GET
GET /data/{table name}/{row key}
Server returns:
{
data:{...JSON OBJECT GOES HERE ....},
message:"customer messages go here",
responseTime:'123ms',
otherInfo:"Yada yada yada;
}
PUT
PUT GET /data/{table name}/{row key}
Client sends as payload:
{
data:{...JSON object goes here...},
queryArguments:{...extra long query arguments go here...}
}
I'm afraid this might violate the rules for proper RESTful GET and PUT resources because what you are sending to the server is not exactly what you are getting back out since other information is being included in the payloads. I'd rather not have every operation be a POST as a remedy.
Am I being too much of a stickler with this? Is there some other way I should be structuring this?
Thanks!
Edit::::
I should note that in the resource: /data/{table name}/{row key}, I used 'table name' and 'row key' for simplicity. This is for use with a noSQL database. This resource is intended to work similar to Amazon S3. "uuid" would actually be a better description than 'row key'.
As for me it just depends on how additional info is going to be used. For my customers responseTime is not a question (or at least I think so :), they just need that response. For me as developer it can help debugging. So when customer gives me slow request I can test it easy, and that extra information could help. Here I mean that it is possible to create simple url as you specified /data/{table name}/{row key} and send just response according to that request, and you can make one more url /data/{table name}/{row key}/debug or whatever else to get the same data with additional info like "reponseTime". Just an idea ;)
UPDATE: Ah yes, forgot: do not use table-name as part of your url, at least modify its name. I don't like to tell anybody how my tables are called, if somebody is going to hack my DB injecting extra code I would like her to spend more time looking for any information, instead of giving her info on a plate :)
I see nothing wrong with your approach.
But if I was implementing this scenario, I would have asked myself the following questions:
Who is my resource?
Is customer message part of the resource?
Is "response time" is part of the resource?
Let's take as an example "response time". If it's part of your resource, your approach is perfect and nothing else should be done.
However, if it's not part of the resource, return it as a HTTP header. Fair enough.
I don't see anything wrong with this, looks pretty standard to me. I'm not sure what you are planning to pass in queryArguments, is this where you would specify a callback to execute for JSON-P clients? Only thing I'd recommend you keep in mind is that REST deals with resources, and that does not necessarily map 1-to-1 with tables. Instead of using a row key you might want to have some type of GUID or UUID that you can map to that resource.
Related
I'm looking for a best way for implementing an endpoint of REST-full application that will be responsible for creating a new library orders. Let's assume that I have the following resources.
If I want to get all books of a particular author I can use the next endpoint:
HTTP GET
api/books/author/123
If I want to fetch all orders of a particular book I can use the endpoint provided below:
HTTP GET
api/books/456/orders
My question is what will be the most suitable URL and a request model for an endpoint that will create orders?
From my perspective it can be
HTTP POST
api/books/456/orders
And one more question. Is it a good practice in REST to use request models like CreateOrder? If I want to create a REST-full web application can I use the following request model:
class CreateOrder
{
AuthorId: number;
BookId: number;
ClientId: number;
}
Sometimes it makes me confused. Should request models look like our resources or not?
Let's assume that I have the following resources.
Your "resources" look suspiciously like "tables". Resources are closer to (logical) documents about information.
what will be the most suitable URL and a request model for an endpoint that will create orders
For the most part, it doesn't matter what URL you use to create orders. In a hypermedia application (think HTML), I'm going to submit a "form", and the meta data associated with that form are going to describe for the client how to compose a request from the form data.
So the human, or the code, that is manipulating the form doesn't need to know anything about the URL (when is the last time that you looked to see where Google was actually sending your search?)
As far as general purpose web components are concerned, the URL/URI is just an opaque identifier - they don't care what the spelling means.
A thing they do care about is whether the spelling is the same as something that they have cached. One of the consequences of a successful POST /x message is that the cached representation(s) of /x are invalidated.
So if you like, you can think about which cached document should be refreshed when an order is created, and send the request to the identifier for that document.
Should request models look like our resources or not?
It's not necessary. Again, think about the web -- what would the representation of create order look like if you were POSTing form data?
clientId=1&bookId=2
or maybe
bookId=2&copies=3
If the "who is creating an order" is answered using the authorization headers.
In our HTTP requests and responses, we are fundamentally sending message representations - sequences of bytes that conform to some schema. There's no particular reason that those sequences of bytes must, or must not, be the same as those we use elsewhere in the implementation.
Your end-point does not need to always start with /books. You can introduce another end-point /orders for creating or getting orders. So , to create an order , you can :
HTTP POST
api/orders
And does the 'request model' that you mean is the HTTP request body structure ? If yes, it does not need to be 100% match with your back-end persisted/domain model. Just include enough parameters that the server needs to know in order to create an order. (e.g. Include bookId rather than the whole book object etc.)
BTW , to get all books for a particular author , it is more common to use query parameter such as :
HTTP GET
api/books?authorId=123
What you are doing is not REST, it is CRUD over HTTP. REST does not care about your URI structures and resources are very far from database tables. If CRUD is all you need, then download a CRUD generator library https://github.com/search?q=crud+generator&type=Repositories, which will generate all the upper and you won't need to write it manually.
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
I'm helping build a similarity search service for files. One way to search for something is with a GET request, by giving a file's URL, but I also need to allow clients to send the file directly. I have to following options:
Make the client send a GET request with a Payload; it seems this is not recommended -- HTTP GET with request body
Use something else than GET (maybe a PUT?) for file-based search. The problem is none of the other HTTP methods seems to suit this purpose.
What option would suit best here? I'm not an expert in this field, and I can't figure out what's the right thing to do in this situation.
Here is the rule I have always followed with REST.
GET - only querying data and returning a data set.
POST - Creating data in the database
PUT - Modifying data
DELETE - Destroy data in the database.
If you are sending a payload for search params, you can do a GET and put those params (assuming they are name/value pairs) in the query string of the URI.
i.e. http://my.simsearch.com?param1=first¶m2=second ...
If you are actually going to change the database then a POST or PUT is in order.
I hope this helps.
I ended up sending the payload with a GET request. Even though it's not really recommended, hopefully no libraries will complain about this.
I was referring to the O'Reilly book on REST api design, that clearly lays down the message format specifically around the areas of how links should be used to represent interrelated resources and stuff. But all the examples are for reading a resource (GET) and how the server structures the message. But what about a Create (POST) ? Should the message structure for create of a similarily inter-connected object be similar i.e through links ??
By the way of an example, let us consider we want to create a Person object with a Parent field . Should the json message format sent to server thru POST (Post msg body) be like :-
{
name:'test',
age:12,
links:[
{
rel:'parent',
href:'/people/john'
}
]
}
Here is a media type you could look at
http://stateless.co/hal_specification.html
Yes, that is one way of doing it. GET information might be usefully made human-readable, but POST/PUT information targets the machine.
Adding information to reduce the server's need to process information (e.g. by limiting itself to verifying information makes sense rather than recovering it all from scratch) also makes a lot of sense, performance-wise. As long as you do verify: keep in mind that user data must be treated as suspect on general principles. You don't want the first ExtJS-savvy guy being able to forge requests to your services.
You might also format data in XML or CSV, depending on what's best for the specific application. And keeping in mind that you might want to refactor or reuse the code, so adhering to a single standard also makes sense. All things considered, JSON is probably the best option.
I am writing a little app that does one thing only: takes some user-provided data, does some analysis on it, and returns a "tag" for that data. I am thinking that the client should either GET or POST their request to /getTag in order to get a response back.
Nothing is stored on the server when the client does this, so it feels weird to use a POST. However, there is not a uniform URI for the analysis either, so using a GET feels weird, since it will return different things depending on what data is provided.
What is the best way to represent this functionality with REST?
The "best way" is to do whatever is most appropriate for your application and its needs. Not knowing that, here are a few ideas:
GET is the most appropriate verb since you're not creating or storing anything on the server, just retrieving something that the server provides.
Don't put the word get in the URI as you've suggested. Verbs like that are already provided by HTTP, so just use /tag and GET it instead.
You should use a well-understood (or "cool") URI for this resource and pass the data as query parameters. I wouldn't worry about it feeling weird (see this question's answers to find out why).
To sum up, just GET on /tag?foo=bar&beef=dead, and you're done.
POST can represent performing an action. The action doesn't have to be a database action.
What you have really created is a Remote Procedure. RPC is usually all POST. I don't think this is a good fit for REST, but that doesn't have to stop you from using simple URLs and JSON.
It seems to me like there would probably be a reason you or the user who generated the original data would want the generated tag to persist, wouldn't they?
If that's a possibility, then I'd write it as POST /tags and pass the /tags/:id resource URI back as a Location: header.
If I really didn't care about persisting the generated tag, I'd think about what the "user-generated data" was and how much processing is happening behind the scenes. If the "tag" is different enough from whatever data is being passed into the system, GET /tag might be really confusing for an API consumer.
I'll second Brian's answer: use a GET. If the same input parameters return the same output, and you're not really creating anything, it's an idempotent action and thus perfectly suited for a GET.
You can use GET and POST either:
GET /tag?data="..." -> 200, tag
The GET method means retrieve whatever information (in the form of an
entity) is identified by the Request-URI. If the Request-URI refers to
a data-producing process, it is the produced data which shall be
returned as the entity in the response and not the source text of the
process, unless that text happens to be the output of the process.
POST /tag {data: "..."} -> 200, tag
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.
according to the HTTP standard / method definitions section.
I would use GET if I were you (and POST only if you want to send files).