cross

Travel experience

Node.js, Express.js, MongoDB, Mongoose, Handlebars

Travel reviews application created with Node.js, Express.js, MongoDB and associated libraries: passport, express-session, mongoose, handlebars.

Check the project on Github

Travel experience is a project consisting of a small application where users can register and write reviews and opinions about places they have visited, being at the same time some kind of travel diary for them, and also a reference for other users that can access information about places they might go in the future.

Node.js and Express.js

The project is made with Node.js in JavaScript language through the Express.js framework. All this allows us to completely configure the back of the application, all the logic, and render it directly through templates of the library handlebars, without the need to use front frameworks. The project is distributed in a folder structure: a folder with the models, one with the authentication, another with the routes linked to another with the controllers, another with the middleware and another with the views, and all of them come together in the index.js file. Express.js is a framework that brings us its own functionalities to assign a port and build the server, in addition to allowing us to incorporate external libraries with additional functionalities such as authentication, session creation, interaction with the database, or content rendering.

Mongoose: models and seeds.

The information displayed and collected by the application is sent to and collected from a database created with MongoDB. The interaction between Node Express.js and MongoDB is done through Mongoose. This package allows us, among other things, to create the models, instances of a Schema class with all the attributes that make up the collections. These models define the parameters of the class that will be filled in by the values of the different objects that are added to the database. The type of value that will be valid is also defined, and the values that will be required in a mandatory way. The models on which the application is based are the Experience model and the User model. All users must fill in the fields of this model to shape a user-object, and the same applies to the added experiences. Each experience in the experiences collection also includes a user object that is collected from the user collection. Before having the experiences and the users created, the tests are carried out with a series of seeds to populate the database with testing objects.

Authentication: passport

One of the axes of this application is the user, since he’s the one who adds the that make up the application. As we have already said, the user must first comply with the parameters established in the user model. Once these requirements are met, the creation of users requires the use of a form to make a POST request to the database through a register strategy. All the logic behind this process includes a data validation process based on specifications, in addition to including password encryption. After registering, the user must log into the application with the corresponding login strategy. Both strategies are created thanks to the passport library associated with Express.js. Another feature of the authentication process is the session, which is created when logging in through the passport-session library, and is stored in a cookie and sent to the database where it is registered. In addition to the login, register and logout strategies, the application also includes an authentication middleware, which unlocks some functionalities of the application in case the user is logged in, and even some more if it is marked as admin.

CRUD: endpoints, routes and handlebars

To bring the information to the different pages of the application, a series of endpoints are created from GET requests. The application searches in the database the collection of experiences based on the country or the tag associated with the objects. These searches are carried out through Mongoose functions such as find or findById, or JavaScript's functions such as loops or filters, and they return what is requested. All this is collected in a function created in a controller file and associated with a route of a routes file, and this function returns the rendering of an html template created with the handlebars templates package.

In addition to GET requests, the application has a series of POST requests. To add an experience, the first thing to intervene is the user middleware, which prevents access to that part of the application if the user is not logged in. Once the middleware detects that the user has logged in, a form is accessed that is filled out by the user, and that information is sent through a POST request to the database where the new experience is stored. The application has another file middleware that is in charge of managing the images added by the user in the experience form. This middleware collects the image, uploads it to an online platform, in this case Cloudinary, and sends the link to the database as the value of the image property of the experience-object. The application also has a kind of DELETE request to delete an experience from the database, although in this case it is done through a POST request that makes a findByIdAndDelete in the MongoDB database. This functionality is further restricted by user middleware, and is only accessible to those marked as admins.

Error handlers

First of all, the application has error detection in the routes thanks to a function that, if it detects a request to a non-existent or incorrect route, always launches a route not found message and a 404 Not found error. In addition, the entire application has a series of error handlers in all the functions susceptible to give an error, especially in those that involve asynchrony. All these errors are sent to an error handler function created in the index.js that takes the error as the first parameter and displays it on the screen and in the console. In this way the entire application is protected against possible failures.

© Pablo Pacheco