This commit is contained in:
2026-03-17 15:45:46 +08:00
commit 04261c59cc
7 changed files with 567 additions and 0 deletions
+151
View File
@@ -0,0 +1,151 @@
# URL Shortener
A minimal URL shortener written in pure Python 3.8+ (zero third-party dependencies) backed by SQLite.
## Quick start
### Run locally
```bash
python urlshort.py config.json
```
### Run with Docker Compose
Edit `config.json` first (especially `api_key` and `base_url`), then:
```bash
docker compose up --build
```
The SQLite database is stored in `./data/urlshort.db` on the host — it survives container restarts.
---
## Configuration (`config.json`)
| Key | Required | Default | Description |
|----------------|----------|----------------------|----------------------------------------------|
| `base_url` | ✅ | — | Public base URL used in generated short URLs |
| `short_length` | ✅ | — | Character length of auto-generated codes |
| `api_key` | ✅ | — | Secret key to protect write/read operations |
| `host` | | `"0.0.0.0"` | Bind address |
| `port` | | `8080` | Bind port |
| `db_path` | | `"data/urlshort.db"` | Path to the SQLite database file |
---
## Authentication
All `/api/*` endpoints require the API key.
Pass it as a **Bearer token** in the `Authorization` header or as a query parameter:
```
Authorization: Bearer <api_key>
# or
?api_key=<api_key>
```
---
## API Reference
### `GET /`
Health check.
**Response `200`**
```json
{ "status": "ok", "service": "url-shortener" }
```
---
### `POST /api/shorten` 🔒
Create a new short URL.
**Request body**
```json
{
"url": "https://example.com/very/long/path",
"custom_code": "mycode" // optional
}
```
**Response `201`**
```json
{
"short_code": "aB3xYz",
"short_url": "http://localhost:8080/aB3xYz",
"original_url": "https://example.com/very/long/path",
"created_at": 1710000000
}
```
---
### `GET /api/urls` 🔒
List all short URLs, newest first.
**Response `200`**
```json
{
"count": 2,
"urls": [
{
"short_code": "aB3xYz",
"short_url": "http://localhost:8080/aB3xYz",
"original_url": "https://example.com",
"created_at": 1710000000,
"visit_count": 5
}
]
}
```
---
### `GET /api/urls/<code>` 🔒
Get metadata for a single short code.
**Response `200`** — same shape as one item from the list above.
**Response `404`** — code not found.
---
### `DELETE /api/urls/<code>` 🔒
Delete a short URL entry.
**Response `200`**
```json
{ "message": "Deleted 'aB3xYz'" }
```
---
### `GET /<code>`
Redirect to the original URL (HTTP 302).
Increments `visit_count` on each hit.
---
## Example with `curl`
```bash
# Shorten a URL
curl -X POST http://localhost:8080/api/shorten \
-H "Authorization: Bearer change-this-secret-key" \
-H "Content-Type: application/json" \
-d '{"url": "https://github.com"}'
# Follow the redirect
curl -L http://localhost:8080/aB3xYz
# List all URLs
curl http://localhost:8080/api/urls \
-H "Authorization: Bearer change-this-secret-key"
# Delete a URL
curl -X DELETE http://localhost:8080/api/urls/aB3xYz \
-H "Authorization: Bearer change-this-secret-key"
```