kURLy - a microservice for URL shortening written in Kotlin.
- develop a small microservice with a single endpoint that takes a big URL and responds with a shortened version
- when sending the shortened URL to another endpoint, the service redirects to the desired destination URL
- clean code covered with unit tests
- embedded database like H2
- readme file with instruction on how to run the service
The desired microservice is located in [kurly-service] module. Additionally, I developed some infrastructure around this microservice in order to demonstrate how it works in a real microservices environment. More info in Implementation section.
This section describes various ways of deploying the application in development environment (localhost).
Before the first build you need to take additional steps.
- Clone the repository
- Install JDK 19+
- Install Docker + Docker Compose
This project uses Gradle build tool for simplifying build process and dependency management. It's distributed with a Gradle Wrapper so you don't need to download and install Gradle yourself.
./gradlew build [-x test]
The fastest way to run this application locally is to build artifacts with Gradle and then run docker-compose -f docker-compose.dev.yml up
.
docker-compose.dev.yml is configured to build images locally and expose containers ports for convenient development.
Define environment variable SPRING_PROFILES_ACTIVE=local
.
You can run the developed microservice in a standalone mode:
./gradlew :kurly-service:bootRun
Or run microservices one by one (to get infrastructure up & running).
-
Required:
./gradlew :discovery-server:bootRun ./gradlew :config-server:bootRun ./gradlew :kurly-service:bootRun
-
Optional:
./gradlew :kurly-app:bootRun ./gradlew :turbine:bootRun ./gradlew :hystrix-dashboard:bootRun
- Import root project in IntelliJ IDEA
- Sync project files with Gradle (initial sync may happen automatically)
- Now you should have multiple run configurations for every module. Run them one-by-one:
- DiscoveryServerApplication
- ConfigServerApplication
- KurlyServiceApplication
- KurlyAppApplication
- TurbineApplication
- HystrixDashboardApplication
Tip: if you run multiple instances of the same service (scaling), make sure that you run them on different ports and these ports are free, otherwise you'll get an error.
When runnning in Docker, database type is MySQL and it's shared between kurly-service
instances.
Connection string:
jdbc:mysql://localhost:3306/kurly
When running via Gradle or IntelliJ IDEA, database type is H2 in-memory (embedded mode).
Database data doesn't survive kurly-service
restart.
Connection string:
jdbc:h2:mem:testdb
- http://localhost:9000 - Kurly Service (back-end)
- http://localhost:8761 - Eureka Dashboard
Less important endpoints:
- http://localhost:8080/hystrix - Hystrix Dashboard
- http://localhost:3000/turbine.stream - Turbine Stream (not exposed in Docker)
- http://localhost:8888 - Configuration Service (not exposed in Docker)
- http://localhost:8000 - Kurly Application (front-end, not ready yet)
POST /shorten
body:{"url": "https://long.url/"}
GET /:shortCode
API documentation is available at http://localhost:9000/swagger-ui/index.html
There're unit and integration tests in [kurly-service] module.
Additionally, there're primitive contextLoads
tests in other modules.
Test coverage of kurly-service: 84% LoC |
HTTPie commands (assuming kurly-service
is running on localhost:9000
):
http post localhost:9000/shorten url="https://placekitten.com/200/287"
http get localhost:9000/1
Travis CI builds and tests the application
The main part of this project is kurly-service
module - a microservice for URL shortening.
This project demonstrates such features of microservices architecture as:
- Service Discovery (Eureka)
- Centralized Configuration (git repo)
- Circuit Breaker (Hystrix)
- Monitoring (Turbine + Hystrix Dashboard)
💀 Deprecation Notice
Turbine and Hystrix are currently in maintenance mode. The related microservices are not working after update to Spring Boot 3 and Spring Cloud 2022.0.
The implemented URL shortening service assigns a unique key to every long URL passed to /shorten
endpoint.
For the sake of simplicity, entity ID is used as a unique key.
For better scalability, a numeric ID (base 10) is converted to alphanumeric representation (base 64) using base conversions.
Which results in shorter keys and therefore shorter links. A custom Base64 charset contains:
10 digits + 26 uppercase letters + 26 lowercase letters + dash + underscore
A short link produced by kURLy looks like http://localhost:9000/1aTd0H
(case sensitive) and consists of baseUrl
+ shortLink
.
The baseUrl
is configurable for easier deployment / domain migration.
The short code is stored in DB and when GET request is processed it's used to retrieve a corresponding long URL.
If the retrieval is successful, kurly-service
redirects to the long URL (302 Found
).
An original URL may be very long (browsers support up to ~200KB strings)
so the corresponding column type in DB is MEDIUMTEXT
in order to fit any URL.
- Kotlin
- Gradle
- IntelliJ IDEA
- Docker + Docker Compose
- Spring Boot 3
- Spring Cloud
- Spring Data
- Hibernate
- Travis CI
- Git
- Database: H2 or MySQL
- OpenAPI 3
...
The project is not finished yet. Future work:
kurly-app
module which should be a gateway tokurly-service
.- Open UI documentation
- Design and front-end
- HTTPS
- Public deployment
- Load testing
- Improvement: filter allowed protocols
- Improvement: collect analytics
- Migrate from Hystrix-Turbine to some other tool compatible with a modern Spring Cloud