URL Shortener
A small, complete app built around Angular and Spring Boot. You paste a long URL, get a short one back, and the API redirects anyone who opens it.
I built it alone.

The problem
I wanted a small app that covers the whole path of a web request: a field in the browser, a REST API, and a relational database. A URL shortener has that shape, with one table and two endpoints.
Decisions
A DTO and mapper in a small app
The first working version passed the entity between layers. Once the controller, service, and database worked, I added a record DTO and a MapStruct mapper, so the API contract is separate from the table. For one table this adds files, and it keeps the persistence model out of the HTTP layer.
Four random letters as the code
The service generates four random lowercase letters, which gives short, readable links and 456,976 possible codes. The trade-off is collisions: the database rejects a duplicate code through the unique constraint, but the service does not retry yet, and the README says so.
Schema managed by Hibernate
I let Hibernate create the table with ddl-auto=update instead of writing migrations. With one table and no deployed data, setup comes down to one CREATE DATABASE, at the cost of no versioned schema history.
What I built
- A Spring Boot 4 REST API in Java 17 with two endpoints: one that creates a short code and one that redirects with 302 or returns 404.
- A JPA entity and a Spring Data repository with a derived query that finds a link by its code, backed by a unique constraint on the code column in PostgreSQL.
- A Java record as the DTO and a MapStruct mapper between it and the entity, so the controller receives and returns the DTO and never the persistence model.
- Code generation with Apache Commons Text’s RandomStringGenerator and a scheme check that prefixes https:// to bare addresses.
- An Angular 21 component that posts the address with HttpClient and shows the result through a signal, styled with Tailwind CSS 4.
- A README that documents setup, endpoints, configuration, tests, and the current limits of the app.
How it works
The Angular page binds the typed address to a text field with ngModel. When the user clicks Shorten Url, HttpClient sends it to POST /urlshortener/post. The Spring Boot service adds https:// when the address has no scheme, generates a four-letter lowercase code with Apache Commons Text, and saves the address and the code through Spring Data JPA into a PostgreSQL table. The API answers 201 Created with the id, the saved URL, and the code.
The page joins the back-end address with the returned code, stores the full link in an Angular signal, and shows it under the field. Opening that link hits GET /urlshortener/{code}. The service looks up the code through the repository, and the controller answers 302 Found with a Location header pointing to the original URL, or 404 Not Found when the code does not exist.
Hibernate creates or updates the table on startup. The database password comes from an environment variable, and Spring’s standard environment variables can override the connection URL and username. The controller allows cross-origin requests from the local Angular dev server.
Built with
- Front end
- Angular 21, TypeScript 5.9, Angular signals, HttpClient, Tailwind CSS 4
- Back end
- Java 17, Spring Boot 4.1, Spring Web MVC, Spring Data JPA, Hibernate, MapStruct, Lombok, Apache Commons Text
- Data
- PostgreSQL
- Tooling
- Maven, npm, Vitest, Prettier