How to merge multiple API calls into one call in REST API - node.js

For instance, if I have an API call http://localhost:3006/send-message?email=abc#mysite.com&password=xxxxxx&count=4&location=US and another API call http://localhost:3006/cancel-request?email=abc#mysite.com&password=xxxxxx&count=2&usernames=abc,xyz.
So, can I merge these two calls into one by doing something like http://localhost:3006/send-message?email=abc#mysite.com&password=xxxxxx&count=4&location=US/cancel-request?count=2&usernames=abc,xyz. If Yes then how I can handle this in Node.js with express.

I'd suggest making these operations a POST instead of a GET. Then, you can have one URL for a multi-operation and you can have a JSON payload in the body that contains an array of operations and their parameters:
http://localhost:3006/multi-operation
With a JSON payload that parses to this:
[
{
operation: "send-message",
email: "abc#mysite.com",
password: "xxxxx",
count: 4,
location: "US"
},
{
operation: "cancel-request",
email: "abc#mysite.com",
password: "xxxxx",
count: 2,
usernames: ["abc","xyz"]
}
]
This would also only be sending sensitive information such as passwords in the body of the request which is generally considered safer than putting them in the URL (where they might get logged by various infrastructure).
Note: In a REST API design, a GET request is not supposed to have "side-effects". It's supposed to retrieve some resource. Calling it 0 times, 1 time or 10 times should have the same effect on the server/world. So, independent of the desire to specify multiple operations in one API call, neither of these operations should have been a GET operation anyway because they both have side effects (they cause some change to occur). So, these should likely be POST operations. There are lots of good articles on when to use GET, POST, PUT, PATCH, etc... in a REST API. If you're confused by this, you can start with these articles or find many others with a search:
https://restfulapi.net/http-methods/
https://www.restapitutorial.com/lessons/httpmethods.html

Related

How to correct paging by using top and skip in Azure Search?

According to this document Total hits and Page Counts, if I want to implements paging, I should combine skip and top in my query.
The following is my POST query
{
"count": true ,
"search": "apple",
"searchFields": "content",
"select": "itemID, content",
"searchMode": "all",
"queryType":"full",
"skip": 100,
"top":100
}
It should return something like from 100 --> 200
{
"#odata.context": "https://example.search.windows.net/indexes('example-index-')/$metadata#docs(*)",
"#odata.count": 1611,
"#search.nextPageParameters": {
"count": true,
"search": "apple",
"searchFields": "content",
"select": "itemID, content",
"searchMode": "all",
"queryType": "full",
"skip": 200
},
But it just return top 100 , not paging offset to 100
"#odata.context": "https://example.search.windows.net/indexes('example-index')/$metadata#docs(*)",
"#odata.count": 1611,
Is there any thing I should setup?
The short answer of how to implement paging (from this article): Set top to your desired page size, then increment skip by that page size on every request. Here is an example of how that would look with the REST API using GET:
GET /indexes/onlineCatalog/docs?search=*$top=15&$skip=0
GET /indexes/onlineCatalog/docs?search=*$top=15&$skip=15
GET /indexes/onlineCatalog/docs?search=*$top=15&$skip=30
The REST API documentation also covers how to implement paging, as well as the true purpose of #odata.nextLink and #search.nextPageParameters (also covered in this related question).
Quoting from the API reference:
Continuation of Partial Search Responses
Sometimes Azure Search can't return all the requested results in a single Search response. This can happen for different reasons, such as when the query requests too many documents by not specifying $top or specifying a value for $top that is too large. In such cases, Azure Search will include the #odata.nextLink annotation in the response body, and also #search.nextPageParameters if it was a POST request. You can use the values of these annotations to formulate another Search request to get the next part of the search response. This is called a continuation of the original Search request, and the annotations are generally called continuation tokens. See the example in Response below for details on the syntax of these annotations and where they appear in the response body.
The reasons why Azure Search might return continuation tokens are implementation-specific and subject to change. Robust clients should always be ready to handle cases where fewer documents than expected are returned and a continuation token is included to continue retrieving documents. Also note that you must use the same HTTP method as the original request in order to continue. For example, if you sent a GET request, any continuation requests you send must also use GET (and likewise for POST).
Note
The purpose of #odata.nextLink and #search.nextPageParameters is to protect the service from queries that request too many results, not to provide a general mechanism for paging. If you want to page through results, use $top and $skip together. For example, if you want pages of size 10, your first request should have $top=10 and $skip=0, the second request should have $top=10 and $skip=10, the third request should have $top=10 and $skip=20, and so on.
The follwing example is Get method without top.
GET Method
https://example.search.windows.net/indexes('example-content-index-zh')/docs?api-version=2017-11-11&search=2018&$count=true&$skip=150&select=itemID
The Result:
{
"#odata.context": "https://example.search.windows.net/indexes('example-index-zh')/$metadata#docs(*)",
"#odata.count": 133063,
"value": [ //skip value ],
"#odata.nextLink": "https://example.search.windows.net/indexes('example-content-index-zh')/docs?api-version=2017-11-11&search=2018&$count=true&$skip=150"
}
No matter I use post or get, onces I add $top=# the #odata.nextLink will not show in result.
Finally, I figure out although #odata.nextLink or #search.nextPageParameters will not show. But the paging is working, I have to count myself.

Custom update actions in RESTful Services

My API requires many different types of updates that can be performed by different types of roles. A ticket can have it's data updated, a ticket can be approved (which includes some information), a ticket can be rejected, a ticket can be archived (state that makes a ticket unable to be updated), etc.
I've recently started working as a backend developer and I really do not know what is the most correct approach to this situation but I've two ideas in mind:
A single update endpoint (e.g. /api/tickets/:id) that accepts an action field with the type of update that wants to be done to that file;
Multiple custom action endpoints (e.g. /api/tickets/:id/validate, /api/tickets/:id/accept, etc.)
Which one of those is the best approach to the situation when it comes to the REST architecture? If both are incorrect when it comes to REST, what would be the most correct approach? I couldn't really find any post on SO that answered my question so I decided to create my own. Thank you!
REST stands for Representational State Transfer, which means that the client and the server affect each other’s state by exchanging representations of resources.
A client might GET a representation of a ticket like this:
GET /api/tickets/123 HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 123,
"state": "new",
"archived": false,
"comments": []
}
Now the client can PUT a new representation (replacing it wholesale) or PATCH specific parts of the existing one:
PATCH /api/tickets/123 HTTP/1.1
Content-Type: application/json-patch+json
[
{"op": "replace", "path": "/state", "value": "approved"},
{"op": "add", "path": "/comments", "value": {
"text": "Looks good to me!"
}}
]
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 123,
"state": "approved",
"archived": false,
"comments": [
{"author": "Thomas", "text": "Looks good to me!"}
]
}
Note how the update is expressed in terms of what is to be changed in the JSON representation, using the standard JSON Patch format. The client could use the same approach to update any resource represented in JSON. This contributes to a uniform interface, decoupling the client from the specific server.
Of course, the server need not support arbitrary updates:
PATCH /api/tickets/123 HTTP/1.1
Content-Type: application/json-patch+json
[
{"op": "replace", "path": "/id", "value": 456}
]
HTTP/1.1 422 Unprocessable Entity
Content-Type: text/plain
Cannot replace /id.
Still, this might require more complexity on the server than dedicated operations like “approve”, “reject”, etc. You might want to use a library to implement JSON Patch. If you find that you need many custom actions which are hard to express in terms of a representation, an RPC architecture might suit you better than REST.
REST is all about resources. And the state of the resources should be manipulated using representations (such as JSON, XML, you name it) on the top of stateless communication between client and server.
Once URIs are meant to identify the resources, it makes sense to use nouns instead of verbs in the URI. And when designing a REST API over the HTTP protocol, HTTP methods should be used to indicate the action intended to be performed over the resource.
Performing partial updates
You could use the PATCH HTTP verb to perform partial updates to your resource. The PATCH request payload must contain set of changes to applied to the resource.
There are a couple of formats that can be used to describe the set of changes to be applied to the resource:
###JSON Merge Patch
It's defined in the RFC 7396 and can be applied as described below:
If the provided merge patch contains members that do not appear within the target, those members are added. If the target does contain the member, the value is replaced. Null values in the merge patch are given special meaning to indicate the removal of existing values in the target.
So a request to modify the status of a ticket could be like:
PATCH /api/tickets/1 HTTP/1.1
Host: example.org
Content-Type: application/merge-patch+json
{
"status": "valid"
}
###JSON Patch
It's defined in the RFC 6902 and expresses a sequence of operations to be applies to a target JSON document. A request to modify the status of a ticket could be like:
PATCH /api/tickets/1 HTTP/1.1
Host: example.org
Content-Type: application/json-patch+json
[
{
"op": "replace",
"path": "/status",
"value": "valid"
}
]
The path is a JSON Pointer value, as described in the RFC 6901.
Try to either
Deal with a single object -> api/v1/tickets/1
Deal with a list of objects -> api/v1/tickets/.
Then try to capture all actions as CRUD actions.
Create object(s) -> HTTP POST
Retreive object(s) -> HTTP GET
Update object(s) -> HTTP PATCH
Delete object(s) -> HTTP DELETE
And also:
Save object(s) entirely -> HTTP PUT
When you are changing statuses, and these are just attributes on a ticket. I would send a PATCH request, for instance. If I need to change the statues of ticket #1 to "rejected" I would send something like PATCH api/v1/tickets/1 with a payload like:
{
"status": "rejected"
}
REST has a lot of best practices but not everything is set in stone. Maybe this tutorial: https://restfulapi.net can help you?
Really it all comes down to a matter of taste. It is often observed in the industry to have the static parameters in the URL (eg: /tickets/update, /users/add, /admin/accounts) and the variable parameters in the query (eg: IDs, messages, names). It allows to have a fixed number of endpoints.
I see you're using NodeJS so you're probably using Express and in Express getting the url parameters and the body parameters are equally easy:
// supposing you're using a JSON-based API with body-parser for JSON parsing
app.get('/some/path/:someParam', (req, res) => {
console.log(req.params.someParam);
console.log(req.body.someOtherParam);
res.send();
}

Mongoose, ExpressJs - exposing mongo documents

Every example of using expressjs and mongoose are like that:
const contentTypes = await ContentType.find().sort({createdAt: -1});
res.json(contentTypes);
But in this scenario we are returning all document by REST api (even mongoose version field '_v'. I think it would be good practive to describe interface like this
export class ContentTypeEntry {
id: string;
name: string;
}
and convert mongoose type to this interface object and return this DTO. I just starting using nodejs ecosystem, so maybe in this ecosystem returning directly ORM objects is normal?
How are You dealing with moongose objects and REST endpoints?
I'm not entirely sure if I got the question right, but this is what my response object looks like-
// GET /api/products/1010
{
"meta": {
"type": "success",
"code": 200,
"message": "Retrieved product number 1010"
},
"data": {
"id": 1010,
"name": "Apple iPhone X",
"description: "Yada yada",
"price": 1000
}
}
This just separates the metadata and the actual returned data to make it easier for whoever is consuming the api to handle errors better. I also modify the JSON object to return only the required data and omit things like the version field from the response.
I think this is a great question, even if it's a bit broad. There are lots of frameworks that build on top of Node/Express (for example, LoopBack) to act as the glue between your data layer and your HTTP layer (REST, API, whatever you want to call it), deciding what you want to actually exist at a given endpoint. Happy to share other thoughts here if you have more specific questions.
You could also stay fairly lean and override the toJSON method of your Mongoose object (see this for an example). This is probably in line with your example of having an additional class that your object will conform to before being delivered to the end user, but personally I'd prefer to keep that within my object definition (the Mongoose model file).
I suppose at the end of the day, it's a question of how much control you need, how big the project is going to be and what its future needs will be. For microservices, you may find that Express + Mongoose and a couple of specific strategies will solve your concerns.

Which HTTP Method to Choose When Building Restful API

I am new to node.js and have my first node.js Restful API built in hapi.js framework. All the services do is basically doing database query. An example of the services is like this:
let myservice = {
method: "POST",
path: "/updateRule",
config: {
handler: (request, reply) => {
updateRule(request.payload)
.then((result) => {
reply(successResponse(request, result));
})
.catch((err) => reply(failResponse(request, err)).code(500));
},
validate: {
payload: {
ruleId: joi.number().required(),
ruleName: joi.string().required(),
ruleDesc: joi.string().required()
}
},
auth: "jwt",
tags: ["api", "a3i"]
},
}
updateRule(input): Promise<any> {
return new Promise((resolve, reject) => {
let query = `select a3i.update_rule(p_rul_id := ${input.ruleId}, p_rul_name := '${input.ruleName}', p_rul_desc := '${input.ruleDesc}')`;
postgresQuery(lbPostgres, query, (data, commit, rollback) => {
try {
let count = data.rows[0].update_rule.count;
if (count === 1) {
let ruleId = data.rows[0].update_rule.result[0];
let payload: SuccessPayload = {
type: "string",
content: `Rule ${ruleId} has been updated`
};
commit();
resolve(payload);
} else {
let thisErr = new Error("No rule can be found.");
thisErr.name = "4003";
throw thisErr;
}
}
catch (err) {
rollback();
if (err.name === "4003") {
reject(detailError(4003, err.message));
} else {
reject(detailError(4001, err.message));
}
}
}, reject);
});
}
As you can see, when the service is called, it evokes a database call (query) and updates specified row in database table. Similarly, I have other services named createRule/deleteRule creating/deleting records in database table. In my opinion, the difference between the services is doing different database query. I read this post PUT vs. POST in REST but couldn't see any difference of POST and PUT in my case.
Here are my questions:
What HTTP method should I used in this case?
Most of Restful API examples (for example https://www.codementor.io/olatundegaruba/nodejs-restful-apis-in-10-minutes-q0sgsfhbd) use the same URL with different HTTP methods to do different operations on same "resource", which in my opinion is usually a database table. What's the benefit of this architecture compared with my practice in which one URL only has one HTTP method and only do one type of operation?
I know this question does not refer to a problem and is not specific. Some people may give it a down-vote. But as a beginner I really want to know what's a typical Restful API and make sure my API is "best practice". Please help!
If the resource already exists and thus you have a specific URI to that exact resource and you want to update it, then use PUT.
If the resource does not exist yet and you want to create it and you will let the server pick the URI that represents that new resource, then use POST and the POST URI will be a generic "create new resource" URI, not a URI to a specific resource and it will create the URI that represents that resource.
You can also use PUT to create a new resource if the caller is going to create the resource URI that represents the new resource. In that case, you would just PUT to that new resource and, if a resource with that URI already exists, it would be updated, if not, it would be created.
You do not have to support both. You can decide to make your api work in a way that you just use one or the other.
In your specific case, an update of a specific row in your database that already exists would pretty much always be a PUT because it already exists so you're doing a PUT to a specific URI that represents that row.
What's the benefit of this architecture compared with my practice in which one URL only has one HTTP method and only do one type of operation?
It's really up to you how you want to present your API. The general concept behind REST is that you have several components:
resource identifier
data
method
In some cases, the method can be subsumed by GET, PUT, POST or DELETE so you just need the resource identifier, data and GET, PUT, POST or DELETE.
In other cases or other designs, the method is more detailed than can be expressed in just a PUT or POST, so you have a method actually in the URL in which case, you may not need the distinction between PUT and POST as much.
For example, an action might be "buy". While you could capture that in a POST where the method is implied by the rest of the URL, you may want to actually POST to a URL that has a method in it: /buy for clarity and then you may use that same endpoint prefix with other methods such as /addToCart, etc... It really depends upon what the objects are in your REST design and what operations you want to surface on them. Sometimes, the objects lends themselves to just GET, PUT, POST and DELETE and sometimes, you want more info in the URL as to the specific operation to be carried out on that resource.
If you want to be Rest compliant, you can just use Post and Get.
If you want to be Restfull, you need to base your method on the CRUD
Create -> Post
Read -> Get
Update -> Put or Patch
Delete -> Delete
About building a full API, using method on the same URL could be easier to build / understand. All queries about your user will be on the user url and not user/get, user/add, user/update ... It let you have the same functionality, without too much different URL.
When you build an API, you will want to have some logs, for stats analysis and other stuff. This way, if you split with your method, you can just have a filter to logs how many Post requests, or Get requests.
In fact, you could build an API only with Get requests too. But spliting with methods and URL is the best way to avoid complexes URL (or URL with too much action name) and to have an easiest way to log every requests going through your API
- List item
Level 1 is Rest
Level 2 is Restfull
Level 3 is Hateoas
You should find more informations inside some books or articles written by Martin Fowler
What I usually do is use "POST" for creating a new resource, and use "PUT" for updating an already existing resource.
For your second question, yes most API's use the same URL to do different things on the same resource. That could be because of security where you don't want to expose what you are doing in your URL's (/delete for example). Also, many frameworks generate an auto URL for a resource (Object Class), that is then differentiated on the request method. People just don't tend to use custom URL's for those.

should I pass query parameters in the url or in the payload?

Suppose I have a REST endpoint like this :
http://server/users/query
And I have parameters in my query : age, city, country
I want to do a GET request with those parameters.
Should I better pass the parameters in the url ? Or put something like this in the payload of my GET request.
"query": {
"age": "something",
"city": "something",
"country": "something"
}
On my understanding, you have a collection of users and you want to get a representation of it. You should consider query parameters to filter your collection, as following:
http://[host]/api/users?age=something&city=something&country=something
And avoid GET requests with a payload. See the quote from the RFC 7231:
A payload within a GET request message has no defined semantics;
sending a payload body on a GET request might cause some existing
implementations to reject the request.
From MDN: GET requests (typically) don't have bodies so use the query parameters or the path.
If you are making requests to a server you should instead read the documentation of it's API.

Resources