# Express Beers
Ce tutoriel est basé sur le tutoriel de LostInBrittany Express-Beers
# Présentation
# Les objectifs
Ce tutoriel va vous permettre d'apprendre à construire des APIs en Javascript rapidement et facilement. Vous utiliserez le framework ExpressJS, avec des touches de base de données NoSQL (avec MongoDB).
# Organistion du tutoriel
Le tutoriel est divisé en 5 étapes qui sont les suivantes :
- Hello world
- Routage basique
- JSON beers
- Lancer la webapp
- Mongo beers
# Step 01 - Hello World !
# Initialize npm
First, create the directory for the project express-beers
mkdir express-beers
cd express-beers
Let's begin by initializing npm
npm init
Now we add ExpressJS to your dependencies by installing it with the --save
flag
npm install --save express
A suitable package.json
file is generated including the ExpressJS dependency:
{
"name": "express-beers",
"version": "1.0.0",
"description": "first ExpressJS API",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "@Steffy29",
"license": "MIT",
"dependencies": {
"express": "^4.17.1"
}
}
# Create a minimal Hello World express
Now we are going to create our first API server in the index.js
file.
Let's begin by requiring the express
module, who has all the routing defining functions we need for our API server,
and using it to create an app
object.
var express = require('express');
var app = express();
On this app
object we can now define routes. For each route we define the HTTP method and the URL path it answers to, and the callback function the application will call when a request with matching method and matching path is received.
app.get('/', function (req, res) {
console.log('Received request from', req.ip)
res.send('Hello World !');
});
So here we are saying that all the GET requests to the base URL of our server (path '/'
) are answered by this route, and the answer is given by the callback function: we send "Hello World !" back to the client.
Now we create a web server serving our application on the port 3000, and login the starting of the server.
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Listening at http://%s:%s', host, port);
});
# Let's test it
Let's start the API server:
node index.js
Listening at http://:::3000
And now go to 127.0.0.1:3000 in your browser and see the nice response.
Meanwhile in the console you should get something like:
node index.js
Listening at http://:::3000
Received request from 127.0.0.1
# Step 02 - Basic routing
# Getting the image files
Now we need to copy the img
folder from the root of this tutorial into the app
folder, as express will look for them there.
When done, you can proceed.
# Defining the routes
We are going to define the routes we need for our API application.
As we want to build a backend for front Beers applications, we need to define:
GET /beers
: the list of beers, with name, description, alcohol content and image URL for each beersGET /beer/<beerId>
: to get the detail of a beer
And we also want to serve as static files all the content of the public
folder, and all the content of the img
folder at the /img
path.
Let's begin by defining the routes on Express:
app.get('/beers', function (req, res) {
console.log('Received request for beers from', req.ip)
res.send('Hello beers');
});
app.get('/beer/:beerId', function (req, res) {
console.log('Received request for '+req.params['beerId']+' from', req.ip)
res.send('Hello beer '+req.params['beerId']);
});
And the two static files folders:
app.use('/img', express.static('img'));
app.use(express.static('public'));
# Step 03 - JSON beers
# Getting the beers files
Now we need to copy the beers folder from the root of this tutorial into the app folder, as express will look for them there.
When done, you can proceed.
# Reading beer list from JSON file
With node you read a JSON file simply by using require
:
var myData = require('./data.json');
We are going to use this technique to get the beer list info needed in the /beers
route:
var beerList = require('./beers/beers.json');
console.log("Beers", beerList)
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Listening at http://%s:%s', host, port);
});
So we have a beerList
variable that contains the info needed for the /beers
route.
Now we can modify the route to send back the beer list:
app.get('/beers', function (req, res) {
console.log('Received request for beers from', req.ip)
res.json(beerList);
});
# Getting beer details
Now we want to be able to serve the beer details using the /beer/:beerId
route.
The easiest way would be to load the right JSON file at each request and send it back to the client:
app.get('/beer/:beerId', function(req, res) {
console.log('Received request for ' + req.params['beerId'] + ' from', req.ip);
var beerDetails = require('./beers/' + req.params['beerId'] + '.json');
res.json(beerDetails);
});
# Step 04 - Serving the webapp
# Getting the webapp files
Now we need to copy the Angular Beers or the Polymer Beers web application into the app/public
folder, to get it served from the static express route.
For Angular Beers, you can simply get the step 09 of Angular Beers and copy it into public
. Then you go to localhost:3000/index.html
to see the main page of your app.
For the Polymer version copy the step 8 of Polymer Beers into public/app
and then copy the bower_components
folder into public
. Then you go to localhost:3000/app/index.html
to see the main page of your app.
In both cases, in order to be sure you're calling the Express server, delete the data
folder of the webapp, so you don't feel tempted to simply read your JSON files...
# Modify the webapp to call the express server
# Angular Beers
Now we need to modify the controllers of Angular Beers to call our new server instead of simply requesting the JSON files.
beers.service.ts
import {HttpClient} from "@angular/common/http";
@Injectable()
export class BeerService {
constructor(private httpClient : HttpClient) {
}
getBaseUrl() {
return 'http://localhost:3000/';
}
getBeers(): Observable<any> {
return this.httpClient.get<Beer>(this.getBaseUrl() + 'beers');
}
getBeer(beerId: String): Observable<any> {
return this.httpClient.get<Beer>(this.getBaseUrl() + 'beer/' + beerId);
}
}
# Polymer Beers
In beer-list
element, modify the iron-ajax
to to call our new server using the routes defined for express in index.js
instead of simply requesting the JSON files:
<iron-ajax
auto
url="/beers"
method='get'
params='{}'
handle-as="json"
on-response="gotBeers"
debounce-duration="300"></iron-ajax>
Same thing in beer-details
:
getUrl: function(id) {
return "/beer/"+id;
},
# Where are my pics ?
We still have a problem with the images' path. We could correct it by modifying the JSON... but let's do it in the express way, by adding a route specifically for that:
app.use('/beers/img', express.static('img'));
And now we can see our work on the browser:
# Step 05 - Mongo Beers
Let's say you already have your beers in a MongoDB database. Now we are going to replace our local JSON files with calls to MongoDB.
TIP
In order to do this step you need to have your beer data in a MongoDB database. How to do it is outside the scope of this tutorial, but if you only want to do a quicktest, you could:
- Install MongoDB (see http://mongodb.com/)
- Start the MongoDB daemon (usually with the command
mongo
) - Create new collection
beers
on databasetest
$ mongo
> db
test
> db.createCollection("beers")
{ "ok" : 1 }
> exit
bye
- Use
mongoimport
command line tool to import the detailed JSON datafiles
mongoimport --db test --collection beers beers/AffligemBlond.json
mongoimport --db test --collection beers beers/AffligemDubbel.json
...
# Adding the MongoDB driver dependency
For this step, we are going to use the official MongoDB NodeJS driver.
Use npm
to install the MongoDB Node.js driver:
npm install --save mongodb
And we get it added to the package.json
:
{
"name": "express-beers",
"version": "1.0.0",
"description": "first ExpressJS API",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "@Steffy29",
"license": "MIT",
"dependencies": {
"express": "^4.17.1",
"mongodb": "^3.2.6"
}
}
# Connecting to Mongo
Now in our index.js
we are going to get a MongoClient
variable:
var MongoClient = require('mongodb').MongoClient;
Connect using the MongoClient
to your running mongod
instance by specifying the MongoDB URI. For example, the following code connects to a MongoDB instance that runs on the localhost interface on port 27017 and switch to the beers
database.
var url = 'mongodb://localhost:27017/test';
MongoClient.connect(url, function(err, client) {
console.log("Connected correctly to MongoDB server.");
client.close();
});
# Ask for the beer list
Let's add a /beers
route, with a callback that connects to Mongo and recovers the beer list.
We are heavily using the power of async/await to make asynchronous code simple:
app.get("/beers", async function(req, res) {
console.log("Received request for beers from", req.ip);
let client;
try {
client = await MongoClient.connect(url);
const db = client.db(dbName);
var beerList = await db
.collection("beers")
.find()
.toArray();
res.json(beerList);
} catch (err) {
console.log(err.stack);
}
client.close();
});
# And about the beer details ?
Like for the beer list, we begin by adding a /beer/:beerId
route with an async
callback.
In the callback we connect to Mongo and find the beer corresponding to beerId
:
app.get("/beer/:beerId", async function(req, res) {
console.log(`Received request for ${req.params.beerId} from ${req.ip}`);
let client;
try {
client = await MongoClient.connect(url);
const db = client.db(dbName);
let beerId = req.params.beerId;
let beerList = await db
.collection("beers")
.find({ id: beerId })
.toArray();
let beer = beerList[0];
console.log(beer);
res.json(beer);
} catch (err) {
console.log(err.stack);
}
client.close();
});
# Solutions
# Step 01
index.js
file
var express = require('express');
var app = express();
app.get('/', function (req, res) {
console.log('Received request from', req.ip)
res.send('Hello World!');
});
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Listening at http://%s:%s', host, port);
});
# Step 02
index.js
file
var express = require('express');
var app = express();
app.get('/beers', function (req, res) {
console.log('Received request for beers from', req.ip)
res.send('Hello beers');
});
app.get('/beer/:beerId', function (req, res) {
console.log('Received request for '+req.params['beerId']+' from', req.ip)
res.send('Hello beer '+req.params['beerId']);
});
app.use('/img', express.static('img'));
app.use(express.static('public'));
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Listening at http://%s:%s', host, port);
});
# Step 03
index.js
file
var express = require('express');
var app = express();
app.get('/beers', function (req, res) {
console.log('Received request for beers from', req.ip)
res.json(beerList);
});
app.get('/beer/:beerId', function (req, res) {
console.log('Received request for '+req.param('beerId')+' from', req.ip)
var beerDetails = require('./beers/'+req.param('beerId')+'.json');
res.json(beerDetails);
});
app.use('/img', express.static('img'));
app.use(express.static('public'));
var beerList = require('./beers/beers.json');
console.log("Beers", beerList)
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Listening at http://%s:%s', host, port);
});
# Step 04
index.js
file
var express = require('express');
var app = express();
app.get('/beers', function (req, res) {
console.log('Received request for beers from', req.ip)
res.json(beerList);
});
app.get('/beer/:beerId', function (req, res) {
console.log('Received request for ' + req.params['beerId'] + ' from', req.ip)
var beerDetails = require('./beers/' + req.params['beerId'] + '.json');
res.json(beerDetails);
});
app.use('/beers/img', express.static('img'));
app.use('/img', express.static('img'));
app.use(express.static('public'));
var beerList = require('./beers/beers.json');
console.log("Beers loaded")
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Listening at http://%s:%s', host, port);
});
# Step 05
index.js
file
var express = require('express');
var app = express();
var assert = require('assert');
var MongoClient = require('mongodb').MongoClient;
app.get('/beers', async function (req, res) {
console.log('Received request for beers from', req.ip);
let client;
try {
client = await MongoClient.connect(url);
const db = client.db(dbName);
var beerList = await db.collection('beers').find().toArray();
res.json(beerList);
} catch(err) {
console.log(err.stack);
}
client.close();
});
app.get('/beer/:beerId', async function (req, res) {
console.log(`Received request for ${req.params.beerId} from ${req.ip}`);
let client;
try {
client = await MongoClient.connect(url);
const db = client.db(dbName);
let beerId = req.params.beerId;
let beerList = await db.collection('beers').find({id: beerId}).toArray();
let beer = beerList[0];
console.log(beer);
res.json(beer);
} catch(err) {
console.log(err.stack);
}
client.close();
});
app.use('/beers/img', express.static('img'));
app.use('/img', express.static('img'));
app.use(express.static('public'));
var url = 'mongodb://localhost:27017';
var dbName = 'test'
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Listening at http://%s:%s', host, port);
});