malinichevvv / lift-skeleton
A starter URL-shortener microservice built on the Lift PHP micro-framework.
Package info
github.com/malinichevvv/lift-skeleton
Type:project
pkg:composer/malinichevvv/lift-skeleton
Requires
- php: >=8.1
- malinichevvv/lift-php: ^1.2
Requires (Dev)
- phpunit/phpunit: ^11.0
This package is auto-updated.
Last update: 2026-05-18 14:14:32 UTC
README
A small, production-shaped URL-shortener microservice built on the Lift PHP micro-framework.
It is meant as a starting point: clone it, read it in five minutes, then
replace the links resource with your own. Despite its size it exercises a
real slice of the framework — attribute routing, request validation, the
query builder, migrations, a cache layer, per-route middleware and a custom
console command.
Quick start
composer create-project malinichevvv/lift-skeleton myapp
cd myapp
composer serve
create-project copies .env, generates an APP_KEY and runs the migrations
for you. The service is now live on http://localhost:8000.
# Create a short link (API key is empty by default — see .env) curl -X POST http://localhost:8000/links \ -H 'Content-Type: application/json' \ -d '{"url": "https://www.php.net/releases/8.3/en.php"}' # -> {"slug":"aZ3kPq","short_url":"http://localhost:8000/aZ3kPq", ...} # Open the short link in a browser — it redirects, and the click is counted. open http://localhost:8000/aZ3kPq # Inspect the stats curl http://localhost:8000/links/aZ3kPq/stats
Endpoints
| Method | Path | Description | Auth |
|---|---|---|---|
GET |
/ |
Self-describing endpoint list | — |
GET |
/health |
Liveness + database probe (200 / 503) |
— |
POST |
/links |
Create a short link | X-API-Key |
GET |
/links/{slug}/stats |
Click statistics for a short link | — |
GET |
/{slug} |
Redirect to the original URL | — |
POST /links accepts JSON:
{ "url": "https://example.com", "slug": "optional-custom", "expires_in": 86400 }
slug is optional (a random one is generated); expires_in is optional
(seconds until the link stops resolving).
Authentication
POST /links is guarded by ApiKeyMiddleware. Set API_KEY in .env and send
it as the X-API-Key header. While API_KEY is empty every request is allowed
— handy locally, but set a key before deploying.
Project layout
app/
Controllers/ HealthController, LinkController — attribute-routed
Middleware/ ApiKeyMiddleware — PSR-15
Console/ PruneExpiredCommand — custom CLI command
bootstrap/app.php builds the App: env, config, services, middleware, routes
config/ app.php, database.php
database/migrations/ schema, run by `lift migrate`
public/index.php front controller
tests/ feature tests on an in-memory SQLite database
lift.php registers project console commands
Console
vendor/bin/lift ships with the framework; this project adds a few commands:
php vendor/bin/lift serve # development server php vendor/bin/lift migrate # run migrations php vendor/bin/lift routes:list # show registered routes php vendor/bin/lift links:prune # delete expired links (wire to cron) php vendor/bin/lift list # all available commands
Tests
composer test
Feature tests run against a fresh in-memory SQLite database — no setup, no external services.
Configuration
SQLite is the default and needs nothing. To use MySQL/PostgreSQL or Redis,
uncomment the relevant block in .env. Redis, when configured, backs the
slug → URL lookup cache.
Docker
docker compose up --build
Brings up the service (with lift serve) plus a Redis container.
License
MIT — see LICENSE.