Shortly is a Link shortener service that allows you to shorten links and share them with your friends π
- Create short links with your account
- Share links with anyone
- Permanent redirect links
- Create custom short links
- Strong authentication system
- Delete links
- Edit links
- Edit account
- Group permissions
- Location and device type data
- Session management
- Branded links - with a custom domain or custom route
- Data export
- Link history and reporting
- Expiration for links
- Access links based on location
git clone https://github.com/mreza0100/shortly
cd shortly
cp ./.env.example ./.env
make run
git clone https://github.com/mreza0100/shortly
cd shortly
cp ./.env.example ./.env
make dev-dependency
make dev
curl --location --request POST '10.0.0.10:10000/user/signup' \
--header 'Content-Type: application/json' \
--data-raw '{
"email": "mreza@gmail.com",
"password": "1234"
}'
curl --location --request POST '10.0.0.10:10000/user/signin' \
--header 'Content-Type: application/json' \
--data-raw '{
"email": "mreza@gmail.com",
"password": "1234"
}'
curl --location --request POST '10.0.0.10:10000/link' \
--header 'token: ${token}' \
--header 'Content-Type: application/json' \
--data-raw '{
"link": "google.com"
}'
10.0.0.10:10000/${short_key}
The last target of this app is to respond to 10000 requests per second, but not for now as I didn't have enough time to implement it. but I will try to do it in the future and I will explain the idea of the future app.
- run:
go run cmd/shortly run
- seed:
go run cmd/shortly seed
- healthcheck:
go run cmd/shortly healthcheck
KGS
: KGS = Key Generation System - is a driven adapter used to generate keys. used by service.
Counter
: the counter is the serial numbers that KGS walks on to generate the short keys.
Shortkey
: The short key is the serial numbers that KGS creates for the links. Example: 10.0.0.10:10000/${short_key}
Destination
: The destination is the value that shortkey is mapped to. Example: google.com
- run: run the HTTP server with the given port from the environment variable.
- seed: seed the database with randomly generated data.
- healthcheck: check the health of the app. healthcheck is implemented for the docker-compose.yml file to make sure the connection between the app and database is working.
Unfortunately, I didn't have time to implement the integration tests. But I considered tests and mocking dependencies from the beginning of the project in the dependency injections.
- Hexagonal Architecture
- Domain Driven Design
-
cmd
: The entry point of the app, contains the commands to run and initialize the app. -
pkg
: packages that can be used by the outside world or can use in other projects. not customized to this project. -
internals/
adapters
: contains the driving and drived packages. more explanation in the adapters section below.models
: contains the models that can be used by the app.pkg
: packages that can be used by the app. customized to this project.ports
: contains the interfaces that are shared by the packages to interact with each other.services
: contains the business logic of the app.
- Rest API
- GraphQL API
- gRPC API
- Command Line Interface
- Repository
- KGS special for this project
- Cache database Repository
- Internal cache Layer
- Extra code from services that can be a utility for the services.
βββββββββββββββββββββ
β β
β Cassandra β
β Storage Adapter β
β β
βββββββββββ²ββββββββββ
β
βββββββββββΌββββββββββ
β β
β Service Domain β
β β
βββββββββββ²ββββββββββ
β
β
β
βββββββββββ΄ββββββββββ
β β
β Rest API Adapter β
β β
βββββββββββ²ββββββββββ
β
β
β
β
βββββββββββ΄ββββββββββ
β β
βBrowser Cache Layerβ
βββββββββββββββββββββ
- Change architecture to microservices.
- Make KGS a new service with cached data to solve the latency issue about the real-time generation of short links.
- Implement CQS (Command-Query Separation).
- Make link shortener a microservice cluster with a load balancer between reading and write services.
- Implement an internal cache layer for HOT links in the code to improve the performance of the app.
- Add a Redis cache layer for the app.
βββββββββββββββββββββββββββ
β β
β β
β Final Storage Layer β
β β
β β
β β
β β
ββββββββββββ²βββββββββββββββ
β
β
β
βββββββββββββββββββββ β ββββββββββββββββββββ
β βββ β β β
βRedis Cache Adapterβ β β βInternal Cache β
β β β β βββββΊ Adapterβ
βββββββββββββββββββββ2β β3 β 1ββββββββββββββββββββ
β β β
βββ΄ββββββββ΄ββββββββββ€
β β
β Service Domain β
β β
βββββββββββ²ββββββββββ
β
βββββββββββ΄ββββββββββ
β β
β Rest API Adapter β
β β
βββββββββββ²ββββββββββ
β
β
βββββββββββ΄ββββββββββ
β β
β β
βBrowser Cache Layerβ
β β
βββββββββββββββββββββ