apisutra / php
API Core SDK for declarative API clients
Requires
- php: ^8.4
- guzzlehttp/promises: ^2.0
- guzzlehttp/psr7: ^2.0
- psr/http-client: ^1.0
- psr/http-factory: ^1.0
- psr/http-message: ^1.0
- psr/log: ^3.0
- psr/simple-cache: ^3.0
Requires (Dev)
- guzzlehttp/guzzle: ^7.0
- illuminate/container: ^12.0
- illuminate/http: ^12.0
- illuminate/translation: ^12.0
- illuminate/validation: ^12.0
- pestphp/pest: ^3.8
- phpstan/phpstan: ^2.1
- squizlabs/php_codesniffer: ^4.0
Suggests
- ext-redis: Optional atomic shared rate limits (phpredis >=6.2 with Redis >=7.0)
Provides
None
Conflicts
None
Replaces
None
This package is not auto-updated.
Last update: 2026-09-20 11:58:49 UTC
README
ApiSutra
A declarative SDK for building API clients
English · РусскийApiSutra is a PHP package for building external API SDKs. You describe operations and DTOs; the package manages HTTP, authentication, retries, and pagination. Applications receive typed data and consistent error handling.
The core works without Laravel; enable the built-in integration when needed.
What an SDK looks like
Create and configure a client
Create a client, set a shared DTO policy, and execute an operation. Imports are omitted from these overview snippets:
$hydration = new HydrationConfig(policy: new RulePolicy(scalars: ScalarPolicy::Strict)); $client = new DemoClient( new ClientConfig( baseUrl: 'https://api.example.test', timeout: 15, // HTTP request timeout in seconds. hydration: $hydration, localization: 'ru', // ApiSutra messages in Russian; English is the default. debug: true, // Collect request and response snapshots for diagnostics. ), HttpTransport::createDefault(), ); // Execute synchronously; send() returns ResultHandle, withTraceId() sets the log ID. $request = $client->records()->get(7)->withTraceId('record-7'); $handle = $client->send($request); // Extract the DTO already created by #[Returns]; FAILED status throws an exception. /** @var GetRecordResponseDto $record */ $record = $handle->dataOrFail(); // createdAt is already DateTimeImmutable: format the date directly. echo $record->createdAt->format('d.m.Y'); // 15.09.2026 // Other ways to read the same result without sending the request again. $resolved = $handle->resolved(); // ResolvedResultInterface $execution = $handle->raw(); // ExecutionResult $trace = $execution->trace; // ExecutionTrace|null echo $handle->requestDebugJson(); // Method, URL, headers, and body; secrets are masked.
$resolved — ResolvedResultInterface. Data, status, and errors. Add custom request-result methods, such as recordOrFail() and requiresReauthorization().
$execution — ExecutionResult. HTTP response, metadata, child results, audit, and debug.
$trace — ExecutionTrace. traceId correlates logs, executionId identifies a run, and parentExecutionId identifies its parent.
Client settings · Message language · Trace, debug, and logs. Logs use a PSR-3 logger; trace/audit are available without debug.
Request declaration
GetRecordRequest defines the API operation:
#[Get('/records/{id}')] // HTTP method and operation address. #[Retry(attempts: 3)] // Temporary errors: up to 3 attempts, including the first. #[Returns(GetRecordResponseDto::class, unwrap: 'data')] // The data field → DTO. final class GetRecordRequest extends AbstractRequest { public function __construct( #[Path] // Substitute id into {id} in the request address. public int $id, ) { } }
Response declaration (DTO)
GetRecordResponseDto describes the data the application receives:
// Typed record model received by the application. final readonly class GetRecordResponseDto extends AbstractResponseDto { public function __construct( #[From('record_id', fallback: ['id'])] // Use id when record_id is missing. public int $id, public string $title, // Convert the API response's created_at string to a date object. #[From('created_at')] #[DateTimeFrom(format: DATE_ATOM)] public DateTimeImmutable $createdAt, #[From('author.name')] // Read the name from the nested author object. public ?string $authorName = null, #[EmptyStringAsNull(blank: true)] // Convert empty and whitespace-only strings to null. public ?string $description = null, // Preserve unknown response fields; client requests exclude them. #[Extras] public array $_extra = [], ) { } }
_extra is an optional declared property: #[Extras] stores unread fields in it. If you do not need them, remove both the property and the attribute.
DTO capabilities in one example: nested models, collections, enums, casts, defaults, outgoing JSON, and errors.
Capabilities
Design an SDK
| Area | Supported features |
|---|---|
| SDK operations | Organize an API into a convenient client. Requests, resources, service versions, client discovery, multiple-service SDKs |
| SDK catalogs | Describe operations and types for tools. Operation inventory, response DTO catalog, provider catalogs |
Configure and connect a client
| Area | Supported features |
|---|---|
| Client configuration | Client and per-call settings. ClientConfig parameters, authentication, credentials, token refresh, configuration copies, request options, container setup |
| Authentication | Access protected APIs and work with multiple accounts. API key, Bearer, Basic, HMAC, auth scopes, token refresh after 401, credential protection on address changes |
| Message language | Localized errors and logs. EN/RU per client, custom SDK catalogs, standalone and Laravel |
| Transport | Choose the HTTP client and response mode. Transport contract, promise API, response formats, external and signed URLs |
| Integrations | Connect to the application environment. Standalone, Laravel, Redis for shared quotas |
Describe requests and outgoing data
| Area | Supported features |
|---|---|
| Attributes | Declarations alongside code. HTTP, request parameters, DTOs, responses, behavior, hooks |
| Validation | Check input before sending. Request and DTO rules, validator setup, body oneOf and discriminator |
| Serialization | The right data representation for applications and APIs. Separate toArray() and HTTP settings, query, header, path, and body, array and boolean formats, dates and enums, a JSON string in one field, root body for JSON Patch and bulk |
| Files | Stream files and work with archives. Multipart/binary uploads and Base64 in JSON, download to a file or stream, DTO file fields, reading and extracting archives, runnable example |
Describe and transform DTOs
| Area | Supported features |
|---|---|
| DTOs | Typed models for your API. Attributes and readonly classes, ordinary PHP classes without a base DTO, external rules, inheritance and self/parent, typed collections |
| DTO hydration | Turn API responses into convenient models. Field names, nested paths, and fallback, profiles and shared policy, scalars and unions, dates and timezones, large identifiers without precision loss |
| Field contracts | Explicit API data requirements. Strict typing, required presence and forbidden null, empty strings and defaults, checking constructor-assigned values |
| Response structure | Complex data without manually parsing every field. Nested DTOs and strict lists, discriminator variants, recursive models, unknown fields in extras, excluding extras from requests |
| Custom transformations | Adapt unusual provider data. Input-only, output-only, or bidirectional casts, computed defaults, nested hydration and serialization with current rules, HTTP data in handlers, transformations without HTTP |
Control execution
| Area | Supported features |
|---|---|
| Sending policies | Control retries, load, and execution time. Retry and backoff, idempotency, shared quotas and operation limits, attempt timeout and shared deadline, cross-process quotas with Redis |
| Caching | Reuse responses with a controlled lifetime. PSR-16 and TTL, SDK and credential isolation, cache modes and per-call settings, clearing, token caching and refresh locks |
Coordinate multiple calls
| Area | Supported features |
|---|---|
| Pagination | Traverse pages and obtain collection items. Configurable API schemes, typed items, DTO containers with metadata, result iteration, traversal limits |
| Multiple requests | Execute dependent and bulk operations. Batch and pool, failure strategies, result composition and dependencies, a shared deadline for multiple calls |
| Long-running operations | Obtain deferred API results. Readiness criterion, operation modes, await and polling |
Read results and diagnose failures
| Area | Supported features |
|---|---|
| Results and errors | Results tailored to your SDK. Custom request-result classes and methods, ResultHandle, ResolvedResult, ExecutionResult, errors and exceptions, error context |
| Diagnostics | Find failure causes. Logs, call tree, audit log, debug snapshots, data masking, DTO error paths |
Extend and test an SDK
| Area | Supported features |
|---|---|
| Extensions | Add custom behavior. Lifecycle hooks, response handlers, extension modules, custom HTTP transport |
| SDK testing | Test without network access and against the real API. Fakes and mock responses, response sequences, sent-request assertions, fixture recording and playback, live checks |
Laravel
- Installation and DI. ApiSutra and Laravel-compatible SDK providers are loaded automatically; clients and requests are available through the container, including multiple-service SDKs.
- SDK settings. Configure the API address, auth, and timeout; the provider supplies defaults and optional
vendor:publish. - Validation before sending.
#[Validate]uses an available Laravel Validator. - Incoming HTTP requests. Explicit
RequestFactorycreates an SDK request from route/query/body/headers/files; ordinary DI preserves application-assigned values. - Controller responses.
ClientResponseAdapterconvertsClientResponseresults into JSON, text, or streaming file responses with status and headers.
Use an existing SDK · Add Laravel to your SDK · Full integration contract. Verified with Laravel 12, controllers, Artisan, sequential jobs in one process, and config:cache.
Installation and first run
Install the package and run the example SDK without API keys or network requests:
composer require "apisutra/php:^0.1"
php vendor/apisutra/php/docs/example/sdk/run.php
Quickstart explains the example and how to move to your own API.
Documentation
- Create an SDK: from API analysis to a verified operation and coverage.
- Use an existing SDK: application setup and results.
- Reference: settings, contracts, precedence, and limitations.
- Examples: ready-to-run local code.
All sections and tasks · AI agents: using the package · Capability map.
Developing ApiSutra
Development guide · AI agent instructions · Contributing.
