Free API for Pet Projects: Self-Contained Keys & Rate Limiting
Developers often showcase frontend apps during interviews using data from localStorage or jsonplaceholder. This simplifies development without server costs, but results in static data and artificial delays via setTimeout. A better alternative? A platform with real APIs where you can upload your own data. Setup takes just minutes—no backend required.
The architecture uses Next.js for the web interface with SSG, Node.js/Express to manage users and keys, and a dedicated API service. Everything runs in Docker with an Nginx proxy.
Free Access Challenges & the API Key Solution
Without limits, anyone could flood the system with spam requests, quickly exhausting resources. The key strategy? Minimize database queries and filter invalid keys at parsing time.
Keys are self-contained, formatted as ppk_version_userId_nonce_signature. Authentication uses: Authorization: PetProjects ppk_v1_1_nonce_signature.
Validation happens in two steps:
- Local validation: structure and HMAC signature checked without touching the database.
- Database lookup for userId only after initial validity is confirmed.
function validateApiKey(apiKey: string): ApiKeyPayload | null {
if (!apiKey.startsWith('ppk_')) return null;
const parts = apiKey.split('_');
if (parts.length !== 5) return null;
const [, version, userIdRaw, nonce, signature] = parts;
const userId = Number(userIdRaw);
if (!Number.isInteger(userId)) return null;
if (!signature || !/^[a-f0-9]{64}$/.test(signature)) return null;
const payload = `${version}.${userId}.${nonce}`;
const expectedSignature = crypto.createHmac('sha256', API_KEY_SECRET).update(payload).digest('hex');
if (signature.length !== expectedSignature.length) return null;
const isValid = crypto.timingSafeEqual(Buffer.from(signature, 'hex'), Buffer.from(expectedSignature, 'hex'));
if (!isValid) return null;
return { version, userId, nonce };
}
timingSafeEqual prevents timing attacks. Valid keys are cached in LRUCache (max: 10,000 entries, TTL: 5 minutes).
Caching & Performance Balance
Caching reduces latency and database load. The 5-minute TTL is a trade-off: leaked keys remain active until expiration, then require revalidation.
Limitations:
- No instant key revocation.
- Leaked keys stay valid until TTL expires.
- Secrets must be protected.
Potential improvements: blacklist support, key versioning, and dynamic revocation.
Playground for API Testing
An interactive interface lets you send requests directly from the browser with auto-filled keys. It generates code examples for multiple languages.
Example POST:
curl -L -X POST 'https://api.pet-projects.io/rest/free' \
-H 'Authorization: PetProjects ppk_v1_1_a1b2c3d4e5_a1b2c3d4e5f6g7h8i10j11' \
-H 'Content-Type: application/json' \
-d '{"hello":"world"}'
Response in JSend format:
{
"status": "success",
"data": {
"id": 99,
"payload": {
"hello": "world"
},
"createdAt": 1774297745939,
"updatedAt": 1774297745939
}
}
Scaling & Future Enhancements
The system minimizes database calls, resists abuse, and balances security with speed. As traffic grows, monitoring cache and key usage will become essential.
Benefits for mid/senior developers:
- Real endpoints instead of mocks.
- Personal data without deployment.
- Fast HMAC validation + caching.
- Built-in playground for debugging.
- Docker-based architecture for scalability.
Key takeaways:
- Self-contained keys filter out 99% of junk without DB access.
- LRUCache with 5-minute TTL cuts database load by over 90%.
timingSafeEqualdefends against timing attacks.- Two-step validation: local check + DB lookup for valid keys.
- JSend responses standardize API behavior.
— Editorial Team
No comments yet.