Welcome to today's lesson! We'll be delving into routing, a crucial part of developing web applications. Think of a web application's routes like a system of roads in a city, guiding data from one part to another.
Our goal today is to grasp how to set up these "roads", known as routes, using Node.js and Express for a Todo List backend. It's like giving our web application a map to handle and organize data requests.
Here's our route map for today:
GET
, and POST
HTTP methods for our routes.Ready to start your journey? Let's hit the road!
Routes in a web application are like street addresses. Imagine you're in New York City. Each building has its unique address so people can find it among the skyscrapers. Similarly, each part of your application has an address, known as a route.
Express.js, a framework for Node.js, makes creating these routes simple. An Express route is set up like this:
JavaScript1app.get('/todos', function(req, res) { 2 res.send('GET route on todos.'); 3});
In this snippet, app
is our Express server. get
is the type of HTTP method we're responding to. '/todos'
is the address for our route, and function(req, res) {...}
is what we do when this route is visited.
After setting up our routes, we need to decide what happens when each route is visited. Going back to the city analogy, it's like deciding what each building in the city does. One might be the postal office, another the city hall, and a third the cinema. These decisions are made in route handlers, where we can specify the functionality for each route.
Let's start with an example for our GET
route, where we want to return the list of all todos:
JavaScript1let todos = ["Finish Homework", "Go grocery shopping", "Prep for meeting"]; 2 3app.get('/todos', function(req, res) { 4 res.send(todos); 5});
In this route handler, req
represents the incoming request data, and res
is the object we can manipulate to send a response back. In this case, we've sent back our array of todos with the res.send()
method. This allows the client to receive the current list of todos each time they visit this route.
Next, we need a way to store new information; after all, you cannot GET
something if there is nothing to retrieve. This is done with the POST
operation. Here’s a basic setup of our POST
route:
JavaScript1app.post('/todos', (req, res) => { 2});
As a server, we need to be able to comply with the requests sent to us, particularly for creating new todo items that have specific attributes. To easily access these parameters, we can instruct Express.js
to automatically parse the JSON payloads into JavaScript objects by calling app.use(express.json())
. This will provide us with a req.body
to access the incoming data:
JavaScript1app.use(express.json()); 2 3let todos = []; 4 5app.post('/todos', (req, res) => { 6 const newTodo = { 7 text: req.body.text, 8 done: req.body.done 9 }; 10 todos.push(newTodo); 11 res.send(newTodo); 12});
In this POST
handler, we take in an object with text
and done
fields from the request body. We store the new todo in the server's array and send the newly created object back as a confirmation. Our backend can thus dynamically handle incoming data, keeping our todo list up-to-date. As more todos are added through POST
requests, the server's array will grow, allowing for more comprehensive data retrieval with subsequent GET
requests.
Finally, we can enhance our todos by giving each item a unique identifier for ease of access and control. This identifier can be set to the current time using Date.now()
to avoid overlapping IDs:
JavaScript1app.use(express.json()); 2 3let todos = []; 4 5app.post('/todos', (req, res) => { 6 const newTodo = { 7 id: Date.now(), 8 text: req.body.text, 9 done: req.body.done 10 }; 11 todos.push(newTodo); 12 res.send(newTodo); 13});
Note that the id
is automatically set by the server, ensuring that each todo item has a unique identifier without requiring the requester to provide it. This makes it easier to manage and reference each todo item individually.
It's also important to account for things going wrong in our route handlers, like a missing todo, and to ensure our routes are secure. Think of the city once again: we wouldn't want unauthorized people to have access to secure buildings. This is similar to route protection:
JavaScript1app.get('/todos/:id', function(req, res){ 2 let todoId = req.params.id; 3 4 if (!todoId) { 5 res.status(404).send('Todo not found'); // Send an error message if the id does not exist 6 } else if (!user.isLoggedIn()) { 7 res.status(403).send('Forbidden'); // Prevent unauthenticated users from deleting todos 8 } else { 9 res.send('Return the todo with id ' + todoId); 10 } 11});
In this example, user.isLoggedIn()
is a symbolic placeholder used to illustrate the flow. It represents checking if a user is authenticated but is not an actual implementation.
To interact with our new backend routes, we will once again use Axios. Here's how you can do this.
JavaScript1const axios = require('axios'); 2 3// Example of posting a new todo 4axios.post('http://localhost:3000/api/todos', { 5 text: 'Learn how to post in run.js', 6 done: false // set initial status of the todo 7 }) 8 .then(response => { 9 console.log('Todo created:', response.data); 10 11 // Fetch and log the updated list of todos 12 return axios.get('http://localhost:3000/api/todos'); 13 }) 14 .then(response => { 15 console.log('Updated list of todos:', response.data); 16 }) 17 .catch(error => { 18 console.error('Error:', error); 19 });
In this example, we send a POST
request to add a new todo item. The payload includes the text
field for the todo and a done
status. The then
block logs the created todo and fetches the updated list of todos. The second then
block is for logging the updated list, while the catch
block handles any errors.
With these examples, you can effectively interact with your backend routes using different HTTP methods and properly handle the responses and errors.
Great job! You've learned how to set up and handle routes in Express.js, making your web application more organized and functional. We've covered a lot:
GET
and POST
)Take this chance to cement these skills with our practice exercises. Remember, it's just like traveling roads in a city — the more you use them, the more familiar they'll become!