Skip to main content

Overview

Geni infers most of your document automatically. When you need to change the result (add a description, document a rate limit response, map a custom validation rule), register an extension through Geni::configure() or the extensions config key.

Geni::configure()

Register extensions in a service provider’s boot() method:
app/Providers/AppServiceProvider.php
Each with*() method accepts several arguments or a single array. Class names are resolved from the service container.

Per-API Registration

Geni::configure() targets the default API. Registrations for default also apply to every named API in geni.apis. Pass a name to target one API only:
Here v2 gets both changes, while the default document only gets the shared description. For each API, extensions run in this order:
  1. Classes in geni.extensions
  2. Classes in geni.apis.{name}.extensions
  3. Geni::configure() registrations for default
  4. Geni::configure('{name}') registrations

Document Transformers

A document transformer changes the finished OpenAPI document of an API (info, servers, security, components, paths) before it is cached, served or exported.
app/Docs/SetTermsOfService.php
A closure receives the same arguments: fn (OpenApiDocument $document, string $apiName) => ....

Operation Transformers

An operation transformer changes one documented operation, with access to the route it came from.
app/Docs/TagOperationsWithRouteName.php
DiscoveredRoute exposes uri, methods, action, middleware and name. Operation exposes properties such as summary, description, tags, operationId, deprecated, security, responses and extensions (keys emitted as top-level x-* properties of the operation).

Rule Transformers

Map custom validation rules (for example ipv4_cidr, or a Rule object’s string form) to JSON Schema changes:
app/Docs/Ipv4CidrRule.php
A field validated with 'network' => ['required', 'ipv4_cidr'] is then documented as {"type": "string", "format": "ipv4-cidr"}.

Exception Responses

Map your own exceptions (declared with @throws) to HTTP status codes:
app/Docs/PaymentRequiredResponse.php
A controller method with @throws PaymentRequiredException then documents a 402 response.

Registering Extensions in Config

Classes can also be listed in config/geni.php. Each class is registered by the interface(s) it implements (DocumentTransformer, OperationTransformer, RuleTransformer, ExceptionToResponse):
config/geni.php
A class that implements none of the four interfaces throws an InvalidArgumentException (”… must implement DocumentTransformer, OperationTransformer, RuleTransformer or ExceptionToResponse”) when the document is generated.

Servers

geni.servers (or servers inside an entry of geni.apis) sets the OpenAPI servers list as description => URL:
config/geni.php
Relative URLs go through url(), so '/' becomes your app URL (for example http://localhost). Paths in the document stay absolute (for example /api/users), so point servers at the host, not at the API prefix.

Operation IDs

Every operation gets an operationId, chosen in this order:
  1. An explicit id: #[Endpoint(operationId: ...)] or @operationId.
  2. The route name, without a leading api.: api.users.index becomes users.index.
  3. The controller and method: UserController@show becomes user.show. The Controller suffix and the App, Http, Api and Controllers namespace parts are dropped, and the last two remaining parts are used. When that is not unique, the full controller path is used.
  4. As a last resort, the id is made unique with a numeric suffix.
Generated ids are unique across the document. Closure routes without a route name get no operationId. A PATCH documented next to PUT on the same route (the update route of Route::apiResource(), or Route::match(['PUT', 'PATCH'], ...)) gets a _patch suffix:
Generated ids do not rename MCP tools in the default snake naming mode. Set geni.mcp.tool_naming to operation_id to use them as tool names. See Tool Naming.