Community Post

Building fullstack web app with sails.js and Angular2

HaiderMalik
👁️ 0 views
💬 comments

What is Sails.js ?

Sails is a Javascript framework designed to resemble the MVC architecture from frameworks like Ruby on Rails. It makes the process of building Node.js apps easier, especially APIs, single page apps and realtime features, like chat.

What we will Build ?

In this part we will build a rest api for blog.

Each user can create many blog posts.There is a one to many relationship between user and post. Each category has many posts,One to many relationship between category and post

Table of Contents

    Getting Started with Sails cli

    To install sails.js you must have installed Node.js on your machine.

    npm install sails -g

    You can create a new project with sails new projectName

    sails new blog-api --no-frontend

    We are going to create sails project without frontend code because we will build frontend part in Angular2 . I will discuss more about Angular2 in part2 .

    App Structure

    Click here to learn more about app structure of Sails.js. App Structure

    Connecting mongodb to sails.js

    we are going to use mongodb as a database.You can use any database to build your backend rest api. Sails provide more than 30 adapters like sails-mysql, sails-mongodb, sails-redis. Click here to read more about database adapters. Database Adapters To install sails-mongo adapter

    npm install --save sails-mongo

    Add connection configuration for mongodb in config/connections.js

    //config/connections.js
    mongodbServer: {
        adapter: 'sails-mongo',
        host: 'localhost',
        port: 27017,
        // user: 'username', //optional
        // password: 'password', //optional
        database: 'blog-api' //optional
      }

    Make sure you run mongodb from your terminal or command prompt. In first terminal you will have to run this command.

    mongod

    Open another terminal and run this command

    mongo

    Your mongodb will be running on port 27017. Create a database by running this command

    use blog-ap

    Add mongodb connection to models.js

    //config/models.js
    module.exports.models = { 
       connection: 'mongodbServer',
       migrate: 'alter'
    };

    Set default connection in development.js

    //config/env/development.js
    module.exports = {
    
      models: {
        connection: 'mongodbServer'
      }
    };

    Creating models

    Create a new file User.js in api/models

    
    module.exports = {
    
     tableName:"users",
    
      attributes: {
    
        first_name : { type: 'string', required: true },
    
        last_name : { type: 'string', required:true },
    
        age : { type  : 'integer'},
    
         posts:{
           collection: 'post',
           via:'user'
    
         }
      }
    };

    I have created one to many relationship between users and posts. I have defined posts collection in user model because we can populate all the posts for each user by using user.find().populate('posts') . It will return all the posts for each user.

    Create a new file Post.js in api/models

    
    module.exports = {
    
     tableName:"posts",
    
      attributes: {
    
        title : { type: 'string', required:true },
    
        content : { type: 'longtext' ,required:true },
    
        //Associations
        category : { model :'category', columnName:'category_id', required:true},
    
        user : { model :'user', columnName:'user_id', required:true},
      }
    };

    When we will create a new posts we also need to add id of category model and user model Create a new file Category.js in api/models

    module.exports = {
    
      tableName:"categories",
    
      attributes: {
    
        name : { type: 'string', unique: true, required: true },
    
        posts: {
          collection:'post',
          via:'category'
        }
      }
    };
    

    We can also populate all the posts for each category

    Defining Routes

    /**
     * Route Mappings
     * For more information on configuring custom routes, check out:
     * http://sailsjs.org/#!/documentation/concepts/Routes/RouteTargetSyntax.html
     */
    module.exports.routes = {
    
      //user
      'POST /user': 'UserController.create',
    
      //post
      'POST /post': 'PostController.create',
      'GET /posts': 'PostController.findAll',
      'GET /posts/:id': 'PostController.findOne',
      'DELETE /posts/:id': 'PostController.delete',
      'PUT /posts/:id': 'PostController.update',
    
    };

    Create new User

    To create new user .We need to create a new UserController.js file in api/controllers

    
    module.exports = {
      /**
       * It will create a new user .
       */
      create: function (req, res) {
    
        let firstName = req.param('first_name'),
            lastName = req.param('last_name'),
            age = req.param('age');
    
         if(!firstName){
           return res.badRequest({err:'Invalid first_name'});
         }
    
         if(!lastName){
           return res.badRequest({err:'Invlaid last_name'});
         }
    
        User.create({
         first_name : firstName,
         last_name : lastName,
         age:age
        })
        .then(_user => {
          if(!_user) return res.serverError({err:'Unable to create user'});
    
           return res.ok(_user); //to learn more about responses check api/responses folder
        })
        .catch(err => res.serverError(err.message));
      }
    };

    User.create() will return a promise. Click here to learn more about promises Promises .If you want to test this route you can use postman to test your rest-api. Postman is a chrome extension. If you have google chrome you can install postman very easily. We have defined an action method for each route.

    Let us create new PostController.js in api/controllers . This time I will create a new controller by using sails cli To create PostController.js run this command

    sails generate controller Post create findAll findOne delete update

    Create a new post

    
    module.exports = {
    
      /**
       * This method will create a new post for user
       */
      create: function (req, res) {
    
        let title = req.param('title'),
          content = req.param('content'),
          userId = req.param('user_id'), //original user_id from mongodb user model
          categoryName = req.param('category_name');
    
        if (!title) return res.badRequest({ err: 'Invalid post title field' });
        if (!content) return res.badRequest({ err: 'Invalid post content field' });
        if (!userId) return res.badRequest({ err: 'Invalid user_id field' });
        if (!categoryName) return res.badRequest({ err: 'Invalid category_name field' });
    
        Category.findOrCreate({ name: categoryName })
          .then(_category => {
    
            if (!_category) throw new Error('Unable to create category record');
            return _category;
    
          })
          .then(_category => {
    
            return Post.create({
              title,
              content,
              user: userId,
              category: _category.id
            });
    
          })
          .then(_post => {
            if (!_post) throw new Error('Unable to create new post');
            return res.json({ post: _post });
          })
          .catch(err => res.serverError(err.message));
      }
    }

    Update Post

    Sails cli already created a dummy or empty update method for us. Refactor existing update() in api/controllers/PostController.js

    /**
       * This method will update the post
       */
      update: function (req, res) {
    
        let title = req.param('title'),
          content = req.param('content'),
          userId = req.param('user_id'),
          categoryId = req.param('category_id'),
          postId = req.params.id;
    
        if (!postId) return res.badRequest({ err: 'post id is missing' });
    
        let post = {};
    
        if (title) {
          post.title = title;
        }
        if (content) {
          post.content = content;
        }
        if (userId) {
          post.user = userId;
        }
        if (categoryId) {
          post.category = categoryId
        }
    
        Post.update({ id: postId }, post)
          .then(_post => {
    
            if (!_post[0] || _post[0].length === 0) return res.notFound({ err: 'No post found' });
    
            return res.ok(_post);
    
          }).catch(err => res.serverError(err));
      },
    

    Delete Post

    Refactor existing delete() in PostController.js

    /**
       * This method will delete the post
       */
      delete: function (req, res) {
        let postId = req.params.id;
    
        if (!postId) return res.badRequest({ err: 'missing post_id field' });
    
        Post.destroy({ id: postId })
          .then(_post => {
            if (!_post || _post.length === 0) return res.notFound({ err: 'No post found in our record' });
            return res.ok(`Post is deleted with id ${postId}`);
          })
          .catch(err => res.serverError(err));
      },

    FindAll Posts

    To get all posts you need to write code in PostController.findAll() in api/controllers/PostController.js

      findAll: function (req, res) {
    
        Post.find()
          .populate('user')
          .populate('category')
          .then(_posts => {
    
            if (!_posts || _posts.length === 0) {
              throw new Error('No post found');
            }
            return res.ok(_posts);
    
          })
          .catch(err => res.serverError(err));
      },

    Find Single Post

    To get post by id you need to write code in PostController.findOne()

     /**
       * find single post based on id
       */
      findOne: function (req, res) {
    
        let postId = req.params.id;
    
        if (!postId) return res.badRequest({ err: 'missing post_id field' });
    
        Post.findOne({ id: postId })
          .populate('category')
          .populate('user')
          .then(_post => {
    
            if (!_post) return res.notFound({ err: 'No post found' });
    
            return res.ok(_post);
          })
          .catch(err => res.serverError(err));
      }

    Originally published at fullstackhour.com on April 3, 2017. In the next part we will create a frontend in Angular2 & Angular4.

    HaiderMalik

    3 posts

    Full-Stack Javascript Developer.

    Node.js , Sails.js , React.js , Redux, Angular2