kipchak/starter

Kipchak PHP API Development Kit (ADK) Starter Project

Maintainers

Package info

1x.ax/mamluk/kipchak/starter

Homepage

Type:template

pkg:composer/kipchak/starter

Statistics

Installs: 2

Dependents: 0

Suggesters: 0


README

Kipchak Starter

This is the starter project for Kipchak — a PHP 8.4+ API Development Kit (ADK) built on top of Slim Framework v4 and optimised for FrankenPHP in worker mode.

The starter demonstrates all bundled drivers and middlewares, lays out an opinionated project structure, and is fully usable as a vanilla Slim application. Nothing in Slim is restricted.

For complete documentation, visit https://kipchak.dev.

Install

composer create-project kipchak/starter [api-name] -s dev

Replace [api-name] with the directory name for your new project.

Running with Docker

The starter ships with a docker-compose.yml that brings up the full stack:

docker compose up

This starts the following services:

ServiceDescriptionPort(s)
apiFrankenPHP + Kipchak80, 2019
mysqlMySQL 8internal
couchdbApache CouchDB 3.55984
memcachedMemcached 1.6internal
rabbitmqRabbitMQ 4 with management UI5672, 15672

Hot-reload is enabled via Docker Compose watch — changes to your code restart the worker automatically.

CouchDB first-run setup

CouchDB requires a _users database on first start. Run once after docker compose up:

curl -X PUT http://api:api@localhost:5984/_users
curl -X PUT http://api:api@localhost:5984/api

Project Structure

├── api/
│   ├── Controllers/        # HTTP request handlers, versioned under v1/, v2/, etc.
│   ├── DataTransferObjects/ # Input/output contracts, versioned alongside controllers
│   ├── Entities/           # Database schema representations (Doctrine ORM, CouchDB)
│   ├── Middlewares/        # Custom per-project middleware
│   └── Models/             # Business logic
├── config/                 # PHP config files (one per driver/middleware)
├── drivers/
│   └── drivers.php         # Driver initialisation order
├── middlewares/
│   └── middlewares.php     # Global middleware registration
├── routes/                 # Route definitions, versioned under v1/, v2/, etc.
└── html/
    ├── index.php           # FrankenPHP worker-mode entry point
    └── index.nonworker.php # Standard PHP entry point

Philosophy

Kipchak has an opinionated view of how API layers should be structured. These definitions follow the natural flow of a request.

  • Routes — Entry points into your API. Defined in routes/, versioned by directory (e.g. routes/v1/). They declare the URL, HTTP verb, and which controller handles the request.

  • Middlewares — Reusable logic applied before a request reaches a controller or before a response is sent. Global middlewares are registered in middlewares/middlewares.php. Route-level middlewares are applied in the route file itself.

  • Controllers — Decide how to process a request. Versioned alongside routes. A controller receives the HTTP request, passes it to a Data Transfer Object for validation, then hands off to a Model.

  • Data Transfer Objects (DTOs) — Represent data flowing in and out of your API. DTOs must be versioned — they form the API contract. Validating input here keeps controllers thin.

  • Models — Business logic. The layer between your controllers and your data stores or third-party services.

  • Entities — Code representations of your data schema. Doctrine entities live in api/Entities/Doctrine/. CouchDB document shapes live in api/Entities/CouchDB/.

  • Dependencies — Common classes registered in the DI container so they are instantiated once per request. Drivers are Kipchak's built-in dependency layer, initialised in drivers/drivers.php.

Drivers

Drivers are adapters for external services. They are initialised in drivers/drivers.php and registered into the DI container. Config, Logger, and HTTP are initialised first as other drivers depend on them.

The starter includes and demonstrates the following drivers:

Core

DriverConfig fileDescription
ConfigLoads all PHP config files from config/. Always initialised first.
Loggerkipchak.api.phpPSR-3 logger (Monolog). Available as $this->logger in all controllers.
HTTPPSR-18 HTTP client for outbound requests. Used internally by several drivers.

Data & Messaging

DriverConfig fileDemo routeDescription
Memcachedkipchak.memcached.phpGET /v1/cacheSymfony Cache-backed Memcached pools
File CacheGET /v1/cacheSymfony Cache file-based cache
CouchDBkipchak.couchdb.phpGET /v1/couchApache CouchDB 3.x document store
Doctrinekipchak.doctrine.phpDoctrine DBAL and ORM for MySQL/MariaDB
RabbitMQkipchak.rabbitmq.phpGET /v1/rabbitmq/publishRabbitMQ publisher and subscriber
GET /v1/rabbitmq/subscribe
S3kipchak.s3.phpGET /v1/s3S3-compatible object storage
Gitkipchak.git.phpGET /v1/gitGit repository operations over HTTPS

AI

DriverConfig fileDemo routeDescription
OpenAIkipchak.openai.phpGET /v1/openaiOpenAI chat completions with default model injection
Anthropickipchak.anthropic.phpGET /v1/anthropicAnthropic Claude messages with default model injection

DNS

DriverConfig fileDemo routeDescription
Cloudflare DNSkipchak.cloudflare-dns.phpGET /v1/cloudflare-dnsManage Cloudflare zones and records
ClouDNSkipchak.cloudns.phpGET /v1/cloudnsManage ClouDNS zones and records

Middlewares

Middlewares are registered in middlewares/middlewares.php and apply globally to every request.

MiddlewareConfig fileDescription
ErrorStandardised JSON error responses for all unhandled exceptions
API Keykipchak.auth.key.phpValidates an API key from a header or query parameter. Disabled by default.
JWKSkipchak.auth.jwks.phpValidates a Bearer JWT against a remote JWKS URI. Disabled by default.
Subashi (WAF)kipchak.subashi.phpRequest firewall with OWASP rules, rate limiting, IP/header allow/blocklists. Enabled by default.

Authentication middlewares are disabled by default ('enabled' => false) so the demo routes are accessible without credentials. Set 'enabled' => true in the relevant config file to activate.

The starter also includes a demo of per-route middleware usage:

RouteMiddleware applied
GET /v1/authKeyAPI Key authentication
GET /v1/authJWKSJWKS authentication

Custom per-project middlewares can be added to api/Middlewares/ and registered in middlewares/middlewares.php or applied directly in a route file.

Configuration

All configuration lives in the config/ directory as PHP files returning arrays. The Config driver loads every file in this directory at boot and makes them available via Config::get('filename-without-extension').

Environment variables are read using the env() helper:

env('ENV_VAR_NAME', 'default-value')
FilePurpose
kipchak.api.phpApp name, debug mode, log level
kipchak.auth.key.phpAPI key authentication settings
kipchak.auth.jwks.phpJWKS URI and scope validation settings
kipchak.anthropic.phpAnthropic API key and default model
kipchak.cloudflare-dns.phpCloudflare API token(s)
kipchak.cloudns.phpClouDNS credentials
kipchak.couchdb.phpCouchDB host, port, credentials, and database
kipchak.doctrine.phpDoctrine DBAL connections and ORM entity manager settings
kipchak.git.phpGit clone directory and named repository definitions
kipchak.memcached.phpMemcached server pools and options
kipchak.openai.phpOpenAI API key, organisation, project, and default model
kipchak.rabbitmq.phpRabbitMQ connection and queue definitions
kipchak.s3.phpS3-compatible endpoint(s), credentials, and region
kipchak.subashi.phpWAF rules: whitelist, blacklist, and rate limit rules

Writing Custom Controllers

Controllers extend Kipchak\Core\Components\Controllers\Base, which provides:

  • $this->container — the DI container
  • $this->logger — the PSR-3 logger
namespace Api\Controllers\v1;

use Kipchak\Core\Components\Controllers;
use Kipchak\Core\Components\Http;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class Example extends Controllers\Base
{
    public function get(ServerRequestInterface $request, ResponseInterface $response, array $args): ResponseInterface
    {
        return Http\Response::json($response, ['hello' => 'world'], 200);
    }
}

Writing Custom Middlewares

Custom middlewares implement __invoke(ServerRequestInterface $request, RequestHandlerInterface $handler) and can be applied globally in middlewares/middlewares.php or to a specific route group.

$app->group('/v1', function (RouteCollectorProxy $group) {
    $group->get('/protected', [Controllers\v1\Example::class, 'get'])
          ->add(new MyCustomMiddleware());
});

Registering Custom Dependencies

Add any class or service to the DI container in drivers/drivers.php:

$container->set('my.service', function (ContainerInterface $c) {
    return new MyService();
});

Retrieve it anywhere you have access to the container:

$service = $this->container->get('my.service');