Set up your Express server, database connection and routes - ultimagriever/mean-apz GitHub Wiki
Create your MongoDB database with mLab
- Head to https://mlab.com/ and create a MongoDB database.
- Create a user with which to access the newly created database.
- Create a collection inside your database.
Create .env and .env.example files
Your .env
file will contain any sensitive environment-specific information, such as database connection info, any keys/secrets pertaining to your application and data that will vary between environments (development, QA, production).
In our example, we're only going to set our new database's connection string to our .env
.
echo 'MONGODB_URI=mongodb://user:password@ds[port].mlab.com:[port]/database_name' >> .env
We should also create an .env.example
file that will be committed to source control. This file will contain all variables that should be set in our application, but without values (obviously).
echo 'MONGODB_URI=' >> .env.example
Create server.js file
vi server.js
Require all necessary dependencies
var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var mongodb = require('mongodb');
var env = require('dotenv');
var ObjectID = mongodb.ObjectID;
Initiate your .env
file.
env.config({ silent: true });
Setting silent
to true
will make dotenv
fail silently. This will be important later on.
Set up your Express server.
var app = express();
app.use(express.static(__dirname + "/public")); // Set application root as /public
app.use(bodyParser.json()); // Set request and response data format as JSON
Create a database variable in the global scope so we can reuse the connection across routes.
var db; // Create outside database connection callback
Set up database connection options.
var options = {
options: {
server: {
auto_reconnect: true,
socketOptions: {
connectTimeoutMS: 3600000,
keepAlive: 3600000,
socketTimeoutMS: 3600000
}
}
}
}
Here, we're setting the connection timeout and lifetime to 1 hour and the server should attempt to reconnect if disconnected.
Create a database connection and start the server
mongodb.MongoClient.connect(process.env.MONGODB_URI, options, function(error, database) {
if (error) {
console.error(error);
process.exit(1);
}
db = database;
console.log("Database connection ready");
// Initialize app
var server = app.listen(process.env.PORT || 8080, function() {
var port = server.address().port;
console.log("App now running on port", port);
});
});
// Routes defined below.
The connection string will be stored in an environment variable. Once the database connection is ready, we'll start serving our application through port 8080 by default or a port we establish in the environment.
Run application
node server.js
You should see your application running.
Database connection ready.
App now running on port 8080
Set up your routes
In order to have our server communicate and manipulate the database, we have to set up routes to which we can request our server for data.
Express has a method for each HTTP verb (GET, POST, PUT, DELETE) to which we can set up our routes.
Configuring a route is as easy as
app.get('/route-name', (request, response) => {
console.log('GET /route-name');
});
Run your application, then, on a new console window or tab,
curl http://localhost:8080/route-name
You should see GET /route-name
echoed to your console, in the same window you started your server (not after curl
).
Set the MongoDB collections you wish to use in your application
In this example, we're going to use only one collection (akin to a MySQL table). We're going to declare it in our code.
const EMPLOYEE_COLLECTION = "employees";
For DRY purposes, let's define a standard error handler, should any errors occur (service being interrupted mid-request, database connection dying, etc.).
function handleError(response, reason, message, code) {
console.log("ERROR: " + reason);
response.status(code || 500).json({"error": message});
}
This way, should any error happen, we supply the server response, what caused the error, the error message to be displayed and the HTTP response code to be returned.
Let's get all our routes set up.
// GET /employees
app.get('/employees', function(request, response) {
db.collection(EMPLOYEE_COLLECTION).find({}).toArray(function(error, docs) {
if (error) {
handleError(response, error.message, "Failed to get employees"); // 500 Internal Server Error
} else {
response.status(200).json(docs); // 200 OK
}
});
});
// POST /employees
app.post('/employees', function(request, response) {
var newEmployee = request.body;
newEmployee.createDate = new Date();
if (!(request.body.name || request.body.age)) {
handleError(response, "Invalid user input", "Must provide name and age.", 400); // 400 Bad Request
}
db.collection(EMPLOYEE_COLLECTION).insertOne(newEmployee, function(error, doc) {
if (error) {
handleError(response, error.message, "Failed to create employee");
} else {
response.status(201).json(doc.ops[0]); // 201 Created
}
});
});
// GET /employees/:id
app.get('/employees/:id', function(request, response) {
db.collection(EMPLOYEE_COLLECTION).findOne({ _id: new ObjectID(request.params.id) }, function(error, doc) {
if (error) {
handleError(response, error.message, "Failed to get employee"); // 500 Internal Server Error
} else {
response.status(200).json(doc); // 200 OK
}
});
});
// PUT /employees/:id
app.put('/employees/:id', function(request, response) {
var updateDoc = request.body;
delete updateDoc._id;
db.collection(EMPLOYEE_COLLECTION).updateOne({ _id: new ObjectID(request.params.id) }, updateDoc, function(error, doc) {
if (error) {
handleError(response, error.message, "Failed to update employee data"); // 500 Internal Server Error
} else {
response.status(204).end(); // 204 No Content
}
});
});
// DELETE /employees/:id
app.delete('/employees/:id', function(request, response) {
db.collection(EMPLOYEE_COLLECTION).deleteOne({ _id: new ObjectID(request.params.id) }, function(error, result) {
if (error) {
handleError(response, error.message, "Failed to delete employee"); // 500 Internal Server Error
} else {
response.status(204).end(); // 204 No Content
}
});
});
Test your routes
npm start
curl -H "Content-Type: application/json" --data '{"name": "John Doe", "age": 25, "job": "JavaScript Full-Stack Developer"}' http://localhost:8080/employees
curl http://localhost:8080/employees
Initiate a Git repository and ignore node_modules
git init
echo "node_modules" >> .gitignore
Because node_modules
is a folder containing only third party dependencies and package.json
is already responsible for managing those dependencies and keeping them up to date, we're not adding it to our source control. Instead, every time we clone our repo somewhere else, we just need to run npm install
.
Also, if you're wont to create .env
files for each environment, go ahead, just be careful to not let them slip into source control.
echo '.env*' >> .gitignore
echo '!env.example' >> .gitignore
This way, all .env
files, except .env.example
, are ignored by git.
Next, tell git to track all files, then commit to source control. Git will automatically ignore any patterns listed under .gitignore
.
git add .
git commit -m "Create Express server, set up initial routing and add .gitignore file"
Next step: Install Bower, initiate bower.json and install front-end dependencies