This is a simple url-shortener inspired by Cutt.ly. It returns a unique shortened url for every input which redirects to the original url.
This project is written in typescript and uses fastify as a web framework. I am using Redis as a database here to store the key/value pair of the input urls and the corresponding redirect-code. Tests are powered by jest. Other dependencies can be found in package.json
The structure of the project is pretty much straight forward and intuitive. All of the application code is under src/
. The src/
folder is further broken down into server
, helpers
and store
.
-
server/ houses all of the code relevant to the web server, including routes, handlers and controllers. The reason for this abstraction was to make the code more intuitive and separation of concerns. In this design, the
routes
are only responsible for routing the requests to appropriate handlers. Thehandlers
are responsible for handling the response and there is no application logic here except for input/output validations. The main application logic sits inside thecontrollers
. -
helpers/ contain all application specific helpers. In this case createUniqueHash
-
store/ contains setup and implementation details for external database, in this case
redis
The test are broken down similarly and can be found under tests/
.
The createUniqueHash function is responsible for creating a unique hash, that is used as a key for every incoming request and then saved in redis. The underlying implementation relies on Node's crypto.randomBytes to generate random bytes of data that is returned as a hex
string of length 8.
The current implementation has the following 3 endpoints
POST /shorten
GET /:id
GET /:id/stats
More details can be found in the Swagger
Requires Node.js v14.x
In order to run this locally, make sure you have redis installed and running locally, also ensure that the redis user requires a password (the default user 'default' has no auth). Alternatively, a docker image for redis can be used, this is how I am using running the test in the CI. To get a redis instance with docker -
docker run -d -p 6379:6379 redis redis-server --requirepass $REDIS_PASS --port 6379
The following 4 environment variables are required for redis - REDIS_PORT
, REDIS_HOST
, REDS_USER
and REDIS_PASS
. If either of these are not set, the default values from the config are applied.
Once redis is setup with auth, the server can be started with npm run start
. This basically compiles the project into /dest
and runs the compiled js code.
For running tests, simply npm run tests
. Make sure redis is up and running, otherwise tests may misbehave. Tests are run on a different redis database (database#2) and the db is cleaned up after the tests.
I am using GitHub actions for CI, more details can be found in the yaml file
- Use better logging. Right now I am using
console.log
andconsole.error
, for more control over logs a custom logger with multiple log levels should be used. - Add access logs for every endpoint.
- Add a retention policy for redis keys, right now the keys do not expire. Ideally this could use the Expire command from redis.
- Host this somewhere so that we can also leverage a base url for every redirect.