A production-ready GraphQL API template built with Mezzio, FrankenPHP, and PostgreSQL
This template provides a complete foundation for building modern GraphQL APIs with authentication, database migrations, and comprehensive development tooling.
- Use this template to create a new repository
- Clone your new repository locally
- Follow the Getting Started instructions below
- Customize the application for your specific needs
- GraphQL-First Architecture: All data operations through
/graphqlendpoint - Modern PHP Stack: PHP 8.4 with FrankenPHP for high performance
- Authentication Ready: OAuth2 with PKCE, magic links, and JWT tokens
- Database Migrations: Automated PostgreSQL migrations with Phinx
- Development Tools: Docker, Xdebug, PHPUnit, PHPCS, PHPStan
- CI/CD Ready: GitHub Actions for testing and code quality
- Vector Database: Weaviate integration for AI/ML features
Built on mezzio which builds on laminas-stratigility to provide a minimalist PSR-15 middleware framework for PHP with routing, DI container, optional templating, and optional error handling capabilities.
This project uses Docker for development to ensure consistent environments. The setup includes:
- PHP 8.4 with FrankenPHP (high-performance PHP application server)
- Built-in Caddy web server with HTTP/2 and automatic HTTPS
- Xdebug support for development debugging
- Local PostgreSQL database for authentication
- External Weaviate vector database access via Docker networks
- Development tools (PHPUnit, PHPCS, Psalm)
Architecture: This is a GraphQL-first API application. All data operations go through the /graphql endpoint rather than traditional REST endpoints.
- Start the development environment:
docker compose up -d- Install dependencies:
docker compose exec app-api composer install- Set up environment variables (database configuration is now environment-based):
# Copy the example environment file
cp .env.example .env
# Edit .env with your database credentials- Run database migrations:
docker compose exec app-api composer migrate- Access the application:
# The application will be available at:
http://localhost:8088
# Health check endpoint (returns JSON with PostgreSQL status):
http://localhost:8088/health
# Ping endpoint:
http://localhost:8088/ping
# GraphQL endpoint:
http://localhost:8088/graphqlThe /health endpoint provides comprehensive health status information:
{
"status": "ok",
"timestamp": 1640995200,
"checks": {
"postgres": {
"status": "ok",
"message": "PostgreSQL database connection successful"
}
}
}Status Codes:
200 OK- All health checks pass503 Service Unavailable- One or more health checks fail
Configuration:
- Docker health checks are disabled in development (commented out in Dockerfile)
- Uncomment the
HEALTHCHECKdirective in production for monitoring
Future Enhancements:
- Weaviate vector database connectivity check will be added
The development environment exposes the following services:
| Service | Internal Port | External Port | URL |
|---|---|---|---|
| API Application | 80 | 8088 | http://localhost:8088 |
| PostgreSQL Database | 5432 | 5434 | localhost:5434 |
Note: External Weaviate access is configured via Docker networks and doesn't expose ports directly.
All development tools run inside the Docker container to ensure consistency:
# Run all checks (code style, static analysis, and tests)
docker compose exec app-api composer check
# Individual tools
docker compose exec app-api composer cs-check # Code style check
docker compose exec app-api composer cs-fix # Code style fix
docker compose exec app-api composer test # Unit tests
docker compose exec app-api composer static-analysis # Static analysis
# Database migrations
docker compose exec app-api composer migrate # Run migrations
docker compose exec app-api composer migrate-status # Check migration status
docker compose exec app-api composer migrate-rollback # Rollback last migration
# Database seeds
docker compose exec app-api composer seed # Run all seeds
docker compose exec app-api composer seed-create # Create a new seed fileThis project includes laminas-development-mode.
# Enable development mode
docker compose exec app-api composer development-enable
# Disable development mode
docker compose exec app-api composer development-disable
# Check status
docker compose exec app-api composer development-statusNote: Development mode enables:
- Detailed error pages with Whoops
- Configuration caching disabled
- Development-specific middleware
Xdebug is pre-configured for development debugging. To use it with your IDE:
- Install the "PHP Debug" extension
- Create a
.vscode/launch.jsonfile:
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/app": "${workspaceFolder}"
}
}
]
}- Go to Settings β PHP β Debug
- Set Xdebug port to 9003
- Configure path mappings:
/appβ your project root - Set the IDE key to
PHPSTORMin your environment:
export XDEBUG_IDEKEY=PHPSTORMYou can customize Xdebug behavior with these environment variables:
XDEBUG_MODE: Set debug modes (default:debug,develop)XDEBUG_CLIENT_HOST: IDE host (default:host.docker.internal)XDEBUG_CLIENT_PORT: IDE port (default:9003)XDEBUG_IDEKEY: IDE identifier (default:VSCODE)
The development environment includes a local PostgreSQL database with the following default settings:
- Database Name:
zestic_api - Username:
zestic - Password:
password1 - Host:
postgres(container name) - Port:
5434(external),5432(internal)
The database configuration is environment-based and will automatically use the environment variables you set in your .env file. The configuration will fail fast if any required database environment variables are not set.
To connect to the database from your host machine (e.g., using a database client):
# Connection details for external access
Host: localhost
Port: 5434
Database: zestic_api
Username: zestic
Password: password1You can customize the database configuration using these environment variables in your .env file:
# PostgreSQL Docker container configuration
POSTGRES_DB=zestic_api
POSTGRES_USER=zestic
POSTGRES_PASSWORD=password1
# Application database connection configuration
DB_HOST=postgres
DB_PORT=5432
DB_NAME=zestic_api
DB_USER=zestic
DB_PASSWORD=password1
DB_SCHEMA=publicThe application is configured to connect to an external Weaviate instance via Docker networks:
- Default URL:
http://weaviate:8080 - Network:
zestic-api-network
To connect to a different Weaviate instance, set the WEAVIATE_URL environment variable:
WEAVIATE_URL=http://your-weaviate-host:8080Note: The Weaviate service should be on the same Docker network (zestic-api-network) for container-to-container communication.
The FrankenPHP Docker image includes common PHP extensions, but you may need to add additional ones. To add PHP extensions:
- Install system dependencies (if required) in the Dockerfile:
RUN apt-get update && apt-get install -y \
libicu-dev \ # For intl extension
libxslt1-dev \ # For xsl extension
libxml2-dev \ # For xml-related extensions
&& rm -rf /var/lib/apt/lists/*- Install PHP extensions using
docker-php-ext-install:
RUN docker-php-ext-install \
intl \
xsl \
bcmath \
gd- For PECL extensions (like xdebug):
RUN pecl install xdebug \
&& docker-php-ext-enable xdebug- Rebuild the container after adding extensions:
docker compose down
docker compose up -d --buildCurrent Extensions: The template includes pdo, pdo_pgsql, intl, xsl, and xdebug extensions.
By default, the skeleton will create a configuration cache in
data/config-cache.php. When in development mode, the configuration cache is
disabled, and switching in and out of development mode will remove the
configuration cache.
You may need to clear the configuration cache in production when deploying if you deploy to the same directory. You may do so using the following:
docker compose exec app-api composer clear-config-cacheBefore contributing read the contributing guide.
If you encounter issues:
- Ensure Docker is running and containers are healthy:
docker compose ps- Check container logs:
docker compose logs- Try rebuilding the containers:
docker compose down
docker compose up -d --build- Clear Composer's cache:
docker compose exec app-api composer clear-cacheFor more detailed troubleshooting, refer to the Mezzio documentation.