Skip to content

Instantly share code, notes, and snippets.

@flacial
Created August 18, 2021 13:30
Show Gist options
  • Save flacial/d925d9fb41a4c3bb4b667a9a36b1ad83 to your computer and use it in GitHub Desktop.
Save flacial/d925d9fb41a4c3bb4b667a9a36b1ad83 to your computer and use it in GitHub Desktop.
URL Shortener - ExpressJS/Postgresql
/*
Steps:
0. Choose a method to save the shortUrl and originalUrl (Database or file)
1. Create an endpoint (GET "/pathName/:shortUrlParameter") to validate the shortUrl and redirect
the user to the corresponding originalUrl
2. Create an endpoint (POST "/pathName") to create new shorten links
*/
// Backend Framework.
import express from "express";
// SQL query builder.
import Knex from "knex";
// Random ids generator.
import shortid from "shortid";
// Secure Express app by setting various headers.
import helmet from "helmet";
// Initialize express instance.
const app = express();
// Middleware to parse body (JSON) before handler.
app.use(express.json());
// Middleware to secure the app.
app.use(helmet());
// Connect to a database.
const db = Knex({
// Database client (Postgres, MongoDB, Mysql,...etc).
client: "pg",
connection: {
// connectionString has all the required details (user, password, port, database) to make a connection.
connectionString: process.env.DATABASE_URL,
ssl: {
// rejectUnauthorized is used specifically for free Heroku postgress database.
rejectUnauthorized: false,
},
},
});
// Endpoint that run a handler function whenever it's called with a shortLink parameter (E.g., potato.com/urls/someParameter).
app.get("/urls/:shortLink", (req, res) => {
// Extract the shortLink from the req.params.
const { shortLink } = req.params;
// Check if the database has the shortLink.
db.select("longurl")
.from("links")
.where("shorturl", shortLink) // return the records that are equal to shortLink from shorturl column.
.then((record) => {
// record is an array with the records as objects [{record}].
if (record.length) return res.status(301).redirect(record[0].longurl);
// Object has to be turned into a string for it to be sent.
res.status(400).send(
JSON.stringify({
error: {
message: "Provide a valid shorten link",
},
})
);
})
.catch((err) => {
return res.status(500).send({
message: "Server Error",
});
});
});
/*
Endpoint that run a handler function whenever it's called with a POST request body containing
an originUrl variable (E.g., potato.com/urls)
Example request body for POST request:
{
"originUrl": "https://google.com"
}
*/
app.post("/urls", (req, res) => {
const { originUrl } = req.body;
if (originUrl) {
const shortUrl = shortid.generate();
// The current host full URL (E.g., https://nyaasi-url-shortener.herokuapp.com/)
const hostUrl = `${req.protocol}://${req.get("Host")}${req.originalUrl}/`;
// It reads like "Insert longUrl and shortUrl into links table"
db("links").insert([{ longurl: originUrl, shorturl: shortUrl }]).catch(err => {throw err})
// Send back shortenUrl and originUrl to the requester
return res.status(201).send({
shortenUrl: hostUrl + shortUrl,
originUrl,
});
}
});
// Port for the app (server) to run/listen on for requests
app.listen(process.env.PORT || 3000);
/*
Additional info:
GET request method is used to literally get data from an API.
POST request method is used to create new data.
process.env.X is the (secret) environment variable. In original script, they were used for Heroku.
res.status(CODE).send(): used to send a reponse (text, json, file) with a status code like 200 for successful requests or
401 for unauthorized requests.
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment