PHPackages                             silencenjoyer/api-sdk - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. silencenjoyer/api-sdk

ActiveLibrary[API Development](/categories/api)

silencenjoyer/api-sdk
=====================

A lightweight PHP SDK for creating API integrations.

0.1.0(2mo ago)00MITPHPPHP ^7.4.0|^8.0.0CI passing

Since May 1Pushed 2mo agoCompare

[ Source](https://github.com/silencenjoyer/api-sdk)[ Packagist](https://packagist.org/packages/silencenjoyer/api-sdk)[ RSS](/packages/silencenjoyer-api-sdk/feed)WikiDiscussions main Synced 3w ago

READMEChangelogDependencies (11)Versions (4)Used By (0)

🛠️ API SDK
==========

[](#️-api-sdk)

A lightweight PHP framework for building typed HTTP API integrations.

[![Tests](https://github.com/silencenjoyer/api-sdk/actions/workflows/tests.yml/badge.svg)](https://github.com/silencenjoyer/api-sdk/actions/workflows/tests.yml)[![codecov](https://camo.githubusercontent.com/46601769c2420bb1b094b5d2e591ec87b893a62bce3d8862968434163ef6d72a/68747470733a2f2f636f6465636f762e696f2f67682f73696c656e63656e6a6f7965722f6170692d73646b2f6272616e63682f6d61696e2f67726170682f62616467652e737667)](https://codecov.io/gh/silencenjoyer/api-sdk)[![Static Analyze](https://github.com/silencenjoyer/api-sdk/actions/workflows/phpstan.yml/badge.svg)](https://github.com/silencenjoyer/api-sdk/actions/workflows/phpstan.yml)[![Latest Stable Version](https://camo.githubusercontent.com/6e17110c8d4f5cdf7ddf1c32429641820c36cdb72db25e24e7b81efda7671837/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f73696c656e63656e6a6f7965722f6170692d73646b2e737667)](https://packagist.org/packages/silencenjoyer/api-sdk)[![PHP Version Require](https://camo.githubusercontent.com/8ed572e56c95459e9b94f9c4fa77c22edcf80bac7d24fa67f6d1f3c1d066f14b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f73696c656e63656e6a6f7965722f6170692d73646b2e737667)](https://packagist.org/packages/silencenjoyer/api-sdk)[![License](https://camo.githubusercontent.com/169e83b74ab9ad00c2c44044340e99ebfe97b58efee25ae43a2df28b08ab4b35/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f73696c656e63656e6a6f7965722f6170692d73646b)](LICENSE)

Requirements
------------

[](#requirements)

- PHP 7.4 or 8.x
- PSR-18 HTTP client
- PSR-17 HTTP factories (request factory + stream factory)

Installation
------------

[](#installation)

```
composer require silencenjoyer/api-sdk
```

The package includes `php-http/discovery` and will auto-discover PSR-18/PSR-17 implementations. Install any compatible package alongside:

```
# PSR-7 + PSR-17
composer require nyholm/psr7
# PSR-18 client, e.g. one of:
composer require symfony/http-client
composer require guzzlehttp/guzzle
```

Overview
--------

[](#overview)

The SDK is organized around two layers:

- **Layer 1 — end users**: consume a ready-made API client (`NbuApi`, `StripeApi`, etc.)
- **Layer 2 — integration developers**: build those clients by extending `AbstractApi`

---

Layer 1: Using an API client
----------------------------

[](#layer-1-using-an-api-client)

### Zero-config instantiation

[](#zero-config-instantiation)

If `php-http/discovery` is installed alongside compatible PSR-18/PSR-17 packages, the client discovers them automatically:

```
$api = NbuApi::build();
```

Explicit dependencies:

```
$api = NbuApi::build($httpClient, $requestFactory, $streamFactory);
```

### Advanced builder

[](#advanced-builder)

For middleware or parser customization, obtain the builder first:

```
use Silencenjoyer\ApiSdk\Middlewares\LoggerMiddleware;

$api = NbuApi::getBuilder()
    ->withMiddlewares([new LoggerMiddleware($logger)])
    ->build();
```

### Authentication

[](#authentication)

Attach an auth strategy to a built instance. The call is immutable and returns a new instance:

```
use Silencenjoyer\ApiSdk\Authentication\Bearer;

$api = NbuApi::build()->withAuthentication(new Bearer($token));
```

Implement `AuthInterface` to create custom strategies (API key header, HMAC signature, etc.).

### Executing commands

[](#executing-commands)

Two styles are available:

```
// Immediate execution
$response = $api->execute(new GetExchangeRatesCommand(date: '2026-01-01'));

// Dispatchable — bind command to the API, send later
$command = $api->createCommand(GetExchangeRatesCommand::class, ['date' => '2026-01-01']);
// ... pass $command around ...
$response = $command->send();
```

### Working with the response

[](#working-with-the-response)

```
$response->asArray();           // array
$response->asObject();          // stdClass
$response->getHttpResponse(); // PSR-7 ResponseInterface
```

---

Layer 2: Building an API client
-------------------------------

[](#layer-2-building-an-api-client)

### Minimal implementation

[](#minimal-implementation)

```
use Silencenjoyer\ApiSdk\AbstractApi;
use Silencenjoyer\ApiSdk\Commands\CommandInterface;

class NbuApi extends AbstractApi
{
    protected function getUrl(): string
    {
        return 'https://bank.gov.ua';
    }

    protected function supports(CommandInterface $command): bool
    {
        return $command instanceof NbuCommandInterface;
    }
}
```

### Providing default builder configuration

[](#providing-default-builder-configuration)

Override `getBuilder()` to apply defaults that are always needed for this API. The signature must match the parent:

```
class NbuApi extends AbstractApi
{
    public static function getBuilder(
        ?ClientInterface $client = null,
        ?RequestFactoryInterface $requestFactory = null,
        ?StreamFactoryInterface $streamFactory = null
    ): ApiBuilderInterface {
        return parent::getBuilder($client, $requestFactory, $streamFactory)
            ->withFormats(Format::JSON)
            ->withMiddlewares([new NbuRetryMiddleware()]);
    }
}
```

`AbstractApi::build()` calls `static::getBuilder()`, so defaults are applied automatically for both `NbuApi::build()` and `NbuApi::getBuilder()`.

### Custom constructor parameters

[](#custom-constructor-parameters)

If your API requires extra constructor arguments (e.g., an environment-specific base URL), add a named factory method that uses `withFactory()`:

```
class NbuApi extends AbstractApi
{
    private string $baseUrl;

    public function __construct(
        string $baseUrl,
        RequestBuilderInterface $requestBuilder,
        ResponseParserInterface $responseParser,
        HandlerInterface $handler,
        MiddlewareStack $middlewareStack
    ) {
        parent::__construct($requestBuilder, $responseParser, $handler, $middlewareStack);
        $this->baseUrl = $baseUrl;
    }

    protected function getUrl(): string
    {
        return $this->baseUrl;
    }

    public static function forUrl(string $baseUrl): ApiBuilderInterface
    {
        return static::getBuilder()
            ->withFactory(fn($rb, $rp, $h, $ms) => new self($baseUrl, $rb, $rp, $h, $ms));
    }
}

// Usage:
$api = NbuApi::forUrl($_ENV['NBU_API_URL'])->build();
$api = NbuApi::forUrl($_ENV['NBU_API_URL'])->withMiddlewares([$logger])->build();
```

### Implementing commands

[](#implementing-commands)

Extend `AbstractCommand` and declare the HTTP semantics:

```
use Silencenjoyer\ApiSdk\Commands\AbstractCommand;
use Silencenjoyer\ApiSdk\Constants\HttpMethod;

class GetExchangeRatesCommand extends AbstractCommand implements NbuCommandInterface
{
    public function __construct(private string $date) {}

    protected function isPublic(): bool
    {
        return true;
    }

    protected function getMethod(): string
    {
        return HttpMethod::GET;
    }

    protected function getPath(): string
    {
        return '/NBUStatService/v1/statdirectory/exchange';
    }

    protected function getQueryParams(): array
    {
        return ['json' => '', 'date' => $this->date];
    }
}
```

Override `getBodyParams()`, `getHeaders()`, `getRequestContentType()`, or `getAnswerContentType()` as needed.

For private commands, `isPublic()` must return `false`. The authentication strategy attached via `withAuthentication()` will sign the request automatically.

### Per-command middleware

[](#per-command-middleware)

Attach middleware to a specific command class only:

```
$api = NbuApi::getBuilder()
    ->withCommandMiddleware(GetExchangeRatesCommand::class, new RateLimiterMiddleware())
    ->build();
```

### Custom middleware

[](#custom-middleware)

Implement `MiddlewareInterface`:

```
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Silencenjoyer\ApiSdk\Handlers\HandlerInterface;
use Silencenjoyer\ApiSdk\Middlewares\MiddlewareInterface;

class RetryMiddleware implements MiddlewareInterface
{
    public function handle(RequestInterface $request, HandlerInterface $handler): ResponseInterface
    {
        $response = $handler->handle($request);

        if ($response->getStatusCode() === 503) {
            $response = $handler->handle($request);
        }

        return $response;
    }
}
```

### Custom parsers and serializers

[](#custom-parsers-and-serializers)

Register additional format support on the builder:

```
use Silencenjoyer\ApiSdk\Constants\Format;

NbuApi::getBuilder()
    ->withAddedParser(Format::JSON, new MyJsonParser())
    ->withAddedSerializer('xml', new XmlSerializer())
    ->withFormats(Format::JSON, 'xml')
    ->build();
```

### Serializer resolution

[](#serializer-resolution)

When a command has body params, the SDK selects a serializer using this priority chain:

1. `getRequestContentType()` — explicit override on the command.
2. The `Content-Type` header already present on the request — set it via `getHeaders()` to let the SDK pick the serializer automatically.
3. If neither provides a recognized content type, `UnableToResolveSerializerException` is thrown.

```
// Option 1 — override on the command
protected function getRequestContentType(): ?ContentTypeDto
{
    return new ContentTypeDto(Format::JSON);
}

// Option 2 — set the header, the SDK reads it
protected function getHeaders(): array
{
    return ['Content-Type' => 'application/json'];
}
```

The recognized content types are controlled by `withFormats()` on the builder.

### Parser resolution

[](#parser-resolution)

After a response is received, the SDK selects a parser using this priority chain:

1. `getAnswerContentType()` — explicit override on the command; bypasses all automatic detection.
2. The `Content-Type` header on the response — matched against the content types registered via `withFormats()`.
3. Assumes — when the header is absent or unrecognized, the body is inspected by registered assume strategies. `JsonAssume` is active by default.
4. If none of the above resolves, `UnableToResolveParserException` is thrown.

```
// Force a specific parser regardless of the response header
protected function getAnswerContentType(): ?ContentTypeDto
{
    return new ContentTypeDto(Format::JSON);
}
```

### Content-type inference

[](#content-type-inference)

When a response carries no `Content-Type` header, the SDK uses registered "assumes" to infer the format from the body. JSON is assumed by default. Register additional strategies:

```
NbuApi::getBuilder()
    ->withParserContentTypeAssume(new XmlAssume())
    ->build();
```

---

Built-in components
-------------------

[](#built-in-components)

ComponentDescription`LoggerMiddleware`Logs request and response bodies via PSR-3`RepeatableMiddleware`Retries requests on 5xx by default; configurable condition and retry count`RateLimiterMiddleware`Throttles outgoing requests via `silencenjoyer/rate-limiter`; blocks until the rate window allows`ThrowOnErrorStatusMiddleware`Throws `ClientHttpException` on 4xx and `ServerHttpException` on 5xx; opt-in`Bearer`Adds `Authorization: Bearer ` header`JsonParser`Parses JSON responses`JsonSerializer`Serializes request bodies as JSON`UrlEncodedSerializer`Serializes request bodies as `application/x-www-form-urlencoded`License
-------

[](#license)

MIT

###  Health Score

31

—

LowBetter than 65% of packages

Maintenance85

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity31

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~3 days

Total

3

Last Release

79d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/92015969?v=4)[Andrii Gebrych](/maintainers/Silencenjoyer)[@silencenjoyer](https://github.com/silencenjoyer)

---

Top Contributors

[![silencenjoyer](https://avatars.githubusercontent.com/u/92015969?v=4)](https://github.com/silencenjoyer "silencenjoyer (11 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/silencenjoyer-api-sdk/health.svg)

```
[![Health](https://phpackages.com/badges/silencenjoyer-api-sdk/health.svg)](https://phpackages.com/packages/silencenjoyer-api-sdk)
```

###  Alternatives

[flow-php/flow

PHP ETL - Extract Transform Load - Data processing framework

85036.3k](/packages/flow-php-flow)[tempest/framework

The PHP framework that gets out of your way.

2.2k34.4k16](/packages/tempest-framework)[telnyx/telnyx-php

Official Telnyx PHP SDK — APIs for Voice, SMS, MMS, WhatsApp, Fax, SIP Trunking, Wireless IoT, Call Control, and more. Build global communications on Telnyx's private carrier-grade network.

36789.4k2](/packages/telnyx-telnyx-php)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k5.9M754](/packages/sylius-sylius)[getbrevo/brevo-php

Official Brevo provided RESTFul API V3 php library

1003.9M50](/packages/getbrevo-brevo-php)[typo3/cms

TYPO3 CMS is a free open source Content Management Framework initially created by Kasper Skaarhoj and licensed under GNU/GPL.

1.2k1.9M122](/packages/typo3-cms)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
