RESTful API best practices on endpoint design - api

Let's say I'd like to implement two functions:
Register for a course
Pay the course fee
I understood that I might have two RESTful API endpoints like this
register the course for the student:
send POST request to /myapp/api/students/{id}/courses
with request body like
{
"course_id": 26,
"is_discount": true,
"reg_date": "2020-04-23T18:25:43.511Z"
}
create payment record of the student for the course:
send POST request to /myapp/api/payment-records
with request body like
{
"student_id": 204,
"course_id": 26,
"amount": 500
}
My question is, how this can be done in one action (or within one transaction) from client side by just calling to one RESTful endpoint without separating them into two like the above? Because if one fails to make successful payment, due to network failure of card system, for example, then the course registered by the student should be rollbacked accordingly.
Or, should I do it like:
send POST request to /myapp/api/course-registration
with request body like this?
{
course: {
"course_id": 26,
"is_discount": true,
"reg_date": "2020-04-23T18:25:43.511Z"
},
payment: {
"record_id": 1,
"student_id": 204,
"course_id": 26,
"amount": 500
}
}

My question is, how this can be done in one action (or within one transaction) from client side by just calling to one RESTful endpoint without separating them into two like the above?
How would you do it on the web?
You'd have a web page with a form to collect all of the information you need from the student -- some fields might be pre-filled in, others might be "hidden" so that they aren't part of the presentation. When the form is submitted, the browser would collect all of that information into a single application/x-www-form-urlencoded document, and would include that document in a POST request that targets whatever URI was specified by the form.
Note that you might also have two smaller forms - perhaps part of the same web page, perhaps somewhere else, to do the registration and payment separately.
Two things to note about the target URI. The browser does not care what the spelling of the target-uri is; it's just going to copy that information into the HTTP request. But the browser does care if the target URI is the same as something that is available in its local cache; see the specification of invalidation in RFC 7234.
So a heuristic that you might use for choosing the target is to think about which cached document must be refreshed if the POST is successful, and use the identifier for that document as the target-uri.

Related

How to express this request as a RESTful API?

I am asked to write a small HTTP based service that will accept requests that look like this:
[
{ name: 'James Smith', address: '10 Lake Drive' }
{ name: 'Jones', phone_number: '999-123-4567' }
{ name: 'Mr. Lucas', address: 'Detroit, MI' }
]
(but with a larger number of requests) and to attempt to determine whether an account exists for each one, returning data that looks like this:
[
{ name: 'James Smith', address: '10 Lake Drive', account='123ABC' }
{ name: 'Jones', phone_number: '999-123-4567', account='Not Found' }
{ name: 'Mr. Lucas', address: 'Detroit, MI', account='654CBA' }
]
The client of this service (at least, the first client I know about) will use this data synchronously -- it cannot continue until it receives the account numbers back from the service. (The actual processing done to match up the specifications request items to the accounts is not important.)
I'm asked to provide a RESTful API to this service. The only way I can see to encapsulate this in a RESTful API is to create the concept of a "LookupRequestDocument" which contains one or more lookup requests. The client would POST this to a URI at \LookupRequests\, receive a server-generated URL for the entire request, and then use GET to poll that URL until the response is ready.
This feels uncomfortable to me for the following reasons:
I've created a new concept (the LookupRequestDocument "resource") solely to allow me to make the API RESTful -- it has no other existence in the problem statement.
I've introduced asynchronicity into what is otherwise a synchronous problem.
It seems more natural to me to POST the data to a URI like \DoMatches and get the completed results in the returned document. But this does not seem to meet my client's requirement that the API be RESTful.
Question: Is my encapsulation of the problem into a RESTful API the best way of "being RESTful" for this problem? Is my \DoMatches solution actually RESTful even though it does not involve resources as I understand them?
So it seems to that your LookUpRequests process is not RESTful. Its not a stateless transaction, it requires the information in the post to be stored and processed on the server then returned in a different request.
I would do the \DoMatches but are you really "POSTING" anything your "GETTING" information right ? so why wouldn't that be a GET request with the response being the answer/answers ?
Neither one is RESTful. This is RPC, pure and simple.
The RESTful approach would be treating each account as a resource, identified by an URI, and checking each one of them on a single request.
If you don't want to have multiple requests like that, you can have a higher level interface as a workaround, where you submit a list of URIs (mimetype text/uri-list) via POST and get a 207 Multi-Status with the equivalent responses.

Which resource should I use to keep my API RESTFul?

I'm building an API to allow the client of the API to send notifications to remind a user to update an Order status. So far, there are two notifications:
when the user hasn't marked the order as received;
when the user hasn't marked the order as done.
I want to build this API to make it simple to extend to other notifications related to the order, but keep a simple URI for the clients of this API.
How can I define my resources in order to keep my API RESTFul?
I was thinking about having one of these structures:
Option 1:
POST: /api/ordernotification/receive/{id}
POST: /api/ordernotification/complete/{id}
Option 2 (omit the status from the resource and post it instead):
POST: /api/ordernotification/?id={id}&statusID={statusID}
EDIT
Option 2.1 (keeping an articulated URI, as suggested by #Jazimov):
POST: /api/ordernotification/{statusID}/{id}.
Which option is more appropriate? Is there any advantage that one option has over the other? Or are there any other option I haven't thought of?
I would go with something along these lines
POST /api/order/1234/notifications/not-received
POST /api/order/1234/notifications/not-completed
Which can later be accessed via
GET /api/order/1234/notifications/not-received
GET /api/order/1234/notifications/not-completed
Or
GET /api/order/1234/notification/8899
There's no real limitation on how semantically rich a URI can be, so you might as well take advantage of that and be explicit.
If I understand you correctly, you have two types of ordernotifications: those for notifying receive and those for notifying complete. If those are two separate data models then I think nesting them is a good idea (i.e. a table called ReceiveOrderNotification and CompleteOrderNotification). If that's the case then you may want to expose two different endpoints entirely, such as POST /api/receiveordernotification and POST /api/completeordernotification.
But I don't think that's the best you can do, given so many overlapping similarities there probably are between order notifications. Now, option 2 is more like a GET, since you're using query parameters, so with your first option let's collapse them into this:
POST: /api/ordernotification/
and then pass it some JSON data to create the notifications
{
"orderId": "orderId",
"userId": "userId",
"prompt": "not marked received/not marked done"
}
I also removed the /{id} because when you POST you create a brand new thing and the id has not been created yet, usually. Even if the client is creating an id and sending it to the API it is a good practice to leave it open so your API can handle creating a new, unique resource in its own way.
This is RESTful is because a POST creates a resource ordernotification with certain data points. Your first option made actions a resource in themselves but that's probably not represented in any data model in your backend. To be as RESTful as possible, your API endpoints should represent the database domains (tables, collections, etc). Then you let your controllers choose what service methods to use given the data sent in the request. Otherwise REST endpoints expose all the logic up front and get to be a long list of unmaintainable endpoints.
I think, to update status of already inserted records, your endpoint should be PUT instead of POST.
You can use
PUT: /api/ordernotification/:id/status/
with clients json data
{
"status": "your_status"
}
according to request data, endpoint should update the record.

Efficiency of RESTful APIs

I'm currently creating an application (let's say, notes app, for instance - webapplication + mobile app). I wanted to use RESTful API here, so I read a lot about this topic and I found out there's a lot of ambiguity over there.
So let's start at the beginning. And the beginning in REST is that we have to first request the / (root), then it returns list of paths we can further retrieve, etc, etc. Isn't this the the first part where REST is completely wasteful? Instead of rigid paths, we have to obtain them each time we want to do something. Nah.
The second problem I encountered was bulk operations. How to implement them in REST? Let's say, user didn't have access to the internet for a while, made a few changes and they all have to be made on server as well. So, let's say user modified 50 notes, added 30 and removed 20. We have to make 100 separate requests now. A way to make bulk operations would be very helpful - I saw this stackoverflow topic: Patterns for handling batch operations in REST web services? but I didn't found anything interesting here actually. Everything is okay as long as you want to do one type of operation on one type of resources.
Last, but not least - retrieving whole collection of items. When writing an example app I mentioned - notes app - you probably want to retrieve all collection of items (notes, tags, available notes colors, etc...) at once. With REST, you have to first retrieve list of item links, then fetch the items one by one. 100 notes = over 100 requests.
Since I'm currently learning all this REST stuff, I may be completely wrong at what I said here. Anyway, the more I read about it, the more gruesome it looks like for me. So my question finally is: where am I wrong and/or how to solve problems I mentioned?
It's all about resources. Resources that are obtained through a uniform interface (usually via URI and HTTP methods).
You do not have to navigate through root every time. A good interface keeps their URIs alive forever (if they go stale, they should return HTTP Moved or similar). Root offering pathways to navigate is a part of HATEOAS, one of Roy Fieldings defined architectural elements of REST.
Bulk operations are a thing the architectural style is not strong on. Basically nothing is stopping you to POST a payload containing multiple items to a specific resource. Again, it's all up to what resource you are using/offering and ultimately, how your server implementation handles requests. Your case of 100 requests: I would probably stick with 100 requests. It is clean to write and the overhead is not that huge.
Retrieving a collection: It's about resources what the API decides to offer. GET bookCollection/ vs GET book/1 , GET/book/2 ... or even GET book/all. Or maybe GET book/?includeDetails=true to return all books with same detail as GETting them one-by-one.
I think that this link could give you interesting hints to design a RESTful service: https://templth.wordpress.com/2014/12/15/designing-a-web-api/.
That said, here are my answers to your questions:
There is no need to implement a resource for the root path. With this, I think that you refered to HATEOS. In addition, no link within the payload is also required. Otherwise you can use available formats like Swagger or RAML to document your RESTful service. This show to your end users what is available.
Regarding bulk operations, you are free to use methods POST or PATCH to implement this on the list resource. I think that these two answers could be helpful to you:
REST API - Bulk Create or Update in single request - REST API - Bulk Create or Update in single request
How to Update a REST Resource Collection - How to Update a REST Resource Collection
In fact, you are free to regarding the content you want for your methods GET. This means the root element managed by the resources (list resource and element resource) can contain its hints and also the ones of dependencies. So you can have several levels in the returned content. For example, you can have something like this for an element Book that references a list of Author:
GET /books
{
"title": "the title",
(...)
"authors": [
{
"firstName": "first name",
"lastName": last name"
}, {
(...)
},
(...)
]
}
You can notice that you can leverage query parameters to ask the RESTful service to get back the expected level. For example, if you want only book hints or book hints with corresponding authors:
GET /books
{
"title": "the title",
(...)
}
GET /books?include=authors
{
"title": "the title",
(...)
"authors": [
{
"firstName": "first name",
"lastName": last name"
}, {
(...)
},
(...)
]
}
You can notice that you can distinguish two concepts here:
The inner data (complex types, inner objects): data that are specific to the element and are embedded in the element itself
The referenced data: data that reference and correspond other elements. In this case, you can have a link or the data itself embedded in the root element.
The OData specification addresses such issue with its feature "navigation links" and its query parameter expand. See the following links for more details:
http://www.odata.org/getting-started/basic-tutorial/ - Section "System Query Option $expand"
https://msdn.microsoft.com/en-us/library/ff478141.aspx - Section "Query and navigation"
Hope it helps you,
Thierry

Defining Status Codes

I am building a wrapper for a 3rd party api (email suite) inside of a web application, accessible internally and via an own api. The methods take, for example, an email-address and a subscription list as a parameter and return a result code.
So basically I want to:
Define status codes to display different states of success/failure.
For example successes:
new contact created
new contact created AND optin mail sent
new contact created AND coupon sent
existing contact subscribed
existing contact subscribed AND coupon sent
and so on..
All of these cases are basically the category 2xx OK, but have to trigger different user feedback messages, that's why I'm unhappy with using the HTTP status codes. Using pure HTTP status codes doesn't give feedback detailed enough and defining a) additional status codes or b) completely custom status codes feels so random.
So, what is the best practice to go here?
This answer suggests that I should always use the standard HTTP status codes and if they do not apply, my design is wrong. How would I distinguish the difference, without using additional logic and api calls on the client side?
The purpose of HTTP status codes is to convey the status of the HTTP operation - was it successful, unauthorized, pending, misconfigured, whatever. In all your described cases, the requested operation was successful - everything went as planned. So the most likely status code is 200 OK or 201 CREATED for ALL those cases.
Additional domain-specific statuses should not be forcefully hammered into HTTP statuses. Just return an additional field in your response. For example:
POST http://www.example.com/users
{
name : "The User",
email : "email#theuser.com"
}
Response would contain:
201 CREATED
{
status : "Optin mail sent",
timestamp : "...",
...
}
This keeps a cleaner separation of concerns and improves extensibility.
How would I distinguish the difference, without using additional logic and api calls on the client side?
Use meaningful response bodies. The status code is just that. You don't want to create a new HTTP status code for each new combination of results.
So for your first three scenarios:
HTTP/1.1 201 Created
...
{
contact_created: "true",
optin_mail_sent: "true",
coupon_sent: "true",
}
You need some display logic on the client side any way (e.g. from 254 ContactYesOptInNoCouponYes to the appropriate notifications), so the response body seems the most sensible and extensible way possible.

REST API design of a resource whose properties are not editable by the client

What's the best way to handle resource properties which must be modified/updated through another method that is not exposed to the API consumer?
Examples:
Requesting a new token to used for X. The token must be generated following a specific set of business rules/logic.
Requesting/refreshing the exchange rate of a currency after the old rate expires. The rate is for informational purposes and will be used in subsequent transactions.
Note that in the above two examples, the values are properties of a resource and not separate resources on their owns.
What's the best way to handle these types of scenarios and other scenarios where the API consumer doesn't have control of the value of the property, but needs to request a new one. One option would be to allow a PATCH with that specific property in the request body but not actually update the property to the value specified, instead, run the necessary logic to update the property and return the updated resource.
Lets look at #1 in more detail:
Request:
GET /User/1
Response:
{
"Id": 1,
"Email": "myemail#gmail.com",
"SpecialToken": "12345689"
}
As the consumer of the API, I want to be able to request a new SpecialToken, but the business rules to generate the token are not visible to me.
How do I tell the API that I need a new/refreshed SpecialToken with in the REST paradigm?
One thought would be to do:
Request:
PATCH /User/1
{
"SpecialToken": null
}
The server would see this request and know that it needs to refresh the token. The backend will update the SpecialToken with a specific algorithm and return the updated resource:
Response:
{
"Id": 1,
"Email": "myemail#gmail.com",
"SpecialToken": "99999999"
}
This example can be extended to example #2 where SpecialToken is an exchange rate on resource CurrencyTrade. ExchangeRate is a read only value that the consumer of the API can't change directly, but can request for it to be changed/refreshed:
Request:
GET /CurrencyTrade/1
Response:
{
"Id": 1,
"PropertyOne": "Value1",
"PropertyTwo": "Value2",
"ExchangeRate": 1.2
}
Someone consuming the API would need a way to request a new ExchangeRate, but they don't have control of what the value will be, it's strictly a read only property.
You're really dealing with two different representations of the resource: one for what the client can send via POST / PUT, and one for what the server can return. You are not dealing with the resource itself.
What are the requirements for being able to update a token? What is the token for? Can a token be calculated from the other values in User? This may just be an example, but context will drive how you end up building the system.
Unless there were a requirement which prohibited it, I would probably implement the token generation scenario by "touching" the resource representation using a PUT. Presumably the client can't update the Id field, so it would not be defined in the client's representation.
Request
PUT /User/1 HTTP/1.1
Content-Type: application/vnd.example.api.client+json
{
"Email": "myemail#gmail.com"
}
Response
200 OK
Content-Type: application/vnd.example.api.server+json
{
"Id": 1,
"Email": "myemail#gmail.com",
"SpecialToken": "99999999"
}
From the client's perspective, Email is the only field which is mutable, so this represents the complete representation of the resource when the client sends a message to the server. Since the server's response contains additional, immutable information, it's really sending a different representation of the same resource. (What's confusing is that, in the real world, you don't usually see the media type spelled out so clearly... it's often wrapped in something vague like application/json).
For your exchange rate example, I don't understand why the client would have to tell the server that the exchange rate was stale. If the client knew more about the freshness of the exchange rate than the server did, and the server is serving up the value, it's not a very good service. :) But again, in a scenario like this, I'd "touch" the resource like I did with the User scenario.
There are many approaches to that. I'd say the best one is probably to have a /User/1/SpecialToken resource, that gives a 202 Accepted with a message explaining that the resource can't be deleted completely and will be refreshed whenever someone tries to. Then you can do that with a DELETE, with a PUT that replaces it with a null value, and even with a PATCH directly to SpecialToken or to the attribute of User. Despite what someone else mentioned, there's nothing wrong with keeping the SpecialToken value in the User resource. The client won't have to do two requests.
The approach suggested by #AndyDennie, a POST to a TokenRefresher resource, is also fine, but I'd prefer the other approach because it feels less like a customized behavior. Once it's clear in your documentation that this resource can't be deleted and the server simply refreshes it, the client knows that he can delete or set it to null with any standardized action in order to refresh it.
Keep in mind that in a real RESTful API, the hypermedia representation of user would just have a link labeled "refresh token", with whatever operation is done, and the semantics of the URI wouldn't matter much.
I reckon you should consider making SpecialToken a resource, and allow consumers of the api to POST to it to retrieve a new instance. Somehow, you'll want to link the User resource to a SpecialToken resource. Remember, one of the central tenets of REST is that you should not depend on out-of-band information so if you want to stay true to that you'll want to investigate the possibility of using links.
First, let's look at what you've got:
Request:
GET /User/1
Accept: application/json
Response:
200 OK
Content-Type: application/json
{
"Id": 1,
"Email": "myemail#gmail.com",
"SpecialToken": "12345689"
}
While this response does include the SpecialToken property in the object, because the Content-Type is application/json will not actually mean anything to clients that aren't programmed to understand this particular object structure. A client that just understands JSON will take this as an object like any other. Let's ignore that for now. Let's just say we go with the idea of using a different resource for the SpecialToken field; it might look something like this:
Request:
GET /User/1/SpecialToken
Accept: application/json
Response:
200 OK
Content-Type: application/json
{
"SpecialToken": "12345689"
}
Because we did a GET, making this call ideally shouldn't modify the resource. The POST method however doesn't follow those same semantics. In fact, it may well be that issuing a POST message to this resource could return a different body. So let's consider the following:
Request:
POST /User/1/SpecialToken
Accept: application/json
Response:
200 OK
Content-Type: application/json
{
"SpecialToken": "98654321"
}
Note how the POST message doesn't include a body. This may seem unconventional, but the HTTP spec doesn't prohibit this and in fact the W3C TAG says it's all right:
Note that it is possible to use POST even without supplying data in an HTTP message body. In this case, the resource is URI addressable, but the POST method indicates to clients that the interaction is unsafe or may have side-effects.
Sounds about right to me. Back in the day, I've heard some servers had problems with POST messages without a body, but I personally have not had a problem with this. Just make sure the Content-Length header is set appropriately and you should be golden.
So with that in mind, this seems like a perfectly valid way (according to REST) to do what you're suggesting. However, remember before when I mentioned the bits about JSON not actually having any application level semantics? Well, this means that in order for your client to actually send a POST to get a new SpecialToken in the first place, it needs to know the URL for that resource, or at least how to craft such a URL. This is considered a bad practice, because it ties the client to the server. Let's illustrate.
Given the following request:
POST /User/1/SpecialToken
Accept: application/json
If the server no longer recognizes the URL /User/1/SpecialToken, it might return a 404 or other appropriate error message and your client is now broken. To fix it, you'll need to change the code responsible. This means your client and server can't evolve independently from each other and you've introduced coupling. Fixing this however, can be relatively easy, provided your client HTTP routines allow you to inspect headers. In that case, you can introduce links to your messages. Let's go back to our first resource:
Request:
GET /User/1
Accept: application/json
Response:
200 OK
Content-Type: application/json
Link: </User/1/SpecialToken>; rel=token
{
"Id": 1,
"Email": "myemail#gmail.com",
"SpecialToken": "12345689"
}
Now in the response, there's a link specified in the headers. This little addition means your client no longer has to know how to get to the SpecialToken resource, it can just follow the link. While this doesn't take care of all coupling issues (for instance, token is not a registered link relation,) it does go a long way. Your server can now change the SpecialToken URL at will, and your client will work without having to change.
This is a small example of HATEOAS, short for Hypermedia As The Engine Of Application State, which essentially means that your application discovers how to do things rather than know them up front. Someone in the acronym department did get fired for this. To wet your appetite on this topic, there's a really cool talk by Jon Moore that shows an API that makes extensive use of hypermedia. Another nice intro to hypermedia is the writings of Steve Klabnik. This should get you started.
Hope this helps!
Another thought just occurred to me. Rather than model a RefreshToken resource, you could simply POST the existing special token to a RevokedTokens collection that's associated with this User (assuming that only one special token is allowed per user at a given time).
Request:
GET /User/1
Accept: application/hal+json
Response:
200 OK
Content-Type: application/hal+json
{
_links: {
self: { href: "/User/1" },
"token-revocation": { href: "/User/1/RevokedTokens" }
},
"Id": 1,
"Email": "myemail#gmail.com",
"SpecialToken": "12345689"
}
Following the token-revocation relation and POSTing the existing special token would then look like this:
Request:
POST /User/1/RevokedTokens
Content-Type: text/plain
123456789
Response:
202 Accepted (or 204 No Content)
A subsequent GET for the user would then have the new special token assigned to it:
Request:
GET /User/1
Accept: application/hal+json
Response:
200 OK
Content-Type: application/hal+json
{
_links: {
self: { href: "/User/1" },
"token-revocation": { href: "/User/1/RevokedTokens" }
},
"Id": 1,
"Email": "myemail#gmail.com",
"SpecialToken": "99999999"
}
This has the advantage of modeling an actual resource (a token revocation list) which can effect other resources, rather than modeling a service as a resource (i.e., a token refresher resource).
How about a separate resource which is responsible for refreshing the token within the User resource?
POST /UserTokenRefresher
{
"User":"/User/1"
}
This could return the refreshed User representation (with the new token) in the response.