The application should provide an API to create a short URL by providing a long URL.
A user should be able to get a long URL by providing a short one.
The system should be highly scalable.
The system should have a high performance.
Short URLs should have an expiration date of 1 year.
Estimation: 1000 users per day.
User makes 1 write : 100 read requests per day.
Each request takes about 500 bytes - expected throughput ~ 50 MB daily.
Expected space requirement - up to 200 MB.
String generateShortUrl(String url) - send URL, receive short URL.
String retrieveUrl(String shortUrl) - send short URL, receive normal URL.
void deleterShortUrl(String shortUrl) - send a short URL that is no longer needed to be deleted.
The database should contain the following columns:
String long_url - original URL
String short_url - generated URL
Date - generated date
Client - a web application written in ReactJS that provides a convenient UI for a user.
Load balancer - a gateway to forward client requests to the server, selecting one based on availability and performance capabilities.
Server - a highly scalable stateless backend application written in Kotlin with a SpringBoot framework.
Database - a highly scalable multi-shared MongoDB database.
Expiration function - a serverless function scheduled to run once per day that would clean the Database from expired URLs.
The client web application should provide a convenient way for a user to send a request to the backend API, including creation, retrieval, removal, and redirection using the stored URL.
The request will go through the load balancer to one of the available backend servers, and the result should be written in the database. In case the operation went successfully, the client should receive HTTP response 200 and the expected result as the response body.
The client is a single page ReactJS application deployed on Azure Static Web App service. This application contains two forms. The fist one allows user to generate a shortUrl for the provided URL using a form with a text input and a button. The second allows a user to either retrieve the original URL using a once-generated shortUrl, or to permanently delete the shortUrl using text input and one of two buttons.
The server is a small stateless application hosted on Azure Web App, which allows quick scaling both horizontally and vertically. The server should generate a random 64-bit Base10 uid for incoming long URLs. This uid will be converted to Base58, which will serve as a short URL to be stored in the database and returned to the user.
When receiving requestUrl or deleteUrl requests, the incoming short URL will be used as a key to find the saved record, and then delete or return the original URL.
The expiration function is a simple serverless function scheduled to run daily, that will execute a query to delete all Database URL records with dates older than a year from the current time.
The client is written in ReactJS as its currently the most popular framework to write frontend SPAs.
Azure is used as a cloud provider as one of the biggest players on cloud market with excellent services and support, providing great SLAs and a wide range of services.
The backend is written in Kotlin. Other choices rejected: Java since it has much older and less maintainable syntax, and C# since it is generally less popular on the market.
The Database is using MongoDB. Other choices are - Postgress and Cassandra. Postgress was rejected since the relational model is not required, due to the absence of relations in the model. Cassandra is rejected since MongoDB generally provides better read performance, and we expect read throughput to be much higher than the write one.
All services are hosted on Azure cloud which provides high SLAs. Additionally, all services are called horizontally to multiple nodes which allows us to achieve high availability even during node downtime or maintenance. This also allows us to overcome the request bottleneck by scaling up the number of Server applications or Database partitions.
In case the second user retrieves the same shortUrl as already present within a system, the Server will receive an exception and will generate a new 64-bit uid for this request.
The application might be improved in future in many ways, depending on business requirements:
1) The application might use an authorization system to require users to register before getting access to shortUrl generation functionality. Each shortUrl is assigned per user, so no one except this user can delete his shortUrls.
2) The users might require a replenishable tokens system, which means that users will have a tokens count, used for each shortUrl generation request. These tokens might be replenished over time or by a monetization system.
3) ShortURL expiration date can be prolonged using a monetization system or tokens.
4) In case of high read load using the same shortUrls, it would make sense to implement a distributed cache using Memcache to keep the last used URL records and reuse them instead of doing the Database requests.
5) In case of a too high load from users the system can receive a RateLimiter to drop or queue exceeded requests. Requests priority might be monetized as well.