Skip to content

Repository files navigation

UrlShortenerAPI

build

A small URL shortener REST API built with ASP.NET Core 8, EF Core, and PostgreSQL. Post a long URL, get back an 8-character token; request the token and get a 302 redirect to the original. Links expire after 30 days.

Stack

Runtime .NET 8 (net8.0)
Web ASP.NET Core, attribute-routed controllers
Data EF Core 8.0.30 + Npgsql 8.0.11, PostgreSQL
Tests xUnit + Moq + EF Core InMemory — 13 tests

API

Method Route Body / Param Response
POST /api/urls { "originalUrl": "https://example.com" } 200 { shortUrlToken, fullShortUrl } · 400 on empty or malformed URL
GET /api/urls/{shortUrl} short token in path 302 redirect to the original · 404 if unknown or expired

Posting a URL that already exists returns the existing token rather than minting a second one.

Quickstart

You need the .NET 8 SDK and a reachable PostgreSQL instance.

git clone https://github.com/Ar4gornn/UrlShortenerAPI.git
cd UrlShortenerAPI

The connection string is not in source control. Create UrlShortenerAPI/appsettings.Development.json (already gitignored):

{
  "ConnectionStrings": {
    "UrlShortenerDB": "Host=localhost;Port=5432;Database=urlshortener;Username=postgres;Password=your-password"
  }
}

Apply the migrations and run:

dotnet ef database update --project UrlShortenerAPI/UrlShortenerAPI.csproj
dotnet run --project UrlShortenerAPI/UrlShortenerAPI.csproj

The API listens on http://localhost:5251. Try it:

curl -X POST http://localhost:5251/api/urls \
  -H "Content-Type: application/json" \
  -d '{"originalUrl":"https://learn.microsoft.com/aspnet/core"}'

curl -i http://localhost:5251/api/urls/<token>

Run the tests:

dotnet test

Architecture

A thin three-layer slice. UrlsController handles HTTP concerns only — model validation and mapping exceptions to status codes. UrlShortenerService holds the business rules: URL well-formedness via Uri.IsWellFormedUriString, deduplication against existing rows, token generation, and the expiry check on read. UrlShortenerContext is the EF Core boundary, with three migrations tracked in Migrations/. The service is registered scoped and injected through IUrlShortenerService, so the controller tests mock the interface and the service tests run against an in-memory provider.

Tokens are the first 8 characters of a Guid, and expiry is 30 days from creation.

Known limitations

Honest list — these are real, and they are the roadmap.

  • Token collisions are not handled. Tokens are truncated GUIDs with no uniqueness check before insert, and the read path uses SingleOrDefaultAsync, which throws if a duplicate ever lands.
  • fullShortUrl hardcodes http://localhost:5251. The response is wrong anywhere but a local dev machine.
  • The Dockerfile does not work. It builds on the .NET 8 SDK image but runs on the ASP.NET 7.0 runtime image, so the published net8.0 assembly will not start. Fix before trusting it.
  • CORS is AllowAnyOrigin + any method + any header. Fine for local development, not for a public deployment.
  • No Swagger UI. Microsoft.AspNetCore.OpenApi is referenced but never wired up in Program.cs.
  • AppConstants.LinkExpirationDays and the private GenerateUniqueGuidToken() helper are both dead code — the 30-day window is inlined in the service instead.

Roadmap

  • Collision-safe token generation (retry loop or a counter-based encoding), plus a unique index
  • Base URL from configuration instead of a hardcoded localhost string
  • Fix the Dockerfile runtime tag and add a docker compose with PostgreSQL
  • Swagger/OpenAPI
  • Tighten CORS to a configured origin list
  • Hit counter per link

License

MIT — see LICENSE.

About

REST API that shortens URLs to 8-character tokens and 302-redirects them back. ASP.NET Core 8, EF Core, PostgreSQL, 13 xUnit tests, CI on every push.

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages