Now that our app is set up and configured, let's see how Express.js simplifies our routing.
Here's what our app currently looks like.
const express = require('express'); // makes Express available in your app.
const app = express(); // Creates an instance of Express, which allows us to begin routing.
app.listen(3000); // Starts up our server on port 3000.
module.exports = app; // Allows other files to access our Express app.
Let's add our first route above where we start our server.
const express = require('express'); // makes Express available in your app.
const app = express(); // Creates an instance of express, which allows us to begin routing.
// OUR NEW ROUTE
app.get('/home', function(request, response, next) {
response.send(200);
});
app.listen(3000); // Starts up our server on port 3000.
module.exports = app; // Allows other files to access our Express app.
What's going on here?
If you recall from our the first article in this series, HTTP requests all have a verb like GET or POST. GET is probably the most common HTTP verb. It's used for when the client is trying to retrieve a file or page from the server.
When we create a route in Express, we first specify the verb that our HTTP request will use. The get
in our app.get
is our verb.
app.get
is a function and takes the route we want use as its first argument. In this case, we are routing to '/home'.
That means that all GET requests to localhost:3000/home will be handled by this route.
Next we see a callback function:
function(request, response, next) { });
This function is called when the user requests the route. Here's where all the magic happens! Let's look at this function more closely.
In Express.js, requests and responses are handled through three core objects, typically named request
(request), response
(response), and next
. request
and response
are the two sides of HTTP communication. We'll talk about next
in a moment.
The request
object contains properties that allow us to access the components of our HTTP request.
For example:
- We can call
request.body
to see the payload of the HTTP request - We could call
request.method
to see if the request was a GET, POST, or other HTTP verb. - We could call
request.ip
to see the IP address that's requesting our site.
Check out the Express documentation for how to access the many properties of your request
object!
Remember, every HTTP request needs one and only one response. Here's where our res
object comes in.
An HTTP response might send the user a status code, some files, a website, or more!
With our response
object, we have methods to easily craft a response.
In our example above we call response.send(200)
. This sends the 200
status code back to the user when they request our site. We can also call methods like response.render(template, data)
to render an HTML page or response.redirect(anotherURL)
to send users somewhere else.
As with request
, just check out the docs for how to get the most out of your response
object.
With these two objects in our callback, we have everything we need to complete the HTTP request/response loop.
So what's up with next
?
Next is a callback that we can invoke to tell Express to search for another route that satisfies our request.
Let's say that we don't want our webpage to be accessible by a particular IP address. We use an if block and our request
object's .ip
property to block that IP by sending it a 404 status code.
app.get('/home', function(request, response, next) {
if (request.ip ==== '192.168.1.123') {
response.send(404);
} else {
next();
}
});
For every other ip, we call next()
. When we call next()
, Express will search our routes for the next handler that match the request. In this case, Express would search for a handler that manages a GET request to our '/home' route.
Let's add one.
app.get('/home', function(request, response, next) {
if (request.ip === '192.168.1.123') {
response.send(404);
} else {
next(); // Looks for our next relevant handler
}
});
// Here's another GET route to /home!
app.get('/home', function(request, response, next) {
response.render(myHomePage, myDataObject);
// ^ Render my home page with my data (defined elsewhere)
});
Next
is great for keeping individual routes short and clear, while still permitting control flow through different routes called through next
.