API Endpoint Design : Technical Spec or Product - rest

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.

Related

How to design RESTful API URI when you can't have user ID on the URI

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.

REST API - Logical way to name an endpoint

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.

Is it legal to have REST resource such as /currentUser in terms of RESTful and stateless?

In terms of RESTful and stateless it's pretty legal to have resource like
/users/123
But, the question is: is it legal to have resource that omits user id and assumes that it's implicitly resolved on the server from the user session? For example:
/loggedUser
That resource would point to /users/123 when user with identifier 123 is authorized.
Picking a resource locator
Using /me, /users/me, /users/myself, /users/current or similar URIs to identify a resource that corresponds to the authenticated user is perfectly fine from a REST perspective. According to Roy Thomas Fielding's dissertation, any information that can be named can be a resource:
5.2.1.1 Resources and Resource Identifiers
The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (e.g. "today's weather in Los Angeles"), a collection of other resources, a non-virtual object (e.g. a person), and so on. In other words, any concept that might be the target of an author's hypertext reference must fit within the definition of a resource. A resource is a conceptual mapping to a set of entities, not the entity that corresponds to the mapping at any particular point in time. [...]
When using the URIs mentioned above, you have an identifier for the authenticated user and it will always identify the concept of an authenticated user, regardless of which user is authenticated.
The stateless constraint
The stateless constraint is not related to how your resources are identified. The stateless constraint is about not storing any session state on server side. In this approach, each request from client to server must contain all the necessary information to be understood by the server.
See que following quote from Fielding's dissertation:
5.1.3 Stateless
[...] each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client. [...]
When targeting protected resources that require authentication, for example, every request must contain all necessary data to be properly authenticated/authorized.
A similar question has been answered here and here.
It is OK as long as you use only the data from request (HTTP Headers in your case). In other words, this may work only for users that pass authentication.
Yes.
It is very common for ReST services to make assumption about authorization context.
Though making such a decision will limit usability of that route for users other than the logged on user. For example an admin might need to use that service for a specific user.
A ReST endpoint may even use Claims that exist in the Authorization context. for example return different data for a user that has logged in using certain mechanism.
of all HTTP headers, there are some that are probably not good to be used to tailor the ReST response. for example I will not use the 'referer'.
Make sure you check for any caching strategy you may have before making such design decisions.
It is perfectly legal as long as you keep it stateless. That is, you infer the current user from a security context provided with the HTTP request, usually a token of some kind.
For example, you perform a GET /current-user with an Authentication header containing a JWT token. The server can get most of the user info of the current user from the JWT token and complete with data from the database and retrieve it back to the caller.
I'd also recommend not to use camel case in URIs. It can be a nightmare for devs and some servers are case insensitive.
Beware, if you are holding a server user session, as you imply in your question, your API is already stateful.
As #n00b says, REST isn't a formal standard - and that's probably a good thing.
The original definition comes from Roy Fielding's dissertation. - so if you're doing the things Roy recommends, your design is RESTful. There are a few other things people have added to that - for instance, the Richardson Maturity Model is pretty commonly accepted. There are a few public "standards" documents on the web, e.g. Microsoft's version. I don't think they address this question directly, though.
So, it's up to you - but for what it's worth...
I believe APIs should be consistent and predictable. If I am asking for information about a user, I don't really like that there are two ways of doing it - one by ID, and one using a magic identifier for the current user. I also don't like the idea of introducing the concept of state into the API - by saying "there's an conceptual entity in your API called current user", you are introducing the concept of statefulness, even if you use HTTP headers to manage that.
So, if your RESTful API is designed for use by client application, I think it's reasonable to ask that client to manage state, and carry around the ID for the current user. This also makes your GET requests consistently cacheable - you can theoretically cache /users/123, but you cannot cache /loggedUser.
I believe there is a logical difference with your authentication and authorization action (I've logged in, proven who I am, and therefore got access to specific resources on the system), versus "I am user 123".
The reason you might disagree with this is that it makes your API harder to discover by human beings - someone who is trying to figure out how to get information about the current user has to log in, and then remember their user ID.

RESTful web service - HATEOAS

I have created a quite simple RESTful web service. It only supports the GET (=read) method, e.g.:
http://localhost/application/id/xyz
The corresponding information for this ID is queried from a data source and returned as JSON.
Now my question: (How) should I implement HATEOAS in this case? Does it even make sense? I understand that HATEOAS is reasonable when having a more complex structure. But in this case, there are no other resources I could link to. The client calls the web service with a certain ID and the server returns information.
Thank you!
As you've said "The client calls the web service with a certain ID" it sounds like you've written your client to visit a specific URL in your service which has the URL to visit generated by the client, i.e. your client application already knows it can visit http://localhost/application/id/xyz for the xyz ID.
If you'd like to leverage some of the power of HATEOAS and decouple yourself from this (slight) dependency, you could instead be querying http://localhost/application/id?query=xyz which could return a list of valid links (if any exist). That way you could change the format or structure of the linked URL without issues for your client (of course, you'd still be dependent on the query URL in some way).
However, as your usage is so simple, this sounds like overkill and unnecessary work so I'd suggest you don't need to worry about HATEOAS until you have a more complex system or clients :)
In HATEOS your return value is not an ID but a URL. Invoking that URL links you to the next resource in the web. Just like a web page containing links to other web pages.

RESTful HATEOAS Client Url

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.