MEAN Stack: Creating a RESTful Web service

Source: Internet
Author: User
Tags http post representational state transfer

This article on the personal blog address is a URL, welcome to taste.

Some time ago, the front-end data storage function in the Dtree project was made, the HTTP request was made on the original Ngcontroller, the backend received the request and then stored to MongoDB. The study proceeds are now recorded in this article. The general content of the rest of the concept of the introduction, and combined with some practical experience in project practice, the last RESTful Web service has been successfully developed (fog).

  1. REST
    REST (representational state Transfer) is a software design architecture style that defines a bunch of concepts that can effectively reduce business complexity with these abstract concepts and related rules. While the daily use of HTTP is the best practice of rest style, restful Web services is to use HTTP as an application layer protocol to comply with, rather than other (such as SOA) as the transport layer of the tool, and then on the HTTP build its own set of application layer protocol.

    When we type the Url/uri in the browser address bar is the rest provided resource (Resource) definition, and the resource is a concept in rest (concepts), when the browser makes a request, it wants to get a specific representation of a concept ( Representation), our common Web page is the specific representation of the resource. The concepts and principles of rest are defined in order to minimize the coupling between the service and the application using the service. Our principle of designing RESTful Web services only follows some of the principles of rest. The picture comes from "talking about rest", as we can see in the rest triangle diagram that the URL is the so-called noun (the location of the resource), and some HTTP methods are verbs, and JSON, XML Data Formats act as a concrete representation of the resource.

    The following is a brief overview of the 4 RESTful Web service fundamentals, excerpted from IBM's Rest-based Web Services Foundation

    Explicitly using the HTTP method

    When you design restful, you use 4 more polymorphic methods (POST, GET, PUT, DELETE) to implement CRUD operations for data storage. These verbs (POST, GET, PUT, and DELETE) have been defined by the HTTP protocol.

      • The HTTP get method is used to get a resource, which does not change the state of the resource, and may result in different results, but it does not have side effects (that is, no modification to the data stored on the source server).
      • The HTTP Delete method is used to delete resources although there are side effects, but the side effects of multiple invocations should be the same, that is, the deletion of the corresponding resource for the URI.
      • The HTTP post method is used to accept the created resource, and if the resource is already created on the server, the server response should be the 201 state that represents created and the URI of the resource, avoiding the POST request creating multiple copies of the same resource on the server.
      • The HTTP put method is used to create or update resources, and the side effects of multiple operations are the same as a put operation. The even if server does not have a put resource to create one, otherwise it can update existing resources.

    The result of these actions is that there must be expectations, there should be no semantic problems, and the typical example is that only get is used in the application to act as a method of all front-end interaction, and the result is that the behavior of some web crawlers inadvertently leads to server-side resource changes.

    No status

    The stateless state of the network transport makes each request independent and complete, allowing the request to be routed from one server to another without the state being reconciled. Of course the request is stateful, transferring most of the state maintenance responsibilities to the client application, which can save bandwidth and minimize server-side application state performance improvements.

    Public directory-structured URI

    A URI is a tree of subordinate and ancestor branches that are joined together on a node, which can visually express the interaction type and resource name, or the URI as an interface to the document description.

    The transport format uses data formats such as XML, JavaScript Object Notation (JSON), and so on

    These data formats enable services to be run on different platforms and devices and written in different languages.

  2. Ngresource
    The back-end data interaction at the front end has been using the $http service, this time Brother Siang education to learn to use Ngresource, advocating "keeping $http out of the controllers and leave that job to services "。 Using Ngresource doesn't have to care about the lower $http service, it helps us encapsulate a simpler way to send XHR requests.

    Ngresource provides a $resource service to interact with the restful back end. First we need to introduce angular-resource.js, and then build a factory method that returns the value of $resource (' URI ', params, methods) in it, so that a custom service is generated. This makes it possible to create a restful client with just a few lines of code, simplifying controllers.

  3. Code

    We first design node to accept the routing assignment when the front-end request is received, temporarily providing only the following CRUD operations for a single Dtree object.

    ///store‘/dtree‘, dtreeCtrl.createDTree);//createapp.get(‘/dtree/:dtree_id‘, dtreeCtrl.readDTree);//readapp.put(‘/dtree/:dtree_id‘, dtreeCtrl.updateDTree);//updateapp.delete(‘/dtree/:dtree_id‘, dtreeCtrl.deleteDTree); // delete

    We exposed the processing request API at Dtreectrl, which is handled as follows for the post operation.

    For get operations, we use DTREE_ID as _id for searching, calling the Mongoose API. Lean () Converts the result to plain JavaScript objects.

    Execute route get/dtree/:d tree_idexports.readdtree =function(req, res) {var checkid =new ObjectId (req.params.dtree_id); //storage to MongoDB pre-processing //. Dtree.findbyid (Checkid). Lean (). EXEC (function  (err, dtree) {if (err) {Console.log ( "Error: Readdtree:db failed to FindByID due to ', err); Res.send ({ ' success ': false,  ' err ' : Err}); }else{console.log ( ' Info:readDTree:DB FindByID successfully Dtree = ', dtree); //sent to the client for preprocessing //... res.send ({true, dtree:dtree}); } });}; 

    For the put operation, I previously wrote V for Versionkey, which can act as the version control flag for a database document, but the Mongoose. Update () method has some bugs, and the value of V is not modified after the operation, and the temporary workaround is through $inc: {key: Value} to set manually.

    Execute route put/dtree/:d tree_idexports.updatedtree =function  (req, res) {// Pre-storage to MongoDB //: Dtree.update ({ "_id": id}, {modifiedkey:modifieddata,  $inc: { __v: 1}}, functionif (err) {Console.log ( "Error:updatedtree : DB failed to update due to ', err); Res.send ({ ' success ': false,  ' err ' : Err}); }else{console.log ( ' Info:updateDTree:DB Updated successully Dtree '); Res.send ({ ' success ': true});});};   


    Delete operation is relatively straightforward.

     //execute Route delete/dtree/:d tree_ Idexports.deletedtree = function  (req, res) {Dtree.findbyidandremove (req.params.dtree_id, < Span class= "Hljs-keyword" >function (err, dropdtree) {if (err) { Console.log ( ' Error:deleteDTree:DB failed to delete due to ', err); Res.send ({ success ': false,  ' err ': err}); }else{console.log ( ' Info:deleteDTree:DB deleted successfully Dtree = ', dropdtree); Res.send ({ ' success ': true});}});     

    At this point, the backend has been established with a set of restful APIs to provide to client HTTP request calls. We first need to use the previously mentioned $resource service definition decision tree CRUD Operations Service Dtreecrudservice, where the URI uses the cors notation, in fact, there is no need to use/dtree/alone:d tree_id can also, This is the resource that accesses this machine. CORS (cross origin Resource sharing) is in contrast to the SOP (same Origin Policy, which refers to a document or script that can only access the server's own domain on the client, cannot get or modify the properties of the document of another domain), and it supports inter-domain requests. Nodejs opens cors through a call to Cors-dependent packages. If the browser side detects the appropriate settings, you can allow xhr for cross-domain access.

    $resource(‘http://localhost\\:4000/dtree/:dtree_id‘, {},{        ‘get‘: {            method:‘GET‘        },        update: {            method: ‘PUT‘ //a PUT request }, ‘delete‘: { method:‘DELETE‘ }});

    The method of HTTP operation is defined here, and the service can be invoked correctly by "injecting" the service into the controller.

    app.controller(‘createDTreeCtrl‘, [    ‘$scope‘,    ‘dtreeCrudService‘    function (        $scope,        dtreeCrudService    ) {    //...具体实现]);

    This is done by defining a crud method to divide the business logic.

    Upload decision tree data to backend for database$scope. Createdtreedata =function(){Data after the front-end processingvar data = someoperate (data); Console.log (' Info:createDtreeData:data = ', data); (data,function(RES) {if (res.success) {Console.log (' Info:createdtreedata:back-end successfully saved Dtree = ', data); }else{Console.log (' Error:createdtreedata:back-end failed to save Dtree due to ', res.err); } },function(Error) {Console.log ("Error:createDtreeData:Fail to create due to", Error);});Reading data$scope. Readdtreedata =function() {Dtreecrudservice.get ({dtree_id:' 54a4c0947752adcc1764f0d4 '},function(RES) {if (res.success) {Console.log ("Info:readdtreedata:back-end successfully read Dtree =", Res.dtree);}else{Console.log (' Error:readdtreedata:back-end failed to read dtree due to ', res.err); } },function(Error) {Console.log ("Error:readDtreeData:Fail to read due to", Error);});Update data$scope. Updatedtreedata =function() {The data is structured into JSON objects.var data = Somechange (data); Console.log (' Info:updateDtreeData:data = ', data); Dtreecrudservice.update ({dtree_id:data._id},data,function(RES) {if (res.success) {Console.log ("Info:updatedtreedata:back-end successfully update Dtree =", data);}else{Console.log (' Error:updatedtreedata:back-end failed to read dtree due to ', res.err); } },function(Error) {Console.log ("Error:updateDtreeData:Fail to update due to", Error);});//Delete the decision tree of an ID  $scope. Deletedtreedata = function  () { Dtreecrudservice.delete ({dtree_id:  $scope. Operate_dtreeid}, function (res) {if (res.success) {console.log (" Info:deletedtreedata:back-end successfully Delete Dtree "); }else{console.log ( ' Error:updatedtreedata:back-end failed to Read Dtree due to ', res.err); }}, function (Error) { Console.log ( "Error:deleteDtreeData:Fail to delete due to", Error);});    

    These 4 methods correspond to the request, which can be called using the ng-click instruction.

    The use of Ngresource's Crud method is so convenient that later modifications are especially handy.

    $resource (URL, [paramdefaults], [Actions], options);

    Referring again to the role of the Pramas parameter in this $resource method, the HTTP request method is overwritten when the parameter is not empty. For example $resource ("/dtree/:id", {ID: @dtreeID}, methods) This section of the resource service, our post data is {"DtreeID": 2333, "Dtreedata": YoYo }, this URL becomes/dtree/2333. And when there is no this @ symbol, the URL is a direct/dtree/dtree_id.

    Another thing is that our back-and-forth data is in JSON format, and JSON does not support looping structure, i.e. A.B = C; C.D = b; This data structure, but in front of the use of D3 drawing process, it is necessary to maintain this structure in order to update the image on the interface in real time. If you forcibly use $resource to pass, JavaScript converts the data to a JSON object and then reports TypeError errors.

    Then we need not panic, directly traverse the decision tree data to the loop structure to kill it.


The implementation of this function module is divided into front and back, and the backend node provides RESTful resource acquisition Api,angularjs to obtain resources in the front end using $resource for the encapsulation of HTT requests. This set of HTTP + CRUD Method + URLs is just the implementation of the rest part concept, and the real value of rest lies in the low-coupling design concept.

References:rest related
    1. Talking about rest
    2. Rest-based WEB service Foundation
    3. The concept and application of HTTP idempotent
    1. Simple-device-management-app
    2. Tv-traker
    3. Update operation cannot add "__v"
    4. $resource documents that seem to require FQ

MEAN Stack: Creating a RESTful Web service

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: 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.