Open an empty directoy
Open a terminal and run npm init -y
. This will generate a package.json
Install express: npm install express --safe
. This will generate a package-lock.json and a folder called node-modules
Create an index.js
const express = require ( "express" ); //load express library
const app = express (); //express app initializing
Create a hello world program:
const express = require ( "express" ); //load express library
const app = express (); //express app initializing
//petition get to the root directory, 2nd param is callback function
app. get ( "/" , ( reequest , response ) => {
//we have to set what we're going to do with response and request
return response. send ( "Hello world!" ); //prints hello world
});
//Port listening the inbound traffic
app. listen ( 3000 , () => {
console. log ( "App running on http://localhost:3000" );
});
Create a new folder called store (for databases)
Continue developing the app to read data from a json file:
const express = require ( "express" ); //load express library
const fs = require ( "fs" ); //library fileSystem for access information stored
const app = express (); //express app initializing
//petition get to the root directory, 2nd param is callback function
app. get ( "/" , ( request , response ) => {
//we have to set what we're going to do with response and request
return response. send ( "Hello world!" ); //prints hello world
});
//Create an endpoint
app. get ( "/todos" , ( request , response ) => {
//To read the file we stored on store directory with utf-8 encoding
//Last parameter is the callback function
fs. readFile ( "./store/todos.json" , "utf-8" , ( err , data ) => {
//Handling errors
if (err) {
return response. status ( 500 ). send ( "Something went wrong :(" ); //http code 500 (error) with a special message
} //the next code will not execute
//We are parsing data to JSON because data is actually a string
const todos = JSON . parse (data);
return response. json ({ todos: todos }); //we return a list like the todos.json
});
});
//Port listening the inbound traffic
app. listen ( 3000 , () => {
console. log ( "App running on http://localhost:3000" );
});
Now check the localhost:3000/todos url
8. Download Postman
9. Create a get petition to the localhost:3000/todos url
10. Remember that express treats const as strings always. Types are very important so make sure your types are correct.
11. Add modify functionality:
const express = require ( "express" ); //load express library
const fs = require ( "fs" ); //library fileSystem for access information stored
const app = express (); //express app initializing
//petition get to the root directory, 2nd param is callback function
app. get ( "/" , ( request , response ) => {
//we have to set what we're going to do with response and request
return response. send ( "Hello world!" ); //prints hello world
});
//Create an endpoint
app. get ( "/todos" , ( request , response ) => {
//To read the file we stored on store directory with utf-8 encoding
//Last parameter is the callback function
fs. readFile ( "./store/todos.json" , "utf-8" , ( err , data ) => {
//Handling errors
if (err) {
return response. status ( 500 ). send ( "Something went wrong :(" ); //http code 500 (error) with a special message
} //the next code will not execute
//We are parsing data to JSON because data is actually a string
const todos = JSON . parse (data);
return response. json ({ todos: todos }); //we return a list like the todos.json
});
});
//To complete todos on the list
app. put ( "/todos/:id/complete" , ( request , response ) => {
const id = request.params.id; //The id of the todo
//function that finds a todo by its id
const findTodoById = ( todos , id ) => {
//go through the items of the todos list
for ( let i = 0 ; i < todos. length ; i ++ ) {
if (todos[i].id === parseInt (id)) {
//parseInt necessary because express treats const as strings by default
//if the element's id coincides
return i;
}
}
return - 1 ; //if not found
};
//To change the value on the file
fs. readFile ( "./store/todos.json" , "utf-8" , ( err , data ) => {
//Handling errors
if (err) {
return response. status ( 500 ). send ( "Something went wrong :(" ); //http code 500 (error) with a special message
} //the next code will not execute
//We are parsing data to JSON because data is actually a string
const todos = JSON . parse (data);
const todoIndex = findTodoById (todos, id);
if (todoIndex == - 1 ) {
return response. status ( 404 ). send ( "File not found" );
}
return response. json (todos[todoIndex]);
});
}); //quick request to mark a todo
//Port listening the inbound traffic
app. listen ( 3000 , () => {
console. log ( "App running on http://localhost:3000" );
});
Add save to a file functionality:
const express = require ( "express" ); //load express library
const fs = require ( "fs" ); //library fileSystem for access information stored
const app = express (); //express app initializing
//petition get to the root directory, 2nd param is callback function
app. get ( "/" , ( request , response ) => {
//we have to set what we're going to do with response and request
return response. send ( "Hello world!" ); //prints hello world
});
//Create an endpoint
app. get ( "/todos" , ( request , response ) => {
//To read the file we stored on store directory with utf-8 encoding
//Last parameter is the callback function
fs. readFile ( "./store/todos.json" , "utf-8" , ( err , data ) => {
//Handling errors
if (err) {
return response. status ( 500 ). send ( "Something went wrong :(" ); //http code 500 (error) with a special message
} //the next code will not execute
//We are parsing data to JSON because data is actually a string
const todos = JSON . parse (data);
return response. json ({ todos: todos }); //we return a list like the todos.json
});
});
//To complete todos on the list
app. put ( "/todos/:id/complete" , ( request , response ) => {
const id = request.params.id; //The id of the todo
//function that finds a todo by its id
const findTodoById = ( todos , id ) => {
//go through the items of the todos list
for ( let i = 0 ; i < todos. length ; i ++ ) {
if (todos[i].id === parseInt (id)) {
//parseInt necessary because express treats const as strings by default
//if the element's id coincides
return i;
}
}
return - 1 ; //if not found
};
//To change the value on the file
fs. readFile ( "./store/todos.json" , "utf-8" , ( err , data ) => {
//Handling errors
if (err) {
return response. status ( 500 ). send ( "Something went wrong :(" ); //http code 500 (error) with a special message
} //the next code will not execute
//We are parsing data to JSON because data is actually a string
let todos = JSON . parse (data); //let allow to modify the content (different from const)
const todoIndex = findTodoById (todos, id);
if (todoIndex == - 1 ) {
return response. status ( 404 ). send ( "File not found" );
}
todos[todoIndex].complete = true ; //we put the value as true
//we write changes to the file with todos data being stringify (converted back to)
fs. writeFile ( "./store/todos.json" , JSON . stringify (todos), () => {
return response. json ({ status: "ok" });
});
});
}); //quick request to mark a todo
//Port listening the inbound traffic
app. listen ( 3000 , () => {
console. log ( "App running on http://localhost:3000" );
});
Now we apply a filter:
const express = require ( "express" ); //load express library
const fs = require ( "fs" ); //library fileSystem for access information stored
const app = express (); //express app initializing
//petition get to the root directory, 2nd param is callback function
app. get ( "/" , ( request , response ) => {
//we have to set what we're going to do with response and request
return response. send ( "Hello world!" ); //prints hello world
});
//Create an endpoint
app. get ( "/todos" , ( request , response ) => {
//filter all the complete todos ones
const showPending = request.query.showpending;
//To read the file we stored on store directory with utf-8 encoding
//Last parameter is the callback function
fs. readFile ( "./store/todos.json" , "utf-8" , ( err , data ) => {
//Handling errors
if (err) {
return response. status ( 500 ). send ( "Something went wrong :(" ); //http code 500 (error) with a special message
} //the next code will not execute
//We are parsing data to JSON because data is actually a string
const todos = JSON . parse (data);
//if the query paramenter showpending is not equals to the string "1"
if (showPending !== "1" ) {
return response. json ({ todos: todos }); //we return a list like the todos.json
} else {
//filter them (return only those which are not completed)
return response. json ({
todos: todos. filter (( t ) => {
return t.complete === false ;
}),
});
}
});
});
//To complete todos on the list
app. put ( "/todos/:id/complete" , ( request , response ) => {
const id = request.params.id; //The id of the todo
//function that finds a todo by its id
const findTodoById = ( todos , id ) => {
//go through the items of the todos list
for ( let i = 0 ; i < todos. length ; i ++ ) {
if (todos[i].id === parseInt (id)) {
//parseInt necessary because express treats const as strings by default
//if the element's id coincides
return i;
}
}
return - 1 ; //if not found
};
//To change the value on the file
fs. readFile ( "./store/todos.json" , "utf-8" , ( err , data ) => {
//Handling errors
if (err) {
return response. status ( 500 ). send ( "Something went wrong :(" ); //http code 500 (error) with a special message
} //the next code will not execute
//We are parsing data to JSON because data is actually a string
let todos = JSON . parse (data); //let allow to modify the content (different from const)
const todoIndex = findTodoById (todos, id);
if (todoIndex == - 1 ) {
return response. status ( 404 ). send ( "File not found" );
}
todos[todoIndex].complete = true ; //we put the value as true
//we write changes to the file with todos data being stringify (converted back to)
fs. writeFile ( "./store/todos.json" , JSON . stringify (todos), () => {
return response. json ({ status: "ok" }); //we return ok as it has been modified
});
});
}); //quick request to mark a todo
//Port listening the inbound traffic
app. listen ( 3000 , () => {
console. log ( "App running on http://localhost:3000" );
});
To add items via post requests:
const express = require ( "express" ); //load express library
const fs = require ( "fs" ); //library fileSystem for access information stored
const app = express (); //express app initializing
//for adding items with post requests
app. use (express. json ());
app. use (express. urlencoded ({ extended: true }));
//petition get to the root directory, 2nd param is callback function
app. get ( "/" , ( request , response ) => {
//we have to set what we're going to do with response and request
return response. send ( "Hello world!" ); //prints hello world
});
//Create an endpoint
app. get ( "/todos" , ( request , response ) => {
//filter all the complete todos ones
const showPending = request.query.showpending;
//To read the file we stored on store directory with utf-8 encoding
//Last parameter is the callback function
fs. readFile ( "./store/todos.json" , "utf-8" , ( err , data ) => {
//Handling errors
if (err) {
return response. status ( 500 ). send ( "Something went wrong :(" ); //http code 500 (error) with a special message
} //the next code will not execute
//We are parsing data to JSON because data is actually a string
const todos = JSON . parse (data);
//if the query paramenter showpending is not equals to the string "1"
if (showPending !== "1" ) {
return response. json ({ todos: todos }); //we return a list like the todos.json
} else {
//filter them (return only those which are not completed)
return response. json ({
todos: todos. filter (( t ) => {
return t.complete === false ;
}),
});
}
});
});
//To complete todos on the list
app. put ( "/todos/:id/complete" , ( request , response ) => {
const id = request.params.id; //The id of the todo
//function that finds a todo by its id
const findTodoById = ( todos , id ) => {
//go through the items of the todos list
for ( let i = 0 ; i < todos. length ; i ++ ) {
if (todos[i].id === parseInt (id)) {
//parseInt necessary because express treats const as strings by default
//if the element's id coincides
return i;
}
}
return - 1 ; //if not found
};
//To change the value on the file
fs. readFile ( "./store/todos.json" , "utf-8" , ( err , data ) => {
//Handling errors
if (err) {
return response. status ( 500 ). send ( "Something went wrong :(" ); //http code 500 (error) with a special message
} //the next code will not execute
//We are parsing data to JSON because data is actually a string
let todos = JSON . parse (data); //let allow to modify the content (different from const)
const todoIndex = findTodoById (todos, id);
if (todoIndex == - 1 ) {
return response. status ( 404 ). send ( "File not found" );
}
todos[todoIndex].complete = true ; //we put the value as true
//we write changes to the file with todos data being stringify (converted back to)
fs. writeFile ( "./store/todos.json" , JSON . stringify (todos), () => {
return response. json ({ status: "ok" }); //we return ok as it has been modified
});
});
}); //quick request to mark a todo
//add items with post requests
app. post ( "/todo" , ( request , response ) => {
if ( ! request.body.name) {
return response. status ( 400 ). send ( "Missing name" );
}
fs. readFile ( "./store/todos.json" , "utf-8" , ( err , data ) => {
//Handling errors
if (err) {
return response. status ( 500 ). send ( "Something went wrong :(" ); //http code 500 (error) with a special message
} //the next code will not execute
const todos = JSON . parse (data);
//We find the max id on the file
const maxId = Math.max. apply (
Math,
todos. map (( t ) => {
return t.id;
})
);
//We add a new value with a new id higher that higher obtained
todos. push ({
id: maxId + 1 ,
complete: false ,
name: request.body.name,
});
//Write changes to the file
fs. writeFile ( "./store/todos.json" , JSON . stringify (todos), () => {
return response. json ({ status: "ok" }); //we return ok as it has been modified
});
});
});
//Port listening the inbound traffic
app. listen ( 3000 , () => {
console. log ( "App running on http://localhost:3000" );
});
To dockerize the app:
Install Docker
Open it (make sure it’s opened before doing anything)
Create a new file called Dockerfile
, where instructions for docker will be descripted
# linux container
FROM node:12
# app directory
WORKDIR /app
# environment variable
ENV NODE_ENV production
# copy package logs files into the working directory
COPY package*.json ./
# docker will make npm install
RUN npm install
# copy all the sources files (from current paste into working directory)
COPY . .
# installs the library pm2
RUN npm install -g pm2
# expose the port 3000
EXPOSE 3000
# executes the library
CMD [ "pm2-runtime" , "index.js" ]
Create a new file called .dockerignore
and type this to ignore all the node packages:
node_modules
Go to the aws console an type (create a Elastic Container Repository):
ecr >> repositories
Create a new repository
View push commands (execute them)
Type ecs >> clusters (To create a Elastic Cluster) (make sure you use the old version)
Do not click VPC
Go to the tasks definitions of the new cluster:
Create a new one with fargate
Assign a name like taskdef-xxx
Add a task size of 0.5 Gb and 0.25vCPU
Click add container
Put a name (maybe the same as the container you created before) like container-xxx
On image copy the url of the repository where all was store (ecr)
Go back to ecr
Copy the image uri of your latest repository
Keep default soft Limit (128)
Put port 3000 on port maps with protocol tcp
Leave blank the rest and create
Go to the cluster you created before >> Services:
Create a new Service
Select FARGATE
select the latest task definition
Add a task and a service name
Leave the rest by default and click next
Select the VPC of the cluster you want
Add your subnets
Edit security groups
Select Custom TCP
Put the port 3000
Save
Select Application Load Balancer
Put health check period to 30
Create an application load balancer
Select the http/https one
Give it a name like alb-xxx
Listener set to HTTP on port 80 (Create a target group if not exists)
Select the default vpc and select all the subnets
Refresh the tasks view (1~2mis)