remove API key requirement from POST /api/shorten
This commit is contained in:
@@ -124,15 +124,14 @@ Health check endpoint.
|
||||
|
||||
---
|
||||
|
||||
### `POST /api/shorten` 🔒
|
||||
Create a new short URL.
|
||||
### `POST /api/shorten`
|
||||
Create a new short URL. No API key required.
|
||||
|
||||
Fields can be passed as **query parameters** (URL-encoded) or in a **JSON request body**.
|
||||
Query parameters take precedence over body fields.
|
||||
|
||||
| Field | Required | Description |
|
||||
|------------------|----------|-----------------------------------------------------------|
|
||||
| `api_key` | ✅ | API key for authentication |
|
||||
| `url` | ✅ | The URL to shorten (must start with `http://` or `https://`) |
|
||||
| `retention_days` | | Override the default retention period for this URL |
|
||||
|
||||
@@ -221,10 +220,10 @@ Increments `visit_count` on each hit.
|
||||
# Shorten a URL (JSON body)
|
||||
curl -X POST http://localhost:8080/s/api/shorten \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"api_key": "change-this-secret-key", "url": "https://github.com"}'
|
||||
-d '{"url": "https://github.com"}'
|
||||
|
||||
# Shorten a URL (query parameters)
|
||||
curl -X POST "http://localhost:8080/s/api/shorten?api_key=change-this-secret-key&url=https%3A%2F%2Fgithub.com&retention_days=30"
|
||||
curl -X POST "http://localhost:8080/s/api/shorten?url=https%3A%2F%2Fgithub.com&retention_days=30"
|
||||
|
||||
# Follow the redirect
|
||||
curl -L http://localhost:8080/s/aB3xYz
|
||||
@@ -248,7 +247,7 @@ curl "http://localhost:8080/s/api/lookup?url=https%3A%2F%2Fexample.com"
|
||||
|
||||
A clean single-page frontend is included in `static/`. It provides:
|
||||
|
||||
- **URL shortening** — paste a URL and press Enter to create a short URL (requires API key)
|
||||
- **URL shortening** — paste a URL and press Enter to create a short URL
|
||||
- **Existing URL lookup** — as you type a URL, the frontend checks if it already exists and shows its metadata
|
||||
- **Admin table** — enter a valid API key to see all shortened URLs in a sortable, paginated table
|
||||
- **Copy & Delete** — per-row copy and delete buttons (delete on hover only)
|
||||
|
||||
+18
-10
@@ -218,6 +218,7 @@ async function lookupUrl(url) {
|
||||
}
|
||||
|
||||
async function handleEnter() {
|
||||
clearTimeout(_lookupTimer); // cancel any pending debounced lookup
|
||||
const input = document.getElementById('url-input');
|
||||
const url = input.value.trim();
|
||||
if (!url || !isValidUrl(url)) {
|
||||
@@ -225,17 +226,27 @@ async function handleEnter() {
|
||||
setStatus('', '');
|
||||
return;
|
||||
}
|
||||
if (!state.apiKey) {
|
||||
// No API key — just do a lookup
|
||||
await lookupUrl(url);
|
||||
return;
|
||||
}
|
||||
|
||||
// First, check if this URL already exists
|
||||
setStatus('checking…', '');
|
||||
try {
|
||||
const lookupRes = await apiGet('/api/lookup?url=' + encodeURIComponent(url));
|
||||
if (lookupRes.ok) {
|
||||
// URL already exists — just show its metadata
|
||||
const data = await lookupRes.json();
|
||||
state.currentMeta = data;
|
||||
renderMeta(data);
|
||||
setStatus('exists', 'ok');
|
||||
return;
|
||||
}
|
||||
} catch { /* lookup failed, proceed to create */ }
|
||||
|
||||
// URL does not exist — attempt to create
|
||||
setStatus('creating…', '');
|
||||
try {
|
||||
const res = await apiPost('/api/shorten', { api_key: state.apiKey, url: url });
|
||||
const res = await apiPost('/api/shorten', { url: url });
|
||||
if (res.status === 201) {
|
||||
const shortUrl = await res.text();
|
||||
// Fetch metadata for the newly created URL
|
||||
const code = shortUrl.split('/').pop();
|
||||
const metaRes = await apiGet('/api/urls/' + encodeURIComponent(code));
|
||||
if (metaRes.ok) {
|
||||
@@ -243,11 +254,8 @@ async function handleEnter() {
|
||||
state.currentMeta = data;
|
||||
renderMeta(data);
|
||||
setStatus('created ✓', 'ok');
|
||||
// Refresh admin list
|
||||
if (state.isAdmin) fetchAdminUrls();
|
||||
}
|
||||
} else if (res.status === 403) {
|
||||
setStatus('invalid key', 'err');
|
||||
} else {
|
||||
const err = await res.json().catch(() => null);
|
||||
setStatus(err?.error || 'error', 'err');
|
||||
|
||||
+1
-5
@@ -6,7 +6,7 @@ Usage: python urlshort.py <config.json>
|
||||
API (all routes are prefixed with base_path, e.g. /s):
|
||||
GET / Frontend (or health check if no static/)
|
||||
GET /api/health Health check
|
||||
POST /api/shorten Create a short URL (API key required)
|
||||
POST /api/shorten Create a short URL (no API key required)
|
||||
GET /api/urls List all short URLs (API key required)
|
||||
GET /api/urls/<code> Get info for a code (no API key required)
|
||||
GET /api/lookup?url=<url> Look up by original URL (no API key required)
|
||||
@@ -433,10 +433,6 @@ class Handler(BaseHTTPRequestHandler):
|
||||
self._error(400, "Invalid JSON body")
|
||||
return
|
||||
|
||||
# Auth: check api_key from query param or body
|
||||
if not self._check_api_key(body):
|
||||
self._send_empty(403)
|
||||
return
|
||||
|
||||
# url: query param takes precedence, then body
|
||||
original_url = qs.get("url", [""])[0] or str(body.get("url", "")).strip()
|
||||
|
||||
Reference in New Issue
Block a user