Example of using Node. js to implement RESTful API, node. jsrestful

Source: Internet
Author: User
Tags representational state transfer node server

Example of using Node. js to implement RESTful API, node. jsrestful

Basic RESTful concepts

REST (Representational State Transfer) describes an architecture-style network system that first appeared in Roy Fielding's doctoral thesis in 2000. In the REST service, application status and functions can be divided into various resources. Resources are made public to the client. The client can add, delete, and modify resources. Resource examples include application objects, database records, algorithms, and so on.

By abstracting resources, REST provides an API that is easy to understand and use. It uses URI (Universal Resource Identifier) to uniquely represent resources. The REST interface uses standard HTTP methods, such as GET, PUT, POST, and DELET, to transmit the status between the client and the server.

In the narrow sense, RESTful focuses on resources, resources represented by URLs, and operations on resources. Leonard Richard and Sam Ruby introduced the mixed architecture of the term REST-RPC in their book RESTful Web Services. REST-RPC Hybrid Web Services transfer data directly over HTTP instead of using envelope packaging methods, parameters, and data, which is similar to REST-style Web Services. However, it does not use standard HTTP methods to operate resources.

Compared with traditional RPC and SOA, RESTful is simpler and more direct and built on standard HTTP, making it very popular.

Node. javascript can simply implement a Web service with few codes, and it has a very active community. Through the excellent Node package management mechanism (NPM), it is very easy to get support for various extensions.

For simple application scenarios Node. implementing REST in js is a very suitable choice (there are many reasons to choose this or that technology stack. This article will not be involved in the debate on various languages and architectures, and our focus is simply simple ).

Application Example

The following describes how to quickly develop a RESTful service using Node. js using an App game ranking backend service.

When game players pass the game, the game clearance time (in seconds) value is submitted to the REST server. The server records and sorts the clearance records. You can view the TOP 10 game rankings.

The data format submitted by the game application is in JSON format, as shown below:

{

  "id": "aaa",

  "score": 9.8,

  "token": "aaa-6F9619FF-8B86-D011-B42D-00C04FC964FF"

};

Id is the user name entered by the user. token is used to distinguish different users and avoid duplicate IDs. score indicates the time (in seconds) required to pass the examination ).

You can use curl as the client to test the RESTful service.

The command to submit a game record is as follows:

Copy codeThe Code is as follows:
Curl-d "{\" cmd \ ": 1, \" record \ ": {\" id \ ": \" test11 \ ", \" score \ ": 29.8, \ "token \": \ "aaa \"} "http: // localhost: 3000/leaderboards

The syntax of this command is not only to add, delete, and modify REST in a narrow sense. We add a cmd command for it. In fact, we use the POST command as a JSON command to implement this service as REST-RPC.

The command format for deleting a game record is as follows:

curl -X DELETE http://localhost:3000/leaderboards/aaa

Or (using REST-RPC semantics)

curl -d "{\"cmd\":2,\"record\":{\"id\":\"test11\"}}" http://localhost:3000/leaderboards

View the TOP 10 commands as follows:

curl http://localhost:3000/leaderboards

In standard REST definitions, POST and PUT have different meanings. GET can distinguish a single resource or a list of resources. We have simplified this application. Both ADD and UPDATE use POST in a unified manner, and there is no distinction between a single resource and a list. The TOP 10 Data is directly returned.

Some preparations

Install Node. js

The version used in this article is v5.5.0.

Find a convenient IDE

The author of this article uses Sublime to tap the code, eclipse + nodeclipse to generate the Framework Code and debug it.

Basic HTTP server in Node. js

In Node, it is very easy to implement an HTTP server. Create an app. js file in the project root directory and write the following code:

var http = require("http");

 

http.createServer(function(request, response) {

 response.writeHead(200, {"Content-Type": "text/plain"});

 response.write("Hello World");

 response.end();

}).listen(3000);

Use Node. js to execute your script:node server.js

Open your browser and access http: // localhost: 3000/. Then, you will see a webpage with "Hello World.

Even if you do not fully understand Node, You can intuitively see that an http module is introduced through require, and then create an HTTP service object using createServer. After receiving the HTTP request from the client, we will call the provided function and write the returned page in the callback function.

Next, we will extend this simple application to a RESTful service.

Simple and intuitive RESTful services

Now we need to go beyond "hello world". We will modify the previous http callback function and return different content based on the request type.

The Code is as follows:

var server = http.createServer(function(req, res) {

  var result;

  switch (req.method) {

    case 'POST':

      break;

    case 'GET':

      break;

    case 'DELETE':

      break;

  }

});

You can obtain the request type through req. method.

1. Add and modify

The post request requires us to add or update records. The requested data can be obtained through callback.

The Code is as follows:

  var item = '';

      req.setEncoding('utf8');

      req.on('data', function(chunk) {

       item += chunk;

      });

      req.on('end', function() {    

       try {

         var command = JSON.parse(item);

         console.log(commandNaNd+ ';'+ command.record.id+ ':'+ command.record.score+ '('+ command.record.token+ ')');

         if (commandNaNd === CMD.UPDATE_SCORE){

           addRecord(command.record,result);

         }

         else if (commandNaNd === CMD.DEL_USE){

           db('leaderboards').remove({id:command.record.id});

         }

         res.end(JSON.stringify(result));

       }

       catch (err) {

         result.comment= 'Can\'t accept post, Error: '+ err.message;

         result.code= ErrCode.DataError;

         console.log(result.comment);

         res.end(JSON.stringify(result));

       }

      });

When the framework parses and reads data, it calls req. on ('data', function (chunk) provides the callback function. we record the request data in the item. Once there is data, we call item + = chunk, after the data is read, the Framework calls req. on ('end', function () callback, In the callback function, use JSON. parse restores the JSON data of the request to a Javascript object, which is a command object. commandNaNd can be used to distinguish between adding or deleting records.

Add or update a record in addRecord.

The Code is as follows:

function addRecord(record,result) {

  var dbRecord = db('leaderboards').find({ id: record.id });

  if (dbRecord){         

    if (dbRecord.token !== record.token){

      result.code= ErrCode.DataError;

      result.comment= 'User exist';

    }

    else{

      db('leaderboards')

       .chain()

       .find({id:record.id})

       .assign({score:record.score})

       .value();

      result.comment= 'OK, New Score is '+ record.score;

    }

  }

  else{

    db('leaderboards').push(record);

  }

}

After the command is executed, the returned data is written through res. end (JSON. stringify (result. The returned data is also a JSON string.

In this simple example, the lowdb (https://github.com/typicode/lowdb#license? Utm_source = ourjs.com ).

LowDB is a Node-based Pure Json file database. It does not require servers, and can be synchronized or asynchronously persisted to files. It can also be simply used as a memory database, which is very fast and simple. LowDB provides the Lo-Dash interface, which can be queried using methods similar to. find ({id: record. id. Through chain (), you can connect multiple operations to complete database search and update operations.

This simple database implementation, if the game only saves user records with high scores, can actually meet our application. For more complex applications, Node also provides various database connection modules, typically mongodb or mysql.

2. Return TOP 10

By querying the data in the database, first use. sortBy ('score '), take the first 10 data records, return them to the record set, convert JSON. stringify to a string, and return the data through res.

The Code is as follows:

       var records= [];

       var topTen = db('leaderboards')

         .chain()

         .sortBy('score')

         .take(10)

         .map(function(record) {

          records.push(record);

         })

         .value();

       res.end(JSON.stringify(records));

3. delete records

RESTful resource deletion IDs are generally carried in URLs, such as "http: // localhost: 3000/leaderboards/aaa". Therefore, var path = parse (req. url ). the pathname resolves the resource ID "aaa ".

The Code is as follows:

   case 'DELETE':

              result= {code:ErrCode.OK,comment: 'OK'};

              try {

                   var path = parse(req.url).pathname;

                   var arrPath = path.split("/");

                   var delObjID= arrPath[arrPath.length-1];

 

                   db('leaderboards').remove({id:delObjID});

                   res.end(JSON.stringify(result));

                   break;

              }

So far, we have implemented a RESTful service with basic functions that can be truly used.

In actual applications, the REST service may be more complex. One application may provide services with multiple resource URLs, or provide basic WEB service functions; or REST requests include file uploads.

In this way, our simple implementation is not enough.

Express framework

Express is a web application development framework based on the Node. js platform. It provides a series of powerful features to help you create various Web applications.

You can use eclipse + nodeclipse to generate the default express application framework. An express application is as follows:

var express = require('express')

 , routes = require('./routes')

 , user = require('./routes/user')

 , http = require('http')

 , path = require('path');

 

var app = express();

 

// all environments

app.set('port', process.env.PORT || 3000);

app.set('views', __dirname + '/views');

app.set('view engine', 'ejs');

app.use(express.favicon());

app.use(express.logger('dev'));

app.use(express.bodyParser());

app.use(express.methodOverride());

app.use(app.router);

app.use(express.static(path.join(__dirname, 'public')));

 

// development only

if ('development' == app.get('env')) {

 app.use(express.errorHandler());

}

 

app.get('/', routes.index);

app.get('/users', user.list);

 

http.createServer(app).listen(app.get('port'), function(){

 console.log('Express server listening on port ' + app.get('port'));

});

Express is a Web server implementation framework. Although we can't use pages or page rendering, as an example, we still keep the page generated by default and briefly explain it.

In the generated framework code, select view engine template as ejs. This is a JSP-like HTML Rendering template engine, app. get ('/', routes. index) indicates to route the HTTP "/" request to routes. index processing, routes. the index corresponds to the index in the project structure. js file processing, the content of which is as follows:

exports.index = function(req, res){ res.render('index', { title: 'Express' });};

This function calls the index in the corresponding view directory. the ejs template and pass {title: 'express '} to the ejs template. In the ejs template, you can use <% = title %> to obtain the imported json object.

Express framework implements RESTful services

First, we implement our own service class. In the routes subdirectory, create the leaderboards. js file. The file structure is roughly the operation function that defines the REST.

exports.fnList = function(req, res){

}; 

exports.fnGet = function(req, res){ 

};

exports.fnDelete = function(req, res){

}; 

exports.fnUpdate = function(req, res){

};

exports.fnAdd = function(req, res){ 

};

In the app. js file, you need to route the HTTP request to the corresponding function.

var leaderboards = require('./routes/leaderboards');

…

app.get('/leaderboards', leaderboards.fnList);

app.get('/leaderboards/:id', leaderboards.fnGet); 

app.delete('/leaderboards/:id', leaderboards.fnDelete); 

app.post('/leaderboards', leaderboards.fnAdd); 

app.put('/leaderboards/:id', leaderboards.fnUpdate); 

In this way, the standard Web Service requests are routed to leaderboards for processing. Because the request contains POST data, you can use

var bodyParser = require('body-parser');

// parse various different custom JSON types as JSON

app.use(bodyParser.json({ limit: '1mb',type: 'application/*' }));

Parse the JSON structure of the request and add it to req. body. Limit is used to prevent illegal data from occupying server resources. Normally, if JSON data is parsed, type should be defined as 'application/* + json'. In this application, to prevent some client requests from specifying a type, parse all input data into JSON data.

'Body-parser 'is a useful library for parsing various types of HTTP request data, including processing file uploads. For details, see https://www.npmjs.com/package/body-parser.

With this routing ing mechanism, we no longer need to consider URL and data parsing. We only need to specify routes and implement corresponding functions.

exports.fnList = function(req, res){

  var result= {code:ErrCode.OK,comment: 'OK'};

  try {

    var records= [];

    var topTen = db('leaderboards')

      .chain()

      .sortBy('score')

      .take(10)

      .map(function(record) {

       records.push(record);

       })

      .value();

    res.end(JSON.stringify(records));

  }catch (err) {

    result.comment= 'Can\'t get leaderboards, Error: '+ err.message;

    result.code= ErrCode.DataError;

    console.log(result.comment);

    res.end(JSON.stringify(result));

  }

  return;

}; 

For URLs similar to http: // localhost: 3000/leaderboards/aaa, express has been resolved to req. param and can be obtained through req. param ('id.

exports.fnDelete = function(req, res){

  var result= {code:ErrCode.OK,comment: 'OK'};

  try {

    var resID= req.param('id');

    db('leaderboards').remove(resID);

    res.end(JSON.stringify(result));

 

    console.log('delete record:'+ req.param('id'));

  }

  catch (err) {

    result.comment= 'Can\'t DELETE at '+ req.param('id')+ ', Error: '+ err.message;

    result.code= ErrCode.DelError;

    console.log(result.comment);

    res.end(JSON.stringify(result)); 

  }

}; 

After bodyParser. json () is used, the JSON data in the POST request has been parsed and put into req. body, which can be directly used in the code.

function processCmd(req, res){

  var result= {code:ErrCode.OK,comment: 'OK'}; 

  try{

    var command = req.body;

    console.log(req.bodyNaNd+ ';'+ req.body.record.id+ ':'+ req.body.record.score+ '('+ req.body.record.token+ ')');

    if (commandNaNd === CMD.UPDATE_SCORE){

      addRecord(command.record,result);

      console.log('add record:'+ command.record.id);

    }

    else if (commandNaNd === CMD.DEL_USE){

      db('leaderboards').remove({id:command.record.id});

      console.log('delete record:'+ command.record.id);

    }

    res.end(JSON.stringify(result));

  }

  catch (err) {

    result.comment= 'Can\'t accept post, Error: '+ err.message;

    result.code= ErrCode.DataError;

    console.log(result.comment);

    res.end(JSON.stringify(result));

  }

  return;

}

exports.fnUpdate = function(req, res){

  processCmd(req,res);

};

exports.fnAdd = function(req, res){ 

  processCmd(req,res);

};

The advantage of using express is that some details can be thrown to the framework for processing, and the code structure is easier to write clearly.

The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.