Skip to content

Instantly share code, notes, and snippets.

@mayankchoubey
Last active October 14, 2023 21:28
Show Gist options
  • Save mayankchoubey/1e02b1be665b710a43271290f51f5a40 to your computer and use it in GitHub Desktop.
Save mayankchoubey/1e02b1be665b710a43271290f51f5a40 to your computer and use it in GitHub Desktop.
Node.js - Native URL shortener service in PostgreSQL
import { DataTypes, Sequelize } from "sequelize";
const dbUser = process.env.dbUser;
const dbUserPass = process.env.dbUserPass;
const dbName = process.env.dbName;
const sequelize = new Sequelize(
`postgres://${dbUser}:${dbUserPass}@localhost:5432/${dbName}`,
{
logging: false,
pool: {
max: 10,
min: 10,
},
},
);
await sequelize.authenticate();
const ShortenedUrl = sequelize.define("shortenedurl", {
id: {
type: DataTypes.STRING,
primaryKey: true,
},
srcurl: DataTypes.STRING,
created: DataTypes.DATE,
lastaccessed: DataTypes.DATE,
}, {
timestamps: false,
});
export async function save(id, srcUrl) {
await ShortenedUrl.create({
id,
srcurl: srcUrl,
created: new Date(),
lastaccessed: new Date(),
});
return true;
}
import { shorten } from "./service.mjs";
export function handleRequest(req, res) {
let rawBody = [];
req
.on("data", (chunk) => {
rawBody.push(chunk);
})
.on("end", () => {
rawBody = Buffer.concat(rawBody).toString();
processRequest(req, res, rawBody);
});
}
async function processRequest(req, res, rawBody) {
const ctHdr = req.headers["content-type"];
if (!(ctHdr && ctHdr.includes("application/json"))) {
res.writeHead(415);
return res.end(getErrJSON("Content type JSON is required"));
}
let reqBody;
try {
reqBody = JSON.parse(rawBody);
} catch (e) {
console.log(e);
res.writeHead(400);
return res.end(getErrJSON("Request body is not a valid JSON"));
}
if (!reqBody.srcUrl) {
res.writeHead(400);
return res.end(getErrJSON("Parameter 'srcUrl' is missing"));
}
const srcUrl = reqBody.srcUrl;
if (srcUrl.length > 250) {
res.writeHead(400);
return res.end(
getErrJSON("Parameter 'srcUrl' must not be more than 250 characters"),
);
}
if (!(srcUrl.startsWith("http://") || srcUrl.startsWith("https://"))) {
res.writeHead(400);
return res.end(
getErrJSON("Parameter 'srcUrl' must start with http:// or https://"),
);
}
const shortenedUrl = await shorten(srcUrl);
if (!shortenedUrl) {
res.writeHead(500);
return res.end(getErrJSON("Failed to shorten"));
}
res.writeHead(200);
res.end(JSON.stringify({ srcUrl, shortenedUrl }));
}
function getErrJSON(errMsg) {
return JSON.stringify({ errMsg });
}
import http from "http";
import { handleRequest } from "./nativeController.mjs";
function requestListener(req, res) {
if (req.method !== "POST") {
res.writeHead(405);
return res.end(JSON.stringify({ errMsg: `${req.method} not allowed` }));
}
if (req.url != "/shorten") {
res.writeHead(404);
return res.end(JSON.stringify({ errMsg: `${req.url} not supported` }));
}
handleRequest(req, res);
}
http
.createServer(requestListener)
.listen(3000, "localhost");
import { nanoid } from "nanoid";
import { save } from "./db.mjs";
const baseUrl = "http://test.short/";
export async function shorten(srcUrl) {
if (!srcUrl) {
return;
}
const urlId = nanoid(10);
const shortenedUrl = `${baseUrl}${urlId}`;
const dbStatus = await save(urlId, srcUrl);
return dbStatus ? shortenedUrl : undefined;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment