A very performant and light (2mb in memory) link shortener and tracker. Written in Rust and React and uses Postgres/SQLite.
1# Link Shortener API Documentation 2 3## Base URL 4`http://localhost:8080` 5 6## Authentication 7The API uses JWT tokens for authentication. Include the token in the Authorization header: 8``` 9Authorization: Bearer <your_token> 10``` 11 12### Register 13Create a new user account. 14 15```bash 16POST /api/auth/register 17``` 18 19Request Body: 20```json 21{ 22 "email": string, // Required: Valid email address 23 "password": string // Required: Password 24} 25``` 26 27Example: 28```bash 29curl -X POST http://localhost:8080/api/auth/register \ 30 -H "Content-Type: application/json" \ 31 -d '{ 32 "email": "user@example.com", 33 "password": "your_password" 34 }' 35``` 36 37Response (200 OK): 38```json 39{ 40 "token": "eyJ0eXAiOiJKV1QiLCJhbGc...", 41 "user": { 42 "id": 1, 43 "email": "user@example.com" 44 } 45} 46``` 47 48### Login 49Authenticate and receive a JWT token. 50 51```bash 52POST /api/auth/login 53``` 54 55Request Body: 56```json 57{ 58 "email": string, // Required: Registered email address 59 "password": string // Required: Password 60} 61``` 62 63Example: 64```bash 65curl -X POST http://localhost:8080/api/auth/login \ 66 -H "Content-Type: application/json" \ 67 -d '{ 68 "email": "user@example.com", 69 "password": "your_password" 70 }' 71``` 72 73Response (200 OK): 74```json 75{ 76 "token": "eyJ0eXAiOiJKV1QiLCJhbGc...", 77 "user": { 78 "id": 1, 79 "email": "user@example.com" 80 } 81} 82``` 83 84## Protected Endpoints 85 86### Health Check 87Check if the service and database are running. 88 89```bash 90GET /health 91``` 92 93Example: 94```bash 95curl http://localhost:8080/health 96``` 97 98Response (200 OK): 99```json 100"Healthy" 101``` 102 103Response (503 Service Unavailable): 104```json 105"Database unavailable" 106``` 107 108### Create Short URL 109Create a new shortened URL with optional custom code. Requires authentication. 110 111```bash 112POST /api/shorten 113``` 114 115Request Body: 116```json 117{ 118 "url": string, // Required: The URL to shorten 119 "custom_code": string, // Optional: Custom short code 120 "source": string // Optional: Source of the request 121} 122``` 123 124Examples: 125 1261. Create with auto-generated code: 127```bash 128curl -X POST http://localhost:8080/api/shorten \ 129 -H "Content-Type: application/json" \ 130 -H "Authorization: Bearer YOUR_TOKEN" \ 131 -d '{ 132 "url": "https://example.com", 133 "source": "curl-test" 134 }' 135``` 136 137Response (201 Created): 138```json 139{ 140 "id": 1, 141 "user_id": 1, 142 "original_url": "https://example.com", 143 "short_code": "Xa7Bc9", 144 "created_at": "2024-03-01T12:34:56Z", 145 "clicks": 0 146} 147``` 148 1492. Create with custom code: 150```bash 151curl -X POST http://localhost:8080/api/shorten \ 152 -H "Content-Type: application/json" \ 153 -H "Authorization: Bearer YOUR_TOKEN" \ 154 -d '{ 155 "url": "https://example.com", 156 "custom_code": "example", 157 "source": "curl-test" 158 }' 159``` 160 161Response (201 Created): 162```json 163{ 164 "id": 2, 165 "user_id": 1, 166 "original_url": "https://example.com", 167 "short_code": "example", 168 "created_at": "2024-03-01T12:34:56Z", 169 "clicks": 0 170} 171``` 172 173Error Responses: 174 175Invalid URL (400 Bad Request): 176```json 177{ 178 "error": "URL must start with http:// or https://" 179} 180``` 181 182Custom code taken (400 Bad Request): 183```json 184{ 185 "error": "Custom code already taken" 186} 187``` 188 189Invalid custom code (400 Bad Request): 190```json 191{ 192 "error": "Custom code must be 1-32 characters long and contain only letters, numbers, underscores, and hyphens" 193} 194``` 195 196Unauthorized (401 Unauthorized): 197```json 198{ 199 "error": "Unauthorized" 200} 201``` 202 203### Get All Links 204Retrieve all shortened URLs for the authenticated user. 205 206```bash 207GET /api/links 208``` 209 210Example: 211```bash 212curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:8080/api/links 213``` 214 215Response (200 OK): 216```json 217[ 218 { 219 "id": 1, 220 "user_id": 1, 221 "original_url": "https://example.com", 222 "short_code": "Xa7Bc9", 223 "created_at": "2024-03-01T12:34:56Z", 224 "clicks": 5 225 }, 226 { 227 "id": 2, 228 "user_id": 1, 229 "original_url": "https://example.org", 230 "short_code": "example", 231 "created_at": "2024-03-01T12:35:00Z", 232 "clicks": 3 233 } 234] 235``` 236 237### Redirect to Original URL 238Use the shortened URL to redirect to the original URL. Source tracking via query parameter is supported. 239 240```bash 241GET /{short_code}?source={source} 242``` 243 244Example: 245```bash 246curl -i http://localhost:8080/example?source=email 247``` 248 249Response (307 Temporary Redirect): 250```http 251HTTP/1.1 307 Temporary Redirect 252Location: https://example.com 253``` 254 255Error Response (404 Not Found): 256```json 257{ 258 "error": "Not found" 259} 260``` 261 262## Custom Code Rules 2631. Length: 1-32 characters 2642. Allowed characters: letters, numbers, underscores, and hyphens 2653. Case-sensitive 2664. Cannot use reserved words: ["api", "health", "admin", "static", "assets"] 267 268## Rate Limiting 269Currently, no rate limiting is implemented. 270 271## Notes 2721. All timestamps are in UTC 2732. Click counts are incremented on successful redirects 2743. Source tracking is supported both at link creation and during redirection via query parameter 2754. Custom codes are case-sensitive 2765. URLs must include protocol (http:// or https://) 2776. All create/read operations require authentication 2787. Users can only see and manage their own links 279 280## Error Codes 281- 200: Success 282- 201: Created 283- 307: Temporary Redirect 284- 400: Bad Request (invalid input) 285- 401: Unauthorized (missing or invalid token) 286- 404: Not Found 287- 503: Service Unavailable 288 289## Database Schema 290```sql 291-- Users table for authentication 292CREATE TABLE users ( 293 id SERIAL PRIMARY KEY, 294 email VARCHAR(255) NOT NULL UNIQUE, 295 password_hash TEXT NOT NULL 296); 297 298-- Links table with user association 299CREATE TABLE links ( 300 id SERIAL PRIMARY KEY, 301 original_url TEXT NOT NULL, 302 short_code VARCHAR(8) NOT NULL UNIQUE, 303 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), 304 clicks BIGINT NOT NULL DEFAULT 0, 305 user_id INTEGER REFERENCES users(id) 306); 307 308-- Click tracking with source information 309CREATE TABLE clicks ( 310 id SERIAL PRIMARY KEY, 311 link_id INTEGER REFERENCES links(id), 312 source TEXT, 313 query_source TEXT, 314 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() 315); 316 317-- Indexes 318CREATE INDEX idx_short_code ON links(short_code); 319CREATE INDEX idx_user_id ON links(user_id); 320CREATE INDEX idx_link_id ON clicks(link_id); 321```