Search by

API Core SDK for declarative API clients

Package info

github.com/apisutra/php

pkg:composer/apisutra/php

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.0 2026-09-19 13:15 UTC

This package is not auto-updated.

Last update: 2026-09-20 11:58:49 UTC


README

ApiSutra logo

ApiSutra

A declarative SDK for building API clients

Tests Test count Docs CI Documentation PHP 8.4+ Packagist

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 RequestFactory creates an SDK request from route/query/body/headers/files; ordinary DI preserves application-assigned values.
  • Controller responses. ClientResponseAdapter converts ClientResponse results 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

All sections and tasks · AI agents: using the package · Capability map.

Developing ApiSutra

Development guide · AI agent instructions · Contributing.

Versions and license

Changelog · MIT license.