0

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:

  1. What HTTP method should I used in this case?

  2. 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!

zhangjinzhou
  • 2,461
  • 5
  • 21
  • 46

3 Answers3

2

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.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • It seems I have to add a parameter to the service path therefore every resource (a row in database table) has a corresponding url. For example, when I want do operations on a record, I need to pass the unique ID as a parameter in the url. Is this right? – zhangjinzhou Oct 17 '17 at 23:20
  • @zhangjinzhou - That would be the RESTful way. Each URI for a GET, PUT or DELETE should represent a unique resource. – jfriend00 Oct 17 '17 at 23:22
  • Yes that is correct. And that is defined as an optional parameter in the URL. – Silencer310 Oct 17 '17 at 23:22
  • Thank you guys! One thing still confuse me is the difference between POST and PUT. Can I use PUT to create a new resource just like using POST, without specifying identifier? I can understand POST and GET are very different because payload and the way to call it. However POST and PUT are very confusing. – zhangjinzhou Oct 17 '17 at 23:33
  • @zhangjinzhou - Please read my answer again as this is all there. You only PUT to a specific resource URI. So, you have to have the resource URI already before you can PUT to it. If you want the server to create the resource URI, then you would always use POST. You don't POST to the end resource URI. You might POST to a DB resource and that POST would create a new resource within the DB and assign a resource identifier to it. For creating new resources, PUT requires the resource identifier to be specified by the client, POST requires the server to create the identifier for the new resource. – jfriend00 Oct 17 '17 at 23:36
  • @zhangjinzhou - Here's a couple examples: http://restcookbook.com/HTTP%20Methods/put-vs-post/ and https://restfulapi.net/rest-put-vs-post/ that should give you a more concrete idea for the difference between PUT and POST. – jfriend00 Oct 17 '17 at 23:42
  • @jfriend00 - Sorry I didn't make my question clear. You explained the USAGE of the two methods very well in your answer. However, I if I want use PUT to create a new resource without specifying identifier, will it allow me to do so? I have read a lot of articles but none of them explained why should we use the two methods differently. – zhangjinzhou Oct 17 '17 at 23:43
  • @zhangjinzhou - You should not attempt to use PUT to do that. You could obviously code your server to do whatever you want it to do, but that would be in violation of the REST principles. You should use POST if you are not specifying the new resource URI in the request. PUT specifies the URI to update or create. POST goes to a URI that does not specify the URI of the new resource and the server creates the new URI that will represent that resource. – jfriend00 Oct 17 '17 at 23:45
  • @jfriend00 - Let me try to explain it more clear. Based on my knowledge, GET and POST are different because you can't upload data as payload using GET. Does POST and PUT have difference in terms of their capability similar to this? – zhangjinzhou Oct 17 '17 at 23:45
  • @jfriend00 - I see! Now it is clear. I thought they have different capability. I really appreciate your patience and the perfect answer! – zhangjinzhou Oct 17 '17 at 23:47
  • @zhangjinzhou - You can code your server to do whatever you want with POST and PUT. It's a matter of whether you follow proper REST principles with the two. REST principles say that if you are updating a resource, you specify the resource ID in the URI and use PUT. If you are creating a new resource and letting the server create the new URI identifier for the new resource, you use POST to URI that does not contain a specific URI. If you are creating a new resource and letting the client pick the new URI to represent that resource, you use PUT to a URI that includes the new resource identifier. – jfriend00 Oct 17 '17 at 23:48
1

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

enter image description here - 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

sheplu
  • 2,937
  • 3
  • 24
  • 21
  • Thanks for your post. The different levels is very helpful! I understand that GET is usually not enough to build a API because you may want to upload a file or pass over a stream or something else. However, when creating/updating a resource with POST/PUT, I don't see any difference. – zhangjinzhou Oct 17 '17 at 23:28
  • Can't I use PUT to create a new resource just like using POST, without specifying identifier? – zhangjinzhou Oct 17 '17 at 23:36
  • It is clear now. I appreciate your answer and patience. Your post definitely answered my question. However I have accepted jfriend00's answer. I really want to accept yours if I could! – zhangjinzhou Oct 17 '17 at 23:53
0

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.

Silencer310
  • 862
  • 2
  • 8
  • 25