DEV Community

Cover image for Creating a Basic Server with Express.js
Tim Smith
Tim Smith

Posted on • Originally published at iamtimsmith.com on

Creating a Basic Server with Express.js

In this post, I'm going to show you how to create a basic Express.js server for your web applications. We will go over starting the server, setting up simple routes, and outputting various types of data.

Node.js burst onto the scene in 2009 when Ryan Dahl pulled the JavaScript engine out of a browser and put it onto a server. Unlike other back-end technologies such as PHP or Java, Node.js isn't a language. It's a runtime environment which allows a server to interpret and run JavaScript code like a browser would.

The ability to use JavaScript for a back-end was a game changer, although it wasn't without challenges. Using it as a back-end required configuration and a lot of code, making it challenging to get up-and-running in a short amount of time. To combat this, Express.js was created in 2010 to give developers tools to stand Node.js back-ends up in no time.

What is Express.js?

Express.js is a framework for Node.js to provide developers with robust tools for building a back-end for a website or web application. It includes routing, simple setup for templating, and many more benefits. Because of it's maturity and ease of use, Express.js has been the most popular Node.js framework for years. There are even other Node.js frameworks built on top of it, such as Sails.js, Koa.js, and Nest.js.

Despite the number of tools it provides, it is a very unopinionated framework. The ability to structure your back-end any way you want means that it can be as flexible as you need it to be. For this reason, it is a staple in many developer's toolkits. Express.js gives us the "E" in the MEAN stack, MERN stack, or MEVN stack. Now that you have a better understanding about what Express.js is, let's build something with it!

Setting up the initial project

Before you can start using Express.js to build a back-end you need to set up your project folder, add your dependencies, and initialize your git repository (assuming you're using git). First, create the folder and enter it with the command below:

Terminal

$ mkdir basic-express && cd $_
Enter fullscreen mode Exit fullscreen mode

Once inside the newly created project folder, you need to initialize npm and set up dependencies. Although you can fill out all of the details in your npm init, I don't really care about that for the sake of this tutorial. I'm going to run the following command to set up npm with the default scaffolding.

Terminal

$ npm init -y
Enter fullscreen mode Exit fullscreen mode

After the package.json file is created, you can add the necessary dependencies which are listed below. Before moving forward, let's talk a bit about why we are installing these packages. The express package is the framework you are using for routing, templating, and more. body-parser allows you to get the body from an http request and use the data in your application. In this tutorial, I've decided to use Pug for templating although there are many different options you could use. Pug is simply a popular option and easy to use.

Terminal

$ npm i express body-parser pug
Enter fullscreen mode Exit fullscreen mode

The next step to perform is setting up your git repository. This is an optional step depending on whether you are using git for version control. If you are using git, I also recommend adding a .gitginore file to exclude the /node_modules directory from the repo. Keeping the node_modules directory will bloat your codebase and will cause problems with git. The code for the .gitignore is below:

.gitignore

node_modules
Enter fullscreen mode Exit fullscreen mode

Creating the Express server

The first file you have to create in your express project is going to be a server file. The purpose of this file is to set up any middleware you'll be using, configure a templating engine, create the server itself, and more. You could also put your routes in this file, but in my opinion that gets pretty messy if you have any more than 1 or 2 routes. You can call the server file whatever you want, although it is often called app.js or server.js. I will be calling mine server.js in this project.

Terminal

$ touch server.js
Enter fullscreen mode Exit fullscreen mode

Open your newly created file and you can begin building a simple server. At first, we will import express and designate a port on which our server can run. Inside your server file, add the following code:

server.js

const express = require('express');
const app = express();
const port = 4000;

app.listen(port, () => {
  console.log(`Success! Your application is running on port ${port}.`);
});
Enter fullscreen mode Exit fullscreen mode

Let's take a closer look at what's going on here. Line 1 imports the express library into the project. Line 2 creates instantiates express inside a variable called app. I am creating a variable for my port on line 3 so I can change it in one place and have it updated anywhere I'm logging or using it.

Once those variables are set, you can create the server by using app.listen(). First, pass in the port at which you want the server to run. This can be any value as long as it's an integer. After the port, can provide a callback. In this case, I've used the callback to log a message to the console indicating the server is running. This isn't required, but I like having the message to indicate that the terminal is working as expected.

Setting up routes in express

Before setting up routes, you need to include the body-parser package we included so express can use the information coming from the http request. To do so, modify the server file like so:

server.js

const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = 4000;

// Add the bodyParser middelware to the express application
app.use(bodyParser.urlencoded({ extended: false }));

app.listen(port, () => {
  console.log(`Success! Your application is running on port ${port}.`);
});
Enter fullscreen mode Exit fullscreen mode

Now that Express can parse the http requests, you can set up your routes. I mentioned earlier that you can place your routes in the server file. I'll show you how to do it that way and then how to do it my preferred way.

Putting routes in the server file

Express allows you to use the app variable with a method for the desired request type to establish routes. To illustrate this, you'll add 2 GET routes to the server file then start the server and navigate from one to the other.

server.js

const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = 4000;

app.use(bodyParser.urlencoded({ extended: false }));

// Set up home route
app.get('/', (req, res) => {
  res.send("This is the homepage");
})
// Set up second page
app.get('/second', (req, res) => {
  res.send("This is the second page");
})

app.listen(port, () => {
  console.log(`Success! Your application is running on port ${port}.`);
});
Enter fullscreen mode Exit fullscreen mode

To start the server, run node server.js in your terminal. You should see the console log in the app.listen() callback indicating that the application is running on port 4000. Once the server is started, you can navigate to http://localhost:4000 and you'll see a page with text that says "This is the homepage". This is the / route. If you visit http://localhost:4000/second, you'll see the "This is the second page" text.

For now, the server file doesn't look bad. As your application grows, you will need more and more routes which will eventually result in the file becoming a mile long, which drives me nuts. If you prefer to keep everything in one file, by all means, do it. This is just my personal preference.

Using controllers and a routes file

When building an application using Express.js, I prefer to stick with an MVC architecture. If you're unfamiliar with this, it stands for model-view-controller. It is an architectural pattern that has been around for a long time and there's lots of information. To put this into the most basic, oversimplified terms possible:

  • Model - The data in our application
  • View - The stuff that the user sees
  • Controller - What the routes should do

I will be using this sort of structure in this tutorial, although we won't have any models. Those can set up using various tools, known as ORMs, to connect databases. For this project, I will use a controller to simplify routing and pug for the views. First, let's set up a controller.

Terminal

$ mkdir controllers && touch controllers/BasicController.js
Enter fullscreen mode Exit fullscreen mode

Now you can open BasicController.js. This file will begin with a module.exports and we will be exporting an object of methods which make up the controllers. If this is confusing, the code below may help to explain a bit better:

controllers/BasicController.js

module.exports = {
  home: (req, res) => {
    res.send("This is the home page");
  },
  second: (req, res) => {
    res.send("This is the second page");
  }
}
Enter fullscreen mode Exit fullscreen mode

The module.exports makes this object available to other pieces of the application. Inside the object, we have the first key (home) which is a function. When setting up a route in express, the callback function takes a request (req) and response (res) parameter. The request allows you to get information about the request being made to the server and the response allows you to determine what the response will be.

Now that you have a controller set up, a file needs to be created for the routes:

Terminal

$ touch routes.js
Enter fullscreen mode Exit fullscreen mode

The routes.js file will house all of the routes for the project. Using controllers helps to keep this file clean since you can just tell Express what controller and method you want to use for the callback. Setting up a route goes from (potentially) many lines to a single line, making it quick and easy to tell what routes are doing what things. The code below illustrates what a routes file should look like given this setup:

routes.js

const express = require('express');
const router = express.Router();

const basic = require('./controllers/BasicController.js');

router.get('/', basic.home);
router.get('/second', basic.second);

module.exports = router;
Enter fullscreen mode Exit fullscreen mode

First you import the express library and the Router() method. Next, import any controller files being used in your routes. In this case, you only have a BasicController.js file. After that, you can begin setting up the routes. Since the routes are in a separate file from the app variable, you will use the router variable just like you did with app. Finally, the router variable with the new routes needs to be exported for use in the server file.

You're almost ready to test this out! The last step to get this working is to modify the server file, like so:

server.js

const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = 4000;

app.use(bodyParser.urlencoded({ extended: false }));
// Specify the url prefix and import routes
app.use('/', require('./routes'));

app.listen(port, () => {
  console.log(`Success! Your application is running on port ${port}.`);
});
Enter fullscreen mode Exit fullscreen mode

The line of code you added above says, "use this middleware, use the prefix of / for any routes in the controller, and use the routes file for the routing. This prefix could be whatever path you want at the beginning of the routes in the route file. In this case, I want the routes be at the root level instead of having a prefix, so I used /. Adding prefixes could be useful for apis or other such tools.

Now if you run node server.js, you'll see the same output as before because the servers work the same way. In my opinion, handling routes this way is much more legible and scalable.

Adding views with pug

Now you have set up a server, created controllers to handle the requests, and set up routes to make the data available to users. The last step to get a basic express server set up (assuming you want to output some sort of front-end and not just an api) is to set up a template engine for views.

Since pug is already installed, we can just tell Express to use that as a templating engine. By default, it will look for the views in a views/ folder, so no further configuration is needed there.

server.js

const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = 4000;

// Set up pug as view engine
app.set('view engine', 'pug');

app.use(bodyParser.urlencoded({ extended: false }));
app.use('/', require('./routes'));

app.listen(port, () => {
  console.log(`Success! Your application is running on port ${port}.`);
});
Enter fullscreen mode Exit fullscreen mode

Now that the view engine is set up, you can start creating the views. In this tutorial, I'm going to create a couple of really basic pug files for the views. Pug offers all kinds of cool features which makes it great for building front-ends, but I won't be covering that here. To begin setting up the views, create a views folder and then create files for each of our views.

Terminal

$ mkdir views && touch views/home.pug views/second.pug
Enter fullscreen mode Exit fullscreen mode

Pug allows you to write a sort of simplified html. It eliminates the need for opening and closing tags, but means that indentation is crucial. To make things simple, I've placed the code for both of the view files below. They are pretty much the same with the exception of the page name.

views/home.pug

html
  head
    title Homepage
  body
    h1 This is the homepage
    p Here is some text for the homepage. This is pretty awesome!
    a(href="/second") Go to the second page
Enter fullscreen mode Exit fullscreen mode

views/second.pug

html
  head
    title Second Page
  body
    h1 This is the second page
    p Here is some text for the second page. This is pretty awesome!
    a(href="/") Go to the home page
Enter fullscreen mode Exit fullscreen mode

The final step to adding views is to update the methods you created in the BasicController.js file. You can update res.send() to res.render(). The first argument you pass into res.render() is the name of the file in the views folder you want to render. The optional second parameter is an object which contains any variables you want to pass into the template. In this case, I won't worry about variables. The updated controller code is below. Once that has been updated, you can run node server.js and give the application a try. You should see a title, some text, and a link to the other page for each page.

controllers/BasicController.js

module.exports = {
  home: (req, res) => {
    res.render('home');
  },
  second: (req, res) => {
    res.render('second');
  }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

Congratulations! You now have a working express application complete with routing, controllers, and views. You can add more items as you see fit to continue and build on your app. Next steps would be adding a database with models, setting up authorization for users, and setting up private routes. Now go forth and create great things!

Have thoughts or questions? You can reach me on Twitter at @iam_timsmith.

Top comments (0)