Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) _ Adrian Mejia Blog
Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) _ Adrian Mejia Blog
The MEAN stack allows you to build complete applications using one programming
language: JavaScript. In this tutorial, we made upon the first part (Creating an
Angular app) which built the front-end, and this part builds the backend with a
RESTful API and Database.
1 npm i -g express-generator
1 express server -e
1 npm start
Go to localhost on port 3000 and make sure you can see a “Welcome to Express.”
http://localhost:3000/
Windows: c:\windows\system32\drivers\etc\hosts
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 2/24
3/17/25, 2:19 PM Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) | Adrian Mejia Blog
Linux/Mac: /etc/hosts
Once you can open the file, you drop the following line at the end:
1 127.0.0.1 server
http://server:3000/
(If you have trouble editing the host file, take a look here)
1 /api/todos[/:id]
This route will get all our todos, update, and delete them.
1 touch server/routes/todos.js
server/routes/todos.js
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 3/24
3/17/25, 2:19 PM Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) | Adrian Mejia Blog
14 res.json(TODOS);
15 } catch (error) {
16 res.status(500).json({ error });
17 }
18 });
19
20 module.exports = router;
All this is doing is replying to the GET commands and returning a hard-coded list of
todos. We will replace it later to get data from mongo instead.
server/app.js
The method use registers the new path /api/todos . When we get any call on this
path, our todosRouter will handle it.
You can restart your server or use nodemon to pick up changes and refresh the
browser.
1 ## npm i -g nodemon
2 nodemon server/bin/www
That should get your server running. Now you can see it in action using cURL:
This command should get you all the lists in JSON format!
In the next step, we will query the server using Angular instead of curl . After that,
we will complete the rest of the operations (update, delete, create).
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 4/24
3/17/25, 2:19 PM Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) | Adrian Mejia Blog
As you might know, when you run ng serve , it will trigger a development server.
However, our API is an entirely different server. To be able to connect the two, we
need to create a proxy.
src/proxy.conf.json
1 {
2 "/api": {
3 "target": "http://server:3000",
4 "secure": false
5 }
6 }
(This will need the host alias from the step before)
Then, we have to tell Angular to load this file when we are serving the App. We are
going to do that in the angular.json file.
If you are using the same version of angular CLI, you need to insert this on line 71:
1 "proxyConfig": "src/proxy.conf.json"
angular.json > projects > Todos > architect > serve > options
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 5/24
3/17/25, 2:19 PM Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) | Adrian Mejia Blog
1 {
2 "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 // ...
4 "projects": {
5 "Todos": {
6 // ...
7 "architect": {
8 // ...
9 "serve": {
10 "builder": "@angular-devkit/build-angular:dev-server",
11 "options": {
12 "browserTarget": "Todos:build",
13 "proxyConfig": "src/proxy.conf.json" // <-- Insert this l
14 },
15 // ...
16 },
17 // ...
18 }
19 }},
20 "defaultProject": "Todos"
21 }
Now our App will pass all requests that start with /api to http://localhost:3000
(or whatever path you specified on the proxy.conf).
src/app/app.module.ts
5 @NgModule({
6 declarations: [
7 AppComponent,
8 TodoComponent
9 ],
10 imports: [
11 BrowserModule,
12 AppRoutingModule,
13 FormsModule,
14 RouterModule.forRoot(routes),
15 HttpClientModule, // <---- import module
16 ],
17 providers: [],
18 bootstrap: [AppComponent]
19 })
20 export class AppModule { }
Now that the HttpClient is available in our App let’s add it to the service and make use
of it.
src/app/todo/todo.service.ts
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 7/24
3/17/25, 2:19 PM Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) | Adrian Mejia Blog
We change the TodoService.get to use HTTP client. However, the component was
responding to a Promise, and the HTTP.get returns an Observable. So, let’s change
it.
Change the getTodos method from the old one to use this one that handles an
observable.
src/app/todo/todo.component.ts
1 getTodos(query = '') {
2 return this.todoService.get(query).subscribe(todos => {
3 this.todos = todos;
4 this.activeTasks = this.todos.filter(todo => !todo.isDone).length;
5 });
6 }
Once you have both running, you can go to http://localhost:4200/all, and you can
verify that it’s coming from your server!
But, we don’t want to have hard-coded tasks. Let’s create a proper DB with Mongo.
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 8/24
3/17/25, 2:19 PM Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) | Adrian Mejia Blog
Setting up MongoDB
It’s time to get MongoDB up and running. If don’t have it installed, you have a couple
of options:
Brew (macOS)
We are going to use Docker since it’s an excellent way to have everything running
together with one command. Also, you can deploy it to the cloud and scale it quickly.
docker-compose.yml
1 version: "3.7"
2
3 services:
4 app:
5 image: node:lts-alpine
6 working_dir: /app
7 volumes:
8 - ./:/app
9 ports:
10 - 4200:4200
11 # --host 0.0.0.0 to listen to all the interfaces from the containe
12 command: >
13 sh -c "npm install &&
14 npx ng serve --host 0.0.0.0"
15
16 server:
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 9/24
3/17/25, 2:19 PM Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) | Adrian Mejia Blog
17 image: node:lts-alpine
18 working_dir: /server
19 volumes:
20 - ./server:/server
21 # port 3000 has to match src/proxy.conf.json
22 ports:
23 - 3000:3000
24 depends_on:
25 - mongo
26 environment:
27 MONGO_HOST: mongo
28 command: >
29 sh -c "npm i -g nodemon && npm install && nodemon ./bin/www"
30
31 mongo:
32 image: mongo
All right, now we can get the whole full-stack App running with one command:
1 docker-compose up --build
NOTE: close other terminals running a web server so the ports don’t conflict. The
docker-compose command will create 3 containers for our Angular App, Node Server,
and Mongo DB. You can also see all the logs in one place.
After you wait a minute or so, you should be able to open the App on
http://localhost:4200/.
Now we can make use of mongo. Keep docker-compose running and now let’s
remove the hard-coded tests and use the database.
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 10/24
3/17/25, 2:19 PM Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) | Adrian Mejia Blog
NOTE: make sure you installed it on the ./server/package.json , rather than the
client-side packages ./packages.json .
The first thing we need to do is to connect to Mongo when our server starts. Go to
server/app.js and add the following code:
server/app.js
We can pass some ENV variables like MONGO_HOST . If we run it locally, it will use
localhost, but if you run it on Docker, we want to pass a hostname. You can see that
in the docker-compose.yml file.
Now, let’s define our data model for Mongo. Let’s create a folder models inside
server and add a file called “todos.js”.
server/models/todo.js
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 11/24
3/17/25, 2:19 PM Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) | Adrian Mejia Blog
The new schema is defining what fields we want to store and what the types are. The
updated_at will update automatically when we create a new todo.
** Todo.find**: find data matching a given query. ( {} , get all, while {isDone:
true} get only completed tasks).
** Todo.create**: Create a new todo
** Todo.findByIdAndUpdate**: Find Todo by given id and update its content.
** Todo.findByIdAndDelete**: Find Todo by given id and delete it.
** Todo.deleteMany**: Delete everything matching a given query.
Here are the routes by their matching HTTP verb (GET, PUT, POST, DELETE). In the
next sections, we will test all these routes and go over some more details.
server/routes/todos.js
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 12/24
3/17/25, 2:19 PM Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) | Adrian Mejia Blog
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 13/24
3/17/25, 2:19 PM Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) | Adrian Mejia Blog
47 // Beaware: it can delete all data from db if body is empty (DON'T exp
48 /* DELETE /api/todos */
49 router.delete('/', async (req, res) => {
50 try {
51 const todo = await Todo.deleteMany(req.body);
52 res.json(todo);
53 } catch (error) {
54 res.status(500).json({ error });
55 }
56 });
57
58 module.exports = router;
We added many routes to this step. Take your time to go through them. In the next
section, we will test them using curl and then integrated them with Angular.
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 14/24
3/17/25, 2:19 PM Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) | Adrian Mejia Blog
1 [{"_id":"5edc2a6d0c41d60054ad715f","title":"CRUD API","isDone":false,"u
You can also check Angular on http://localhost:4200/all. The new task should be
there!
If you remember from your routes file, we are using the method PUT to update tasks.
server/routes/todos.js
1 /* PUT /api/todos */
2 router.put('/:id', async (req, res) => {
3 try {
4 const options = { new: true };
5 const todo = await Todo.findByIdAndUpdate(req.params.id, req.body,
6 res.json(todo);
7 } catch (error) {
8 res.json(500, { error });
9 }
10 });
For updating a task you need the _id . You can get it from the previous step, when
we listed all the tasks. For my case the _id is 5edc2a6d0c41d60054ad715f , find yours
and replace it in the next command:
As you can see in the last update, we can modify existing fields and add new values
like the note field.
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 15/24
3/17/25, 2:19 PM Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) | Adrian Mejia Blog
For our todo route, we also defined the DELETE method. Similar to the update, we
need to pass and id .
server/routes/todos.js
1 /* DELETE /api/todos */
2 router.delete('/:id', async (req, res) => {
3 try {
4 const todo = await Todo.findByIdAndDelete(req.params.id);
5 res.json(todo);
6 } catch (error) {
7 res.status(500).json({ error });
8 }
9 });
As much fun as curl is, let’s move on and complete all these functionalities in
Angular.
src/app/todo/todo.service.ts
5 _id?: string;
6 title: string;
7 isDone: boolean;
8 notes: string;
9 update_at: string;
10 editing ?: boolean;
11 }
12
13 const API = '/api/todos';
14
15 @Injectable({
16 providedIn: 'root'
17 })
18 export class TodoService {
19 constructor(private http: HttpClient) { }
20
21 get(params = {}) {
22 return this.http.get(API, { params });
23 }
24
25 add(data: ITodo) {
26 return this.http.post(API, data);
27 }
28
29 put(changed: ITodo) {
30 return this.http.put(`${API}/${changed._id}`, changed);
31 }
32
33 toggle(selected: ITodo) {
34 selected.isDone = !selected.isDone;
35 return this.put(selected);
36 }
37
38 delete(selected: ITodo) {
39 return this.http.delete(`${API}/${selected._id}`);
40 }
41
42 deleteCompleted(body = { isDone: true }) {
43 return this.http.request('delete', `${API}`, { body });
44 }
45 }
The Todo service matches the HTTP verbs that we used in curl and passes the
payloads.
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 17/24
3/17/25, 2:19 PM Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) | Adrian Mejia Blog
Let’s now change the TodoComponent that goes along with these changes.
src/app/todo/todo.component.ts
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 18/24
3/17/25, 2:19 PM Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) | Adrian Mejia Blog
In the component, one the first thing we do is check the route params (path):
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 19/24
3/17/25, 2:19 PM Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) | Adrian Mejia Blog
1 ngOnInit() {
2 this.route.params.subscribe(params => {
3 this.path = params['status'];
4 this.getTodos(this.path);
5 });
6 }
When you click on the buttons All , Active , and Completed , that will trigger a
route change.
To recap, these buttons use the router link. So, every time you click on them, they will
change the URL.
1 <ul class="filters">
2 <li>
3 <a [routerLink]="['/all']" [class.selected]="path === 'all'">All</
4 </li>
5 <li>
6 <a [routerLink]="['/active']" [class.selected]="path === 'active'"
7 </li>
8 <li>
9 <a [routerLink]="['/completed']" [class.selected]="path === 'compl
10 </li>
11 </ul>
After we change the URL, the next thing we do is to call getTodos . Let’s see that
next.
src/app/todo/todo.component.ts (exerpt)
1 getTodos(route = 'all') {
2 const query = this.mapToQuery[route];
3 return this.todoService
4 .get(query)
5 .subscribe((todos: ITodo[]) => {
6 this.todos = todos;
7 this.activeTasks = this.todos.filter(todo => !todo.isDone).length
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 20/24
3/17/25, 2:19 PM Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) | Adrian Mejia Blog
8 });
9 }
We this.todoService.get will issue an HTTP get and retrieve all the tasks from the
database and update the todos. It also updates the number of active tasks (the ones
that are not done).
The getTodos receives an argument ( route ) with the path that will be one of these:
all , active , or complete . However, MongoDB doesn’t understand these words.
We have to map it ( mapToQuery ) to something a proper query like { isDone: true
} . This MongoDB will understand.
All the other operations, like the update, clear, toggle, are very similar. They trigger an
action and then call getTodos , so the UI is up to date with the latest changes.
That’s all!
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 21/24
3/17/25, 2:19 PM Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) | Adrian Mejia Blog
NEWER OLDER
How to solve any graph/Maze interview questions in The JavaScript Promise
JavaScript? DFS vs. BFS Tutorial
email address
Subscribe
Follow @iAmAdrianMejia
Contents
1. REST API with Node.js
2. Connecting REST API with Angular App.
3. Setting up MongoDB
4. Angular Service to talk to the server
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 22/24
3/17/25, 2:19 PM Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) | Adrian Mejia Blog
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 23/24
3/17/25, 2:19 PM Modern MEAN Stack Tutorial with Docker (Angular, Node, Typescript and Mongodb) | Adrian Mejia Blog
3 Comments
1 Login
Name
smog − ⚑
S 2 years ago
Do you have a repo that includes the code used in the MEAN stack? I have been getting quite a few
errors as I go through this tutorial. A full repo would do a lot to help get a full view of the project,
these little snippets can get messy.
0 0 Reply ⥅
ayush gupta − ⚑
A 4 years ago
I am glad to see this brilliant post. all the details are very helpful and good for us, keep up to good
work.I found some useful information in your blog, it was awesome to read, thanks for sharing this
great content to my vision, keep sharing.
0 0 Reply ⥅
ayush gupta − ⚑
A 4 years ago
I’m excited to uncover this page. I need to thank you for your time for this, particularly fantastic
read!! I definitely really liked every part of it and I also have you saved to fav to look at new
information in your site.
Mean Stack Training in pune
0 0 Reply ⥅
https://adrianmejia.com/angular-todo-mean-stack-node-mongodb-typescript-tutorial/ 24/24