Introduction
Kipchak CLI
The Kipchak command-line tool creates a project, adds any driver or middleware in one command, generates code in the starter's conventions and validates the OpenAPI document against the routes.
The Kipchak CLI creates a project, adds drivers and middleware to it, writes resources, endpoints and middleware in the starter's conventions, and checks the OpenAPI document against the routes. It writes plain code into files your project owns, so the API never depends on it at run time: remove it and nothing changes.
Installation
Projects created from starter 4.2 or later already have it, as a development dependency:
vendor/bin/kipchak list
In an existing project, add it with Composer:
composer require --dev kipchak/cli
To create projects with it, install it globally:
composer global require kipchak/cli
The CLI needs PHP 8.4 or later and works with projects on kipchak/core 3.
kipchak new
kipchak new my-api
Creates a project from the starter, as composer create-project kipchak/starter my-api does, and prints the next steps. --starter-version chooses a starter version. A project created this way is identical to one created with Composer.
kipchak add
kipchak add doctrine
Adds a Kipchak driver or middleware to the project:
- installs the package with
composer require; - copies its sample configuration into
config/, never over a file that already exists; - initialises it in
drivers/drivers.phpormiddlewares/middlewares.php, in the position its documentation requires; - lists any settings you must supply, such as API keys.
A driver often needs other Kipchak drivers. The Anthropic driver, for example, uses the HTTP driver. add initialises those too, before the package that needs them, and copies their configuration, so the API works on its first request:
$ kipchak add anthropic
Created config/kipchak.http.php
Created config/kipchak.anthropic.php
Modified drivers/drivers.php
kipchak/driver-http: https://kipchak.dev/docs/driver-http
kipchak/driver-anthropic: https://kipchak.dev/docs/driver-anthropic
Set these before using it:
config/kipchak.anthropic.php: ANTHROPIC_API_KEY
A driver that is already initialised is left as it is.
Names
doctrine, driver-doctrine and kipchak/driver-doctrine all name the Doctrine driver. A few names are both a driver and a middleware, such as feature-flags and opentelemetry; give those in full, as driver-feature-flags or middleware-feature-flags. Every package is listed on the ecosystem page.
Enterprise packages install the same way, with your project's own Composer credentials for the Enterprise repository.
Where middleware goes
Middleware is placed between the two Error::initialise($app) lines of middlewares/middlewares.php (see Middleware), in the order each package documents. Metering and Quotas, for example, go before the authentication middleware, so that they run after it and see who the caller is. The firewall goes after it, so that it runs first. If the order you have already written cannot satisfy a package, add changes nothing and tells you the line to add by hand.
Each package declares its configuration file, its initialise() line and its order in its own composer.json, under extra.kipchak, so the same information is available to any tool.
Previewing changes
kipchak add doctrine --dry-run
shows every change as a diff and writes nothing. For a package that is not installed yet, a dry run says so and runs no Composer command: its configuration and position are known only once the package is installed.
Generating code
The make: commands write code in the starter's conventions, into your project's own namespaces: DTOs that carry their OpenAPI schema, thin controllers whose attributes describe each operation, and route files with one group per API version. What they write is ordinary code for you to change; nothing is generated again later. Each accepts --dry-run, and --api-version (v1 by default) chooses the version folder.
make:resource
kipchak make:resource Orders --crud --fields=id:int,reference:string,total:float,placedAt:datetime,note:?string
Writes a resource the way the starter's Sultans is written:
Created api/DataTransferObjects/v1/Order.php
Created api/Models/Orders.php
Created api/Controllers/v1/Orders.php
Created routes/v1/orders.php
Created tests/OrdersTest.php
The controller has list and get, and with --crud also create, update and delete, which read the request body once and validate it by mapping it to the DTO. The model holds two example rows built from the fields, so the endpoints answer, and the tests pass, before any storage exists. Replace them with a driver, such as Doctrine, when you choose where the data lives.
The DTO's name is the singular of the resource (Order for Orders); --dto and --singular choose others. A resource needs id:int among its fields.
Fields
--fields takes name:type pairs, separated by commas:
| Type | PHP | OpenAPI |
|---|---|---|
int | int | integer |
float | float | number |
string | string | string |
bool | bool | boolean |
datetime | string | string, format: date-time, an ISO 8601 example |
Address | Address | a reference to the Address schema |
LineItem[] | array of LineItem | an array of references |
?type makes a field nullable. Each property gets a description and, unless it refers to another DTO, an example, for you to replace with your own.
make:dto and make:controller
kipchak make:dto Address --fields=street:string,city:string,postcode:?string
kipchak make:controller Reports
make:dto writes a DTO alone; make:controller writes a controller with its OpenAPI tag and no operations, ready for make:endpoint.
make:endpoint
kipchak make:endpoint POST '/v1/orders/{id:[0-9]+}/cancel' Orders::cancel
Adds an operation to an existing controller: the method, with its OpenAPI attribute, and its route. The path starts with the API version. The route goes into the version's group in the route file that already routes the controller, or into routes/v1/orders.php, which is created if it does not exist. A parameter constrained to digits, as {id:[0-9]+}, is documented as an integer; any other as a string. --dto=Order refers the body and the response to the Order schema.
The new method answers 501 Not Implemented until you write it, so an unfinished endpoint never returns data that does not match its schema.
make:middleware
kipchak make:middleware RequireRole --global
Writes api/Middlewares/RequireRole.php, a PSR-15 middleware. With --global, it is also added for every request in middlewares/middlewares.php, between the two Error::initialise($app) lines, as kipchak add places a package. Without it, add the middleware to a route or a group yourself.
Changing existing files
make:endpoint and make:middleware --global change files you already have, and only by adding lines: the method above the controller's closing brace, the imports it needs in alphabetical place, the route as the last line of its group. Every other line stays as it was, including its line endings. If a file does not have the shape the CLI expects (a route file with no group for the version, or more than one), it is left alone and the line to add is printed instead.
kipchak routes
kipchak routes
Lists the routes the application registers, as Slim sees them, with the controller method each calls:
GET /v1/orders Api\Controllers\v1\Orders::list
GET /v1/orders/{id:[0-9]+} Api\Controllers\v1\Orders::get
POST /v1/orders/{id:[0-9]+}/cancel Api\Controllers\v1\Orders::cancel
GET /status Api\Controllers\Status::get
GET /openapi.json Api\Controllers\OpenApi::get
kipchak openapi:validate
kipchak openapi:validate
Checks the OpenAPI document your API generates, against the OpenAPI specification and against the routes the application registers:
| Check | Severity | What it checks |
|---|---|---|
OAS-001 | Error | The document is valid against the OpenAPI JSON Schema for its version, 3.0 or 3.1. |
OAS-002 | Error | swagger-php reported no warning while generating it. |
OAS-003 | Error | Every $ref resolves. |
KIP-001 | Error | Every route has an operation, and every operation has a route. |
KIP-002 | Error | Every path parameter of a route is declared on its operation. |
KIP-003 | Error | Every operation has a unique operationId, a summary and a tag. |
KIP-004 | Warning | Request and response bodies refer to component schemas instead of defining objects inline, apart from the response envelope (code, status, data). |
KIP-005 | Warning | Every property of a component schema has a description and an example. |
Each finding names its check and the path, operation or schema concerned:
KIP-002 ERROR GET /v1/orders/{id}: The path parameter id is not declared as a parameter of the operation.
KIP-005 WARNING schema Order, property note: The property has no example.
1 error, 1 warning.
It exits with 1 when there is an error, and --strict makes a warning fail too, so the command can gate a release in CI. --no-routes checks the document without booting the application. The route that serves the document, /openapi.json, is not expected in it; --ignore-route="GET /internal/health" (repeatable) leaves out others.
The CLI generates the document and boots the application in a separate PHP process, with your project's own autoloader, so the check uses exactly the swagger-php, Slim and driver versions your API runs. It calls Api\Utils\OpenApi::generate(), which the starter has, or scans api/ when a project has no such class. Reading the routes boots the application as a request would, so its drivers and their configuration must load.
kipchak project
kipchak project
Shows the project the CLI has found (the nearest directory above the current one whose composer.json requires kipchak/core), its kipchak/core version and its namespaces.
Options and exit codes
Every command accepts --format=json, which writes one JSON document to standard output, and --project-dir, to work on a project other than the current directory's. Commands that write files accept --dry-run. Composer's own output goes to standard error.
| Exit code | Meaning |
|---|---|
| 0 | The command did what was asked. |
| 1 | It found a problem, such as a file that already exists, an unknown package or an error in the OpenAPI document. Nothing was written. |
| 2 | It could not run: no Kipchak project was found, dependencies are not installed, or the core version is not supported. |
The commands that write files return the changes, messages and settings. For kipchak add --format=json:
{
"changes": [
{"path": "config/kipchak.anthropic.php", "action": "create", "content": "...", "diff": "..."}
],
"messages": ["kipchak/driver-anthropic: https://kipchak.dev/docs/driver-anthropic"],
"settings": [{"file": "config/kipchak.anthropic.php", "key": "ANTHROPIC_API_KEY"}],
"written": true
}
Fields are added in later versions but never removed or renamed within a major version.
Source
The CLI is MIT-licensed. Its source is at https://1x.ax/mamluk/kipchak/cli, mirrored to https://github.com/kipchak-dev/cli.