Best Way to Write Rest Api in Javascript 2018
Create a REST API in Node.js with MongoDB on Alibaba Cloud
By Alex Mungai Muchiri, Alibaba Cloud Tech Share Author. Tech Share is Alibaba Cloud's incentive program to encourage the sharing of technical knowledge and best practices within the cloud community.
MongoDB is designed to scale and offers superior performance compared to conventional relational databases. Specifically, the NoSQL model on which Mongo is based solves some very important challenges associated with SQL schemas. They include:
- Impeccable handling of large sets of unstructured, structured, or rapidly-changing data structures.
- It is agile and allows iteration of schemas quickly.
- Perfectly-suited for flexible object-oriented programming.
- It is easy to scale-out across geographically distributed systems.
Accordingly, choosing MongoDB as the backend for your mobile application is a wise consideration. Notably, scaling with the number of users is important, and so is being able to iterate the database to accept varying data structures. Rather than using rows and columns, MongoDB stores data in documents thus allowing room for structural changes. On the whole, Mongo scalability is three-tier:
- Cluster Scale: database distribution across hundreds of nodes across data centers.
- Performance: perform more than 100,000+ R/W ops per second with strict latency
- Data scale: sustain more than 1 billion documents
In this article, we are going to explore how to create a powerful REST API in Node.js with MongoDB. Server configuration with Mongo is quite easy, all you need is have your Alibaba Cloud Elastic Compute Service (ECS) instance ready for work. In our case, we will be using Ubuntu 16.04 as our operating system.
Install MongoDB on Alibaba Cloud ECS
Installing MongoDB is simple:
Package Name | Description |
mongodb-org | A metapackage that will automatically install the four component packages listed below. |
mongodb-org-server | Contains the mongod daemon and associated configuration and init scripts. |
mongodb-org-mongos | Contains the mongos daemon. |
mongodb-org-shell | Contains the mongo shell. |
mongodb-org-tools | Contains the following MongoDB tools: mongoimport bsondump, mongodump, mongoexport, mongofiles, mongorestore, mongostat, and mongotop. |
The mongodb-org-server
package provides an initialization script that starts mongod with the /etc/mongod.conf
configuration file.
Use this link and follow the instructions to install MongoDB on ECS Ubuntu Server: https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/
After installation, we can now proceed to build our simple REST API
REST APIs
REST is an acronym for Representational State Transfer. REST APIs are very popular these days and are used to handle the server-side of both web and mobile applications. In fact, most large internet companies have at least deployed some REST APIs such as the Google calendar API. Once a database is built, you can use APIs to deliver data and content to applications with ease. They represent how a server responds to and accepts requests to allow for CRUD processes. This tutorial involves building a simple API to post questions, post answers, as well as vote and remove answers on the scalable MongoDB. Key to a successful implementation of the project is structuring the routes correctly. In that case, routes will be programmed to:
- Analyze posted questions
- Read, create, edit and remove answers
- Upvote or downvote answers
In this example, the following will be applied.
Development environment
This project uses the following tools:
- Plain JavaScript
- Node.js
- Express (JS framework)
- MongoDB (Database)
- Yarn (package management)
- Visual Studio Code as editor
- Postman (to test API endpoints)
Dependencies
The dependency packages used:
- Parser (parses the body of incoming endpoint requests)
- Express (activates the application)
- Nodemon (restarts server to effect changes)
- Mongoose (simplifies MongoDB interactions through object data models)
- Morgan (a middleware to log HTTP requests)
- Eslint with Airbnb (it is an extension to help creation of high quality code)
Summary of the Tutorial
This example involves the following tasks:
- Using express to create API routes
- Modelling API data
- Contacting MongoDB using Mongoose
- Cleaning up and testing the API using Postman
Building API routes Using Express
The Basics
To make development simple, install nodemon and add the script to the package.json package
- Create a basic web server using express (express has a tutorial for this process)
- Ensure that the express middleware is set to be flexible
- Include a body parser to handle requests
- Incorporate the parser in the express middleware
Creating Routes for Questions
- In the server, create a file to store routes
- Include both POST and GET routes to find questions and add new
- For specific questions, create a GET route.
router.get('/', (req, res) => { res.json({ response: 'a GET request for LOOKING at questions' }); }); router.post('/', (req, res) => { res.json({ response: 'a POST request for CREATING questions', body: req.body }); }); router.get('/:qID', (req, res) => { res.json({ response: `a GET request for LOOKING at a special answer id: ${req.params.qID}` }); });
Answer Routes
- The first step is to install the Morgan HTTP requests logger. The package will help to analyze requests for you.
- Next, create a POST route to accept answers.
- Next, include PUT and DELETE to allow editing and deleting of answers
- Create a POST route for upvoting and downvoting answers (we shall use a simple vote in this tutorial)
router.post('/:qID/answers', (req, res) => { res.json({ response: 'a POST request for CREATING answers', question: req.params.qID, body: req.body }); }); router.put('/:qID/answers/:aID', (req, res) => { res.json({ response: 'a PUT request for EDITING answers', question: req.params.qID, answer: req.params.aID, body: req.body }); }); router.delete('/:qID/answers/:aID', (req, res) => { res.json({ response: 'a DELETE request for DELETING answers', question: req.params.qID, answer: req.params.aID, body: req.body }); }); router.post('/:qID/answers/:aID/vote-:dec', (req, res) => { res.json({ response: 'a POST request for VOTING on answers', question: req.params.qID, answer: req.params.aID, vote: req.params.dec, body: req.body }); });
Error Handlers
It is almost impossible to avoid errors in any application. In this example, we shall set up the error handlers in the following steps:
- The middleware will act as our 'error-catcher'.
- After catching error 404, use the middleware to pass it to a custom handler that responds with JSON response format (otherwise, use the 500 as shown below)
- Set up a validation middleware to allow error upvoting or downvoting.
app.use((req, res, next) => { const err = new Error('Not Found'); err.status = 404; next(err); }); app.use((err, req, res, next) => { res.status(err.status || 500); res.json({ error: { message: err.message } }); });
Use Mongoose to Connect to MongoDB
Choose the Data Model for the API
It is very critical that the data types chosen for storage in MongoDB have the right structures and relationships expressed clearly. Mongoose will act as our gateway to the MongoDB. We shall use it to create schemas that will accept JSON data format. The best approach for our case is to use question objects that have answer properties. Nonetheless, it is noteworthy to have in mind that Mongo documents have a maximum number of storage units and thus answers to a question are not unlimited.
Create Schemas
- Depending on your chosen parent-children structure, create appropriate schema on Mongoose
- Use your schemas to build a model
const AnswerSchema = new Schema({ text: String, createdAt: { type: Date, default: Date.now }, updatedAt: { type: Date, default: Date.now }, votes: { type: Number, default: 0 } }); const QuestionSchema = new Schema({ text: String, createdAt: { type: Date, default: Date.now }, answers: [AnswerSchema] }); const Question = mongoose.model('Question', QuestionSchema);
Incorporate Sorting and Voting into the Function
- Priority is given to the newest answers
- Include a storage option for votes in the answer schema
- Instruct Mongoose to pre-sort all answers while saving
- Use the parent method to have answers referenced to the question parent document
- Avoid using arrow functions in the specification
const sortAnswers = (a, b) => { if (a.votes === b.votes) { return b.updatedAt - a.updatedAt; } return b.votes - a.votes; }; QuestionSchema.pre('save', function (next) { this.answers.sort(sortAnswers); next(); }); AnswerSchema.method('update', function (updates, callback) { Object.assign(this, updates, { updatedAt: new Date() }); this.parent().save(callback); }); AnswerSchema.method('vote', function (vote, callback) { if (vote === 'up') { this.votes += 1; } else { this.votes -= 1; } this.parent().save(callback); });
Link the API to MongoDB
You are about to tackle the most difficult challenge in my opinion. Take a good look at the Mongoose documents at this juncture.
Error Handling
- In this case, we shall use the param method to have callbacks for qID and aID routes.
- The method allows error identification when a question or answer is not available in the database.
router.param('qID', (req, res, next, id) => { Question.findById(id, (err, doc) => { if (err) return next(err); if (!doc) { err = new Error('Document not found'); err.status = 404; return next(err); } req.question = doc; return next(); }); }); router.param('aID', (req, res, next, id) => { req.answer = req.question.answers.id(id); if (!req.answer) { err = new Error('Answer not found'); err.status = 404; return next(err); } return next(); });
Getting the Questions Routes Ready
- This will find questions in your Mongo database using a GET route.
- It will return the appropriate questions.
- It will also post new questions in JSON format to the database using a POST route.
- Include a GET route for a single question.
router.get('/', (req, res, next) => { Question.find({}).sort({ createdAt: -1 }).exec((err, questions) => { if (err) return next(err); res.json(questions); }); }); router.post('/', (req, res) => { const question = new Question(req.body); question.save((err, question) => { if (err) return next(err); res.status(201); res.json(question); }); }); router.get('/:qID', (req, res) => { res.json(req.question); });
Routes to Update Answers
- The POST execution to create answers is straightforward: the method involves pushing the answer to the question document and saving it as JSON format.
- User the update method to allow answer updating by returning the new JSON input.
- Accordingly, use the remove method when using the DELETE route to remove answers.
- For voting, we use a POST route embedded on the middleware to save votes in the vote method.
The example below illustrates this operation:
router.post('/:qID/answers', (req, res, next) => { req.question.answers.push(req.body); req.question.save((err, question) => { if (err) return next(err); res.status(201); res.json(question); }); }); router.put('/:qID/answers/:aID', (req, res, next) => { req.answer.update(req.body, (err, result) => { if (err) return next(err); res.json(result); }); }); router.delete('/:qID/answers/:aID', (req, res) => { req.answer.remove(err => { req.question.save((err, question) => { if (err) return next(err); res.json(question); }); }); }); router.post( '/:qID/answers/:aID/vote-:dec', (req, res, next) => { if (req.params.dec.search(/^(up|down)$/) === -1) { const err = new Error(`Not possible to vot for ${req.params.dec}!`); err.status = 404; next(err); } else { req.vote = req.params.dec; next(); } }, (req, res, next) => { req.answer.vote(req.vote, (err, question) => { if (err) return next(err); res.json(question); }); } );
Great! Now our REST API looks all set for consumption. We are now going to get into the next phase
Cleaning Up and Testing the Endpoints
Testing the API
The simplest way to test the functionality of all endpoints is to use Postman. You can use a Chrome extension or download the desktop application. Whatever your choice, that's fine, I personally like the Chrome extension. Postman is simple to use and allows HTTP tests. You can also set up an automated test if you don't want to do it manually.
Cross-Origin Resource Sharing
CORS has been restricted for security reasons. Basically, the method allows domain resource access by a browser. Consequently, we need to have a middleware to allow API consumption by domains involving the following steps:
- The header should have access to all origins
- Enable HTTP requests
app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); res.header( 'Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept' ); if (req.method === 'Options') { res.header('Access-Control-Allow-Methods', 'PUT, POST, DELETE'); return res.status(200).json({}); } });
Get the Front-end Working
Your API is all set to connect with all types of front ends. The process is as simple as using the proper header and route to post, get, put or delete.
Conclusion
REST API is a fantastic tool that can be used to setup very scalable back-end microservices. We have used Mongoose in this project to implement a simple API on MongoDB, a scalable open source database. Get your mobile application running on MongoDB with Alibaba Cloud. I hope you enjoyed this article.
-
Alex
53 posts | 7 followers
Follow
You may also like
Comments
-
Alex
53 posts | 7 followers
Follow
Related Products
-
ApsaraDB for MongoDB
A secure, reliable, and elastically scalable cloud database service for automatic monitoring, backup, and recovery by time point
Learn More -
OpenAPI Explorer
OpenAPI Explorer allows you to call an API through its web interface or WebCLI, and view the entire process.
Learn More -
API Gateway
API Gateway provides you with high-performance and high-availability API hosting services to deploy and release your APIs on Alibaba Cloud products.
Learn More -
Database for FinTech Solution
Leverage cloud-native database solutions dedicated for FinTech.
Learn More
Best Way to Write Rest Api in Javascript 2018
Source: https://www.alibabacloud.com/blog/create-a-rest-api-in-node-js-with-mongodb-on-alibaba-cloud_593851
0 Response to "Best Way to Write Rest Api in Javascript 2018"
Publicar un comentario