Creating a URL Shortener with TypeScript + Express.js + MongoDB

TS + MongoDB + Express.js

In this article, we will create a URL Shortener API which can create and retrieve data from MongoDB Cloud.

What is TypeScript

TypeScript is a superset for JavaScript developed and maintained by Microsoft. In JavaScript, the code is interpreted by browser at runtime which is kinda bad because you won’t be able to catch errors until you run your code. TypeScript prevents error like this by extending JavaScript with types. Since TypeScript is a superset of JavaScript, you can write plain JavaScript code in TypeScript file and choose not to use any features of it. TypeScript behaves like a compiled language where the JavaScript is compilation target. We can use TypeScript compiler (tsc) to transpile TypeScript to JavaScript and customize the behavior of compiler with tsconfig.json.

Getting Started

First, we create a directory for our project then initialize git and npm in root directory and create our first ts file in src folder.

mkdir short-urlsnpm init -y && git initmkdir src/index.ts

Now we need to install packages. We will use

Since we are using TypeScript we need the type definitions for these packages. We can install all of these with

npm i express cors helmet yup nanoid monk dotenvnpm i -D @types/node @types/express @types/cors @types/yup @types/nanoid

We don’t need types for helmet, monk and dotenv because they provide their own definitions. Finally we need TypeScript to compile our ts files. We install ts-node and nodemon alongside with ts to make our development faster.

npm i -D typescript ts-node nodemon

Configuring tsc

As I mentioned above we can customize the ts compiler using tsconfig.json. We can create tsconfig by hand but there is a better way to do it. We can use the npx command

npx tsc --init

This command will create tsconfig.json in our project root. We gonna change some options in this tsconfig.json file like

"target": "es6"
"outDir": "./dist"
"rootDir": "./src"
"moduleResolution": "node"

Configuring .gitignore and package.json

We can add node_modules/ , dist/ and .env to our .gitignore file to ignore them. Before configuring package.json lets create an empty .env file in projects root directory with command

touch .env

We will save our MongoDB URI here later. Now lets configure package.json. We add these following scripts to scripts section

"start": "node dist/index.js","dev": "nodemon src/index.ts","build": "tsc -p . && cp .env dist/.env"

Creating an express app

We open up our index.ts and start writing some code. First we import Express and middlewares.

Import Express, cors, helmet and yup.

We create express application and add our middlewares with app.use() function. Then we need to define a schema for our data which can be done using yup. We create an yup object with desired shape. In this case I want a destination field and a slug field. I want both to be string and destination will be a required url.

Creating express application and data schema

Now we can create our endpoints and start listening for incoming requests. We need an endpoint to create short urls and another one to retrieve them. You can change the data schema and add fields like clicks and token which can track the click count and token for editing slug etc.

First endpoint will be a create endpoint which will create a document in MongoDB with given slug and destination and if there is no slug provided in post data we should be creating a random slug for given destination.

create endpoint for creating short urls

This function will response with posted slug and destination if they are valid otherwise it will return an error message. Before running our express app we need to add an error function and start listening for incoming requests.

error handler and listen function

Now if we go to our terminal and run npm run dev nodemon will start watching for file changes in src directory. Open your favorite API client and send a post request for http://localhost:5000/create with json body.

qnt slug

Connecting to a MongoDB

So far we can send and validate our data, now we need to save these slugs and corresponding urls to our database so we can redirect when user uses a slug. We’ll be using MongoDB Cloud for our database but you can use MongoDB locally if you want. You can follow the Part 1 of Bret Cameron’s MongoDB: A Beginner’s Guide article to learn how to create a MongoDB cluster on cloud. From now on I assume you have your MongoDB URI.

We already created .env file so we just paste it with the name MONGO_URI

MONGO_URI=YOUR_MONGODB_URI

Before connection to MongoDB go to your cluster connections and create database named URL and collection named urls

Your URI should look similar to this where <DATABASE_NAME> is URL

mongodb+srv://<user>:<password>@<clusterURL>/<DATABASE_NAME>?retryWrites=true&w=majority

Next step is creating a connection for the database. We can do that in a separate file. Create a file named db.ts in our src directory.

touch src/db.ts

Inside our db.ts we need to connect to our MongoDB

Database connection

We get MONGO_URI from .env file by loading content to the process.env variable with dotenv.config(). Then we create a monk instance with default function which corresponds to

const db = require("monk")(MONGO_URI)

After connecting to database we get the urls collection with get() function. Finally we create an Index at slug field with unique: true option that assures every slug is unique.

Integrating MongoDB to Express.js

So far we created an express app and and prepared the connection to our database now we have to integrate those two.

First we alter our create endpoint so it can save documents to database.

insert upcoming data to database

Here we save our data to database with urls.insert() function.

Now if we send a post request to /create with proper request body it will save our slug and destination data to MongoDB and return its id.

If we try to send the same request the response status will be 400 and it will say that slug is in use because we created an unique index at slug .

Finally we add our last endpoint to retrieve information about given slug.

get url data from given slug

To test this function we can send a get request to localhost:5000 with desired slug.

get slug from db

Random Slugs

We are able to create random and unique slugs if no slug is provided in request body.

random slugs

Conclusion

You can create more operations and alter the data schema to create more complex shortener. Just another idea is static serving with express to create a frontend to your api and using res.redirect(redirect_url) to perform redirection which is the actual purpose of this article.

You can find the full source code here.

Junior Fullstack Developer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store