I want to follow the best practice to implement a REST API. There is a resource I want to expose and I can think of two ways of doing it as an endpoint.
I want to give the user the opportunity to receive all the payments for a certain campaign.
I can expose /campaigns/{id}/payment that returns a paginated list of payments with all the data for each (name, address, date...). Where /campaign/{id} in turn returns all the data of the campaign (name, description..., array of paymentId with a route to get them one by one).
Or I can expose /payments/campaigns/{campaignsId}.
What is the best approach and why?
I would use /campaigns/{id}/payments because it communicates the contents of the response that the client can expect when querying this URL with a GET most clearly and according to common practice.
GET /camapaigns/{id}/payments
reads much like "give me all the payments for the campaign with id = {id}". So this follows the principle of least astonishment. Also, the client then gets exactly what's requested.
There's a nice API design guide for RESTful APIs from Microsoft, if you'd like to read more about this.
Assuming that REST cares about the URI spelling is a misconception.
However, I encourage you to adopt a consistent naming convention in URIs for your API. It's a common approach to use use plural nouns for URIs that reference collections and organize the URI to represent a hierarchy.
So, for the situation you've described in your question, you could use /campaigns/{id}/payments for identifying your resource. It identifies a collection of payments for a particular campaign.
Related
Make-up scenario:
Let's say I am building a RESTful Web API backend for managing the payment plans for members:
It's for members so you would have to register with us. Each member would have a member ID internally.
There are various payment plans: 0% interest for 6 months, 0% interest for 12 months, etc. Each payment plan would have an ID internally.
The relationship between member and payment plan is many-to-many.
Each member also would have 1 active plan at a time. You can change it, but there is only 1 active plan allowed for a member.
Now if I want to design an API endpoint to return the information about the member active payment plan, I would normally do something like:
/members/{member-id}/plans/active
I understand that it might be a bad idea to put state on the URI (I had a separate question for that matter), but please bear with me.
Now here is the tricky part: the company's policy states that I can't have the member ID in the URI. They will have some kind of tokens in HTTP header, which is required in order to access the RESTful API endpoints, that contains the member ID.
My API application, which is ASP.NET Core Web API by the way, has no problem creating a filter to parse that token and transform it into member ID, in the code. It's just that my API URIs can't have the member ID anymore.
How would you design the URI in this case?
Without the member ID on the URI, mine would look like
/plans/active
And the data now would be all driven/filtered by that member ID, securely inside the API backend. Is this normal?
the data now would be all driven/filtered by that member ID, securely inside the API backend. Is this normal?
It sounds to me as though things are going sideways; as though people don't understand REST, or that people don't understand that what they are trying to achieve isn't a good fit for REST.
In order to obtain a uniform interface, multiple architectural constraints are needed to guide the behavior of components. REST is defined by four interface constraints: identification of resources.... -- Fielding, 2000
REST uses a resource identifier to identify the particular resource involved in an interaction between components. REST connectors provide a generic interface for accessing and manipulating the value set of a resource, regardless of how the membership function is defined or the type of software that is handling the request. The naming authority that assigned the resource identifier, making it possible to reference the resource, is responsible for maintaining the semantic validity of the mapping over time (i.e., ensuring that the membership function does not change). -- Fielding, 2000
The web works on the shared understanding that uniform resource identifiers identify resources. The URI is the key of the key/value store. When you start moving identifying information into other parts of the request, then you are opting out of the "uniform interface" that is shared by everyone else. This puts interop at risk.
On the other hand, much of the web also assumes that identifiers are published, and there isn't in general a lot of discipline to restrict the copying of them. So you certainly don't want secrets and/or sensitive information included.
The answer in REST is to use another layer of indirection. The rule is that we should be using a URI, and each identifier should map to one resource. But there's no rule that says that the spelling of the URI must match the semantics of the resource.
In other words: URL shorteners work!
GET /99bfb1e3-89a4-4a44-a6d7-0e70c209f447 HTTP/1.1
As far as REST is concerned, that's a perfectly valid request, with an entirely satisfactory identifier. As long as your server understands how to find the secrets using that key, then that's fine.
Of course, you could add semantic information to the URI that isn't sensitive, to help the humans orient to the context
GET /members/99bfb1e3-89a4-4a44-a6d7-0e70c209f447/plans/active HTTP/1.1
GET /members/plans/active/99bfb1e3-89a4-4a44-a6d7-0e70c209f447 HTTP/1.1
GET /members/plans/active?99bfb1e3-89a4-4a44-a6d7-0e70c209f447 HTTP/1.1
These are all also fine (again, assuming that you can use the information provided to discover the sensitive information you need to produce/modify the corresponding resource).
On the other hand, if your organization's concerns are related to leaking the identifier itself... then somebody with seniority should really be challenging the assumption that REST/HTTP is the right answer to the problem.
As your deviate further from the "standard" for HTTP messages, you increase the risk that some general purpose component isn't going to understand what is going on, and if that results in significant loss of property, your lawyers aren't going to be happy.
In my opinion this is pretty normal. This is usually the case when you are using a JWT token for authentication for example. The token not only authenticates the user but also contains relevant information about it.
In these cases, you will also see APIs with that kind of endpoints without any information about the user (like an ID or something) explicitly in the path.
Just a suggestion or a point of view from my side, I would actually keep the members part in the path: /members/plans/active.
We have 2 developers who have conflicts in the way to design the RESTful API Endpoint. Basically, let say that we have Facebook product in hand, one table for the posts.
First developer give the opinions that
We should seperate Endpoint by product, not by the technical storage. To be like that, we will have endpoint for user facebook post and other facebook post.
/v1/wall/mypost
/v1/wall/other
To be like that, we be able to configure each products that may return difference results
Second developer disagree, give the opinions that
If be like that, it will make infinite endpoint. it will have /wall/someone, /wall/sometwo.
We should have single endpoint, and just let that be a part of query. ex. /wall?user=someone, /wall?user=sometwo
The endpoint should be look like technical schema, it return the same result, why it have to seperated to make it more jobs on maintenance the code.
What is the good practice to design our endpoint? Is it should be endpoint by the product? or is it should be by schema?
It should depend on what 'resource' that the service is suppose to manage from the API user perspective and not from the internal implementation.
With that, if the service is to manage say, a resource that can be identified by 'someone', 'sometwo' and, then the correct way to model it is
/wall/someone/
/wall/sometwo/
In this case, 'someone' and 'sometwo' are two different resources and you could have infinite # of them; but that has nothing to do with the internal storage or implementation.
On the backend, there should be some url pattern to extract 'someone' and 'sometwo' as resource and map them into internal implementation details.
What are these "endpoints" you speak of? That's SOAP terminology! RESTful web services are defined in terms of "resources" that are uniquely identified by URL.
A resource typically represents an entity in your domain model (e.g., a user). The ID of the entity is typically used as a path element ("path parameter" in the lingo of most REST libraries, such as JAX-RS) in the URL. Query parameters should only be used to sort/filter results on the server side.
Your first developer is closer to being correct.
I'm currently figuring out a way how to build our REST webservice so resources can be linked to other resources at creation time. Take the following scenario.
We have /user/123/ who sits in the collection /company/456/users/ and also in the global users collection at /user/123/
When I want to add a new user to company 456 I perform a POST to /company/456/users/ to add it to this collection. But what if the user resource depends on more than only the company? Lets say for example that the user resource also tracks address information on the user so it might also depend on the /country/12/ resource. How can I pass the dependency on the country to the REST webservice. Should I just pass a country_id in the payload of the POST request?
What is considered best-practice for the RESTful approach to managing links to other resources?
Ummm... posting to /company/456/users/ does not look right to me...
What about posting to /users, or even better to /user/{newid}?
From there, you can either just create a user, and maybe add links in another moment, or you can specify all the links as url-encoded parameters (or in the payload, but I prefer the former... it just looks cleaner to me, but this is only my personal opinion):
POST /users?company_id=456&county_id=12
or
POST /users?company_id=456
or
POST /users
I have resource endpoints that I would like to respond differently to the user that tries to access the endpoint.
Scenario
Let us say that I have a resource endpoint /users, and the following UserTypes:
GirlUser
BoyUser
Admin
When a GirlUser executes a GET on /users I want to only allow for other GirlUsers to be accessible. I would expect BoyUsers to have a similar result, and Admins to receive all users.
My Question
Is it more RESTful to:
Handle this with different GrantTypes or Scopes through OAuth, using the one /users endpoint.
Have different endpoints, such as: users/girls, users/boys, and users/all.
Have different APIs for the different types of users.
I'm totally off-base with possible answers and it's something that I don't expect.
Would anything change if I have other endpoints that I would want to only be operational for a certain UserType?
(For example, ones that process payments.)
Thank you.
Your endpoints should be independent of the sex of the user. What's the problem in having a common User endpoint. (You are doing it right already!!)
Though it depends on the kind of information that you want to return, the kind of resources in hand. Are you returning JSON/XML? You have a Girl and a Boy class that you work with in the backend. If a girl user hits the endpoint you serialize objects and return data to the user - that sounds okay to me.
If your UML design does not differentiate between girls/boys then you should have the same endpoint.
In order to understand the problem properly,
i) What kind of data are you returning?
ii) How have you designed the UML?
iii) Are you returning some data from a DB? Is it expensive to run all girls/all boys query on it everytime the endpoint is hit?
As for scopes, in OAuth one scope generally corresponds to one endpoint. Like in Google, G+ is a scope, google drive is a scope. We don't see G+ girls, G+ boys scopes, do we now?
In java terms, the closest match to the API design is a Factory pattern (that's how I explain it to myself, might not be technically correct) - depending on the type of user you call a specific method that returns data. The endpoint should be generic and extensible - having separate API's is indeed a bad design as it leaves little to expansion.
I'm reasonably sure I understand the server-side of HATEOAS design - returning state URL's in the response - but I'm slightly confused about how to design a client to accept these.
For instance, we access a resource at //somehost.com/resource/1 - this provides us with the resource data and links. We'll assume POST to //somehost.com/resource is returned, indicating a 'new' action. Now I understand posting some data to that url creates a new resource, and provides a response, but where does the form to post that data reside? I've seen implementations where //somehost.com/resource/1/new provides a form which POSTS to /resource, but that URL itself contains a verb, and seems to violate REST.
I think my confusion lies in that I'm implementing a RESTful API and a client to consume it, within the same application.
Is there some sort of best-practice for this sort of thing?
I've seen implementations where //somehost.com/resource/1/new provides a form which POSTS to /resource, but that URL itself contains a verb, and seems to violate REST.
This is incorrect. A URI containing a verb does not, in itself, violate any REST constraint. It is only when that URI represents an action that this becomes a violation. If you can perform a GET request on the URL and receive some meaningful resource (such as a "create new resource" form), then that is perfectly RESTful, and good practice.
My own API is exactly as you describe: /{collection}/new returns a form. /new is just shorthand for a hypothetical /new-resource-creation-form and still represents a noun, and only supports GET requests (HEAD, OPTIONS and TRACE not withstanding).
What HATEOAS prohibits is the user agent being required to know, that in order to create a new resource, it must add /new to the name of the collection.
Basically, if you implement your API as (X)HTML, and can surf it in a browser and perform all actions (AJAX may be required for non-POST form submissions until HTML and browsers catch up with HTTP), then it complies with the hypermedia constraint of REST.
EDIT promoted from comments:
As long as the response negates any need for a priori knowledge, it conforms to the hypermedia constraint. If the client claims to understand HTML, and you send back a response containing a link to an external stylesheet or javascript (no matter where that is hosted) which the client needs to be able to render the page correctly, then it is reasonable to say that the constraint is met. The client should know how to handle all media types it claims to support. A normal human web browser is the perfect example of a client with no out-of-band knowledge about any one HTTP service (web site).
Just to say it explicitly, a web site is a kind of HTTP service. Web browsers do not treat different web sites differently. In order to search for products on Amazon, you load the Amazon service endpoint at http://amazon.com/ and follow links or fill out forms provided in that response. In order to search for products on eBay, you load the eBay service endpoint at http://ebay.com/ and do the same.
Browsers don't know in advance that for searching eBay you must do this, but for searching Amazon you have to do that. Browsers are ignorant. Clients for other HTTP services should be ignorant too.
Yes, you could provide a URI that returns a form for resource creation. Conceivably the form could be used for dynamic discovery of the elements needed to construct a new resource (but you'd want to decide how practical that would really be in a machine-to-machine environment).
Unless there is a requirement that somehow the API has an exact browser-surfable equivalent, the documentation of the media type will describe what elements are needed.
Remember that documentation of media types and the allowed HTTP verbs for a resource is not contrary to RESTful principles. Look at the SunCloud API for an example.
Indeed, according to your example, POST'ing to
//somehost.com/resource
to create a new resource is more standard than first returning a form
//somehost.com/resource/1/new
and THEN POST'ing to
//somehost.com/resource
anyway.