PHPackages                             tomaj/nette-api - 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. tomaj/nette-api

ActiveLibrary[API Development](/categories/api)

tomaj/nette-api
===============

Nette api

3.4.0(1mo ago)36261.8k—0.3%22[3 issues](https://github.com/tomaj/nette-api/issues)[1 PRs](https://github.com/tomaj/nette-api/pulls)4MITPHPPHP &gt;= 8.3CI passing

Since Sep 9Pushed 1mo ago5 watchersCompare

[ Source](https://github.com/tomaj/nette-api)[ Packagist](https://packagist.org/packages/tomaj/nette-api)[ RSS](/packages/tomaj-nette-api/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (24)Versions (56)Used By (4)

Nette-Api
=========

[](#nette-api)

**Nette simple api library**

[![Build Status](https://camo.githubusercontent.com/7262c4cb750927a955d3bce09ea18f584b6b3b61e85a5a2e905cab07c1fb86ca/68747470733a2f2f7472617669732d63692e6f72672f746f6d616a2f6e657474652d6170692e737667)](https://travis-ci.org/tomaj/nette-api)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/87b315b465193e1a629227ecc8633cb0f6aa2b44a5bc7bc7ff74c7788e425cdb/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f746f6d616a2f6e657474652d6170692f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/tomaj/nette-api/?branch=master)[![Code Coverage](https://camo.githubusercontent.com/f3545ff25ecbea422064b6219feb94e26158235fe3230963a2543e800dd8699c/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f746f6d616a2f6e657474652d6170692f6261646765732f636f7665726167652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/tomaj/nette-api/?branch=master)[![Latest Stable Version](https://camo.githubusercontent.com/7d43bdb0e969a9c80005e0644ef47d3422ab84b5796d1e3e46074aa72f7353ad/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f746f6d616a2f6e657474652d6170692e737667)](https://packagist.org/packages/tomaj/nette-api)

[![SensioLabsInsight](https://camo.githubusercontent.com/36d7c622c888e9366e66ee57a6c3261f8484a8543e1da76d280cb03971bcfd1b/68747470733a2f2f696e73696768742e73656e73696f6c6162732e636f6d2f70726f6a656374732f62306134336462612d656238312d343264652d623034332d3935656635316238633039372f6269672e706e67)](https://insight.sensiolabs.com/projects/b0a43dba-eb81-42de-b043-95ef51b8c097)

Why Nette-Api
-------------

[](#why-nette-api)

This library provides out-of-the box API solution for Nette framework. You can register API endpoints and connect it to specified handlers. You need only implement your custom business logic. Library provides authorization, validation, rate limit and formatting services for you API.

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

[](#installation)

This library requires PHP 7.1 or later.

Recommended installation method is via Composer:

```
composer require tomaj/nette-api
```

Library is compliant with [PSR-1](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md), [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md), [PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md) and [PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md).

How Nette-API works
-------------------

[](#how-nette-api-works)

First, you have to register library presenter for routing. In *config.neon* just add this line:

```
application:
  mapping:
    Api: Tomaj\NetteApi\Presenters\*Presenter
```

Register your preferred output configurator in *config.neon* services:

```
services:
    apiOutputConfigurator: Tomaj\NetteApi\Output\Configurator\DebuggerConfigurator
```

Register your preferred error handler in *config.neon* services:

```
services:
    apiErrorHandler: Tomaj\NetteApi\Error\DefaultErrorHandler
```

And add route to you RouterFactory:

```
$router[] = new Route('/api/v/[/][/]', 'Api:Api:default');
```

If you want to use RESTful urls you will need another route:

```
$router[] = new Route('api/v//', [
    'presenter' => 'Api:Api',
    'action' => 'default',
    'id' => [
        Route::FILTER_IN => function ($id) {
            $_GET['id'] = $id;
            return $id;
        }
    ],
]);
```

After that you need only register your API handlers to *apiDecider* [ApiDecider](src/ApiDecider.php), register [ApiLink](src/Link/ApiLink.php) and [Tomaj\\NetteApi\\Misc\\IpDetector](src/Misc/IpDetector.php). This can be done also with *config.neon*:

```
services:
    - Tomaj\NetteApi\Link\ApiLink
    - Tomaj\NetteApi\Misc\IpDetector
    apiDecider:
        factory: Tomaj\NetteApi\ApiDecider
        setup:
            - addApi(\Tomaj\NetteApi\EndpointIdentifier('GET', 1, 'users'), \App\MyApi\v1\Handlers\UsersListingHandler(), \Tomaj\NetteApi\Authorization\NoAuthorization())
            - addApi(\Tomaj\NetteApi\EndpointIdentifier('POST', 1, 'users', 'send-email'), \App\MyApi\v1\Handlers\SendEmailHandler(), \Tomaj\NetteApi\Authorization\BearerTokenAuthorization())
```

or lazy (preferred because of performance)

```
services:
    - App\MyApi\v1\Handlers\SendEmailLazyHandler()
    sendEmailLazyNamed: App\MyApi\v1\Handlers\SendEmailLazyNamedHandler()

    factory: Tomaj\NetteApi\ApiDecider
    setup:
      - addApi(\Tomaj\NetteApi\EndpointIdentifier('POST', 1, 'users', 'send-email-lazy'), 'App\MyApi\v1\Handlers\SendEmailHandler', \Tomaj\NetteApi\Authorization\BearerTokenAuthorization())
      - addApi(\Tomaj\NetteApi\EndpointIdentifier('POST', 1, 'users', 'send-email-lazy-named'), '@sendEmailLazyNamed', \Tomaj\NetteApi\Authorization\BearerTokenAuthorization())
```

As you can see in example, you can register as many endpoints as you want with different configurations. Nette-Api supports API versioning from the beginning. This example will prepare these API calls:

1. `http://yourapp/api/v1/users` - available via GET
2. `http://yourapp/api/v1/users/send-email` - available via POST

Core of the Nette-Api are handlers. For this example you need to implement two classes:

1. App\\MyApi\\v1\\Handlers\\UsersListingHandler
2. App\\MyApi\\v1\\Handlers\\SendEmailHandler

These handlers implement interface *[ApiHandlerInterface](src/Handlers/ApiHandlerInterface.php)* but for easier usage you can extend your handlers from [BaseHandler](src/Handlers/BaseHandler.php). When someone reach your API, these handlers will be triggered and *handle()* method will be called.

```
namespace App\MyApi\v1\Handlers;

use Tomaj\NetteApi\Handlers\BaseHandler;
use Tomaj\NetteApi\Response\JsonApiResponse;
use Tomaj\NetteApi\Response\ResponseInterface;

class UsersListingHandler extends Basehandler
{
    private $userRepository;

    public function __construct(UsersRepository $userRepository)
    {
        parent::__construct();
        $this->userRepository = $userRepository;
    }

    public function handle(array $params): ResponseInterface
    {
        $users = [];
        foreach ($this->userRepository->all() as $user) {
            $users[] = $user->toArray();
        }
        return new JsonApiResponse(200, ['status' => 'ok', 'users' => $users]);
    }
}
```

This simple handler is using *UsersRepository* that was created by Nette Container (so you have to register your *App\\MyApi\\v1\\Handlers\\UsersListingHandler* in config.neon).

Advanced use (with Fractal)
---------------------------

[](#advanced-use-with-fractal)

Nette-Api provides integration with [Fractal](http://fractal.thephpleague.com/) library for formatting API responses. If you want to use it, you have to extend your handler from *[BaseHandler](src/Handlers/BaseHandler.php)* and your Fractal instance will be accessible by `$this->getFractal()`.

Main advantage of Fractal is separation of your API "view" (like transformation data to json object or xml or anything...). Also you can include transformations in other transformations to include other objects to others.

Example with fractal:

1. You will need Transformer

```
namespace App\MyApi\v1\Transformers;

use League\Fractal\TransformerAbstract;

class UserTransformer extends TransformerAbstract
{
    public function transform($user)
    {
        return [
            'id' => $user->id,
            'email' => $user->email,
            'name' => $user->name,
        ];
    }
}
```

2. And this will be your handler:

```
namespace App\MyApi\v1\Handlers;

use Tomaj\NetteApi\Handlers\BaseHandler;
use Tomaj\NetteApi\Response\JsonApiResponse;
use Tomaj\NetteApi\Response\ResponseInterface;

class UsersListingHandler extends Basehandler
{
    private $userTransformer;

    public function __construct(UserTransformer $userTransformer)
    {
        parent::__construct();
        $this->userTransformer = $userTransformer;
    }

    public function handle(array $params): ResponseInterface
    {
        $users = $this->useRepository->all();

        $resource = new Collection($users, $this->userTransformer);
        $result = $this->getFractal()->createData($resource)->toArray();

        return new JsonApiResponse(200, $result);
    }
}
```

We recommend to take a look at [Fractal](http://fractal.thephpleague.com/) library. There are much more information about transformers, serializers, paginations etc. It is really nice library.

ApiLink in latte
----------------

[](#apilink-in-latte)

First, you have to register filter in *config.neon*:

```
services:
    apiLink: Tomaj\NetteApi\Link\ApiLink()
    latte.latteFactory:
        setup:
            - addFilter(apiLink, [@apiLink, link])
```

**Note**: Name of filter has to be `apiLink`, because it is used in macro / extension.

For latte &lt; 3.0 register latte macro:

```
latte:
    macros:
        - Tomaj\NetteApi\Link\ApiLinkMacro
```

For latte &gt;= 3.0 register latte extension:

```
latte:
    extensions:
        - Tomaj\NetteApi\Link\ApiLinkExtension
```

Usage in latte files:

```
{apiLink $method, $version, $package, $apiAction, ['title' => 'My title', 'data-foo' => 'bar']}

```

Endpoint inputs
---------------

[](#endpoint-inputs)

Each handler can describe which input is required. It could be GET or POST parameters, also COOKIES, raw post, JSON or file uploads. You have to implement method `params()` where you have to return array with params. These params are used in API console to generate form.

Example with user detail:

```
namespace App\MyApi\v1\Handlers;

use Tomaj\NetteApi\Handlers\BaseHandler;
use Tomaj\NetteApi\Params\GetInputParam;
use Tomaj\NetteApi\Response\JsonApiResponse;
use Tomaj\NetteApi\Response\ResponseInterface;

class UsersDetailHandler extends Basehandler
{
    private $userRepository;

    public function __construct(UsersRepository $userRepository)
    {
        parent::__construct();
        $this->userRepository = $userRepository;
    }

    public function params(): array
    {
        return [
            (new GetInputParam('id'))->setRequired(),
        ];
    }

    public function handle(array $params): ResponseInterface
    {
        $user = $this->userRepository->find($params['id']);
        if (!$user) {
            return new JsonApiResponse(404, ['status' => 'error', 'message' => 'User not found']);
        }
        return new JsonApiResponse(200, ['status' => 'ok', 'user' => [
            'id' => $user->id,
            'email' => $user->email,
            'name' => $user->name,
        ]);
    }
}
```

Input Types
-----------

[](#input-types)

Nette-Api provides various InputParam types. You can send params with GET, POST, COOKIES, FILES, RAW POST data or JSON. All input types are available via test console.

This is table with supported input types:

Input typeExampleGET`new GetInputParam('key')`POST`new PostInputParam('key')`COOKIE`new CookieInputParam('key')`FILE`new FileInputParam('key')`RAW POST`new RawInputParam('key')`JSON`new JsonInputParam('key', '{"type": "object"}')`Outputs
-------

[](#outputs)

By implementing method outputs for your handlers you can specify list of possible outputs (e.g. output schemas) and those will be validated before response is sent to user. If no outputs are set, response is sent to user without validating.

Usage example:

```
public function outputs(): array
{
    $schema = [
        'type' => 'object',
        'properties' => [
            'name' => [
                'type' => 'string',
            ],
            'surname' => [
                'type' => 'string',
            ],
            'sex' => [
                'type' => 'string',
                'enum' => ['M', 'F'],
            ],
        ],
        'required' => ['name', 'surname'],
        'additionalProperties' => false,
    ];
    return [
        new JsonOutput(200, json_encode($schema)),
    ];
}
```

For more examples see [JSON schema web page](http://json-schema.org). Keep in mind that nette api uses [justinrainbow/json-schema](https://github.com/justinrainbow/json-schema/tree/master/dist/schema) for validating schemas and this package supports only json schema draft 03 and 04.

Security
--------

[](#security)

Protecting your API is easy with Nette-Api. You have to implement your [Authorization](src/Authorization/ApiAuthorizationInterface.php) (Tomaj\\NetteApi\\Authorization\\ApiAuthorizationInterface) or use prepared implementations and add it as third argument to *addApi()* method in *config.neon*.

### Basic authentication

[](#basic-authentication)

Basic authentication is a simple authentication scheme built into the HTTP protocol. It contains username and password. You can define as many pairs of usernames and passwords as you want. But just one password for each username.

```
services:
    apiDecider:
        factory: Tomaj\NetteApi\ApiDecider
        setup:
            - addApi(\Tomaj\NetteApi\EndpointIdentifier('GET', 1, 'users'), \App\MyApi\v1\Handlers\UsersListingHandler(), \Tomaj\NetteApi\Authorization\BasicBasicAuthentication(['first-user': 'first-password', 'second-user': 'second-password']))
```

### Bearer token authentication

[](#bearer-token-authentication)

For simple use of Bearer token authorization with few tokens, you can use [StaticTokenRepository](src/Misc/StaticTokenRepository.php) (Tomaj\\NetteApi\\Misc\\StaticTokenRepository).

```
services:
    staticTokenRepository: Tomaj\NetteApi\Misc\StaticTokenRepository(['dasfoihwet90hidsg': '*', 'asfoihweiohgwegi': '127.0.0.1'])

    apiDecider:
        factory: Tomaj\NetteApi\ApiDecider
        setup:
            - addApi(\Tomaj\NetteApi\EndpointIdentifier('GET', 1, 'users'), \App\MyApi\v1\Handlers\UsersListingHandler(), \Tomaj\NetteApi\Authorization\BearerTokenAuthorization(@staticTokenRepository))
```

With this registration you will have api `/api/v1/users` that will be accessible from anywhere with Authorisation HTTP header `Bearer dasfoihwet90hidsg` or from *127.0.0.1* with `Bearer asfoihweiohgwegi`. In Nette-Api if you would like to specify IP restrictions for tokens you can use this patterns:

IP PatternAccess`*`accessible from anywhere`127.0.0.1`accessible from single IP`127.0.0.1,127.0.02`accessible from multiple IP, separator could be new line or space`127.0.0.1/32`accessible from ip range*null*token is disabled, cannot accessBut it is very easy to implement your own Authorisation for API.

### API keys

[](#api-keys)

You can also use API keys for authorization. An API key is a token that a client provides when making API calls. The key can be sent in the query string, header or cookie. See examples below:

```
services:
    staticTokenRepository: Tomaj\NetteApi\Misc\StaticTokenRepository(['dasfoihwet90hidsg': '*', 'asfoihweiohgwegi': '127.0.0.1'])

    apiDecider:
        factory: Tomaj\NetteApi\ApiDecider
        setup:
            - addApi(\Tomaj\NetteApi\EndpointIdentifier('GET', 1, 'users', 'query'), Tomaj\NetteApi\Authorization\QueryApiKeyAuthentication('api_key', @staticTokenRepository))
            - addApi(\Tomaj\NetteApi\EndpointIdentifier('GET', 1, 'users', 'header'), Tomaj\NetteApi\Authorization\HeaderApiKeyAuthentication('X-API-KEY', @staticTokenRepository))
            - addApi(\Tomaj\NetteApi\EndpointIdentifier('GET', 1, 'users', 'cookie'), Tomaj\NetteApi\Authorization\CookieApiKeyAuthentication('api_key', @staticTokenRepository))
```

Rate limit
----------

[](#rate-limit)

This library provides simple interface for API rate limit. All you need to do is implement this interface like in example below:

```
use Nette\Application\Responses\TextResponse;
use Tomaj\NetteApi\RateLimit\RateLimitInterface;
use Tomaj\NetteApi\RateLimit\RateLimitResponse;

class MyRateLimit implements RateLimitInterface
{
    public function check(): ?RateLimitResponse
    {
        // do some logic here

        // example outputs:

        return null;    // no rate limit

        return new RateLimitResponse(60, 50);   // remains 50 of 60 hits

        return new RateLimitResponse(60, 0, 120);   // remains 0 of 60 hits, retry after 120 seconds

        return new RateLimitResponse(60, 0, 120, new TextResponse('My custom error message'));  // remains 0 of 60 hits, retry after 120 seconds, with custom TextResponse (default is Json response, see ApiPresenter::checkRateLimit())
    }
}
```

Then you have to register API to ApiDecider with Rate Limit

```
services:
    apiDecider:
        factory: Tomaj\NetteApi\ApiDecider
        setup:
            - addApi(\Tomaj\NetteApi\EndpointIdentifier('GET', 1, 'users'), \App\MyApi\v1\Handlers\UsersListingHandler(), \Tomaj\NetteApi\Authorization\BearerTokenAuthorization(@staticTokenRepository), MyRateLimit())
```

Javascript ajax calls (CORS - preflight OPTIONS calls)
------------------------------------------------------

[](#javascript-ajax-calls-cors---preflight-options-calls)

If you need to call API via javascript ajax from other domains, you will need to prepare API for [preflight calls with OPTIONS method](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS). Nette-api is ready for this situation and you can choose if you want to enable pre-flight calls globally or you can register prepared prefligt handlers.

Globally enabled - every api endpoint will be available for preflight OPTIONS call:

```
services:
    apiDecider:
        factory: Tomaj\NetteApi\ApiDecider
        setup:
            - enableGlobalPreflight()
            - addApi(\Tomaj\NetteApi\EndpointIdentifier('GET', 1, 'users'), \App\MyApi\v1\Handlers\UsersListingHandler(), Tomaj\NetteApi\Authorization\NoAuthorization())
```

Or you can register custom OPTIONS endpoints:

```
services:
    apiDecider:
        factory: Tomaj\NetteApi\ApiDecider
        setup:
            - addApi(\Tomaj\NetteApi\EndpointIdentifier('OPTIONS', 1, 'users'), \Tomaj\NetteApi\Handlers\CorsPreflightHandler(), Tomaj\NetteApi\Authorization\NoAuthorization())
            - addApi(\Tomaj\NetteApi\EndpointIdentifier('GET', 1, 'users'), \App\MyApi\v1\Handlers\UsersListingHandler(), Tomaj\NetteApi\Authorization\NoAuthorization())

```

Logging
-------

[](#logging)

It is good practice to log you api access if you provide valuable information with your API. To enable logging you need to implement class with interface [ApiLoggerInterface](src/Logger/ApiLoggerInterface.php) (Tomaj\\NetteApi\\Logger\\ApiLoggerInterface) and register it as service in *config.neon*. It will be automatically wired and called after execution of all API requests.

CORS Security
-------------

[](#cors-security)

If you need to iteract with your API with Javascript you will need to send correct CORS headers. [ApiPresenter](src/Presenters/ApiPresenter.php) has property to set this headers. By default api will send header **'Access-Control-Allow-Origin'** with value *'*'\*. If you need to change it you can set property $corsHeader to values:

1. *'auto'* - send back header Access-Control-Allow-Origin with domain that made request. It is not secure, but you can acces this api from other domains via AJAX
2. *'*'\* - send header with '\*' - this will work fine if you dont need to send cookies via ajax calls to api with jquery *$.ajax with xhrFields: { withCredentials: true }* settings
3. *'off'* - will not send any CORS header
4. other - any other value will be send in *Access-Control-Allow-Origin* header

You can set this property in config.neon if you register [ApiPresenter](src/Presenters/ApiPresenter.php):

```
services:
  -
    factory: Tomaj\NetteApi\Presenters\ApiPresenter
    setup:
      - setCorsHeader('auto')
```

or if you extend [ApiPresenter](src/Presenters/ApiPresenter.php), than you can set it on your own presenter.

WEB console - API tester
========================

[](#web-console---api-tester)

Nette-Api contains 2 UI controls that can be used to validate you api. It will generate listing with all API calls and also auto generate form with all api params.

All components generate bootstrap html and can be styled with bootstrap css:

You have to create components in your controller:

```
use Nette\Application\UI\Presenter;
use Tomaj\NetteApi\ApiDecider;
use Tomaj\NetteApi\Component\ApiConsoleControl;
use Tomaj\NetteApi\Component\ApiListingControl;
use Tomaj\NetteApi\Link\ApiLink;

class MyPresenter extends Presenter
{
    private $apiDecider;

    private $apiLink;

    private $method;

    private $version;

    private $package;

    private $apiAction;

    public function __construct(ApiDecider $apiDecider, ApiLink $apiLink = null)
    {
        parent::__construct();
        $this->apiDecider = $apiDecider;
        $this->apiLink = $apiLink;
    }

    public function renderShow(string $method, int $version, string $package, ?string $apiAction = null): void
    {
        $this->method = $method;
        $this->version = $version;
        $this->package = $package;
        $this->apiAction = $apiAction;
    }

    protected function createComponentApiListing(): ApiListingControl
    {
        $apiListing = new ApiListingControl($this->apiDecider);
        $apiListing->onClick[] = function ($method, $version, $package, $apiAction) {
            $this->redirect('show', $method, $version, $package, $apiAction);
        };
        return $apiListing;
    }

    protected function createComponentApiConsole()
    {
        $api = $this->apiDecider->getApi($this->method, $this->version, $this->package, $this->apiAction);
        $apiConsole = new ApiConsoleControl(
            $this->getHttpRequest(),
            $api->getEndpoint(),
            $api->getHandler(),
            $api->getAuthorization(),
            $this->apiLink
        );
        return $apiConsole;
    }
}
```

You can override the generated form by passing your own implementation of `Tomaj\NetteApi\Component\ApiConsoleFormFactoryInterface` as the last constructor parameter of `ApiConsoleControl`. When omitted, a default factory is used so existing code keeps working.

The default factory can be subclassed to keep the same fields while tweaking the underlying `Form` instance. Overridable methods include `createForm()`, `getUrl()`, and `addAuthorization()`, making it easy to use a different base form class or translator without reimplementing the whole factory.

Troubleshooting
---------------

[](#troubleshooting)

If your apache server is runing on CGI or fastCGI script, *$\_SERVER\['HTTP\_AUTHORIZATION'\]* is empty. You'll need to do some mod\_rewrite wizardry to get your headers past the CGI barrier, like so:

```
RewriteEngine on
RewriteRule .? - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]`

```

Change log
----------

[](#change-log)

Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently.

Testing
-------

[](#testing)

```
$ composer test
```

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) and [CONDUCT](CONDUCT.md) for details.

Security
--------

[](#security-1)

If you discover any security related issues, please email  instead of using the issue tracker.

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information

###  Health Score

68

—

FairBetter than 100% of packages

Maintenance86

Actively maintained with recent releases

Popularity47

Moderate usage in the ecosystem

Community30

Small or concentrated contributor base

Maturity92

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 57.6% 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 ~78 days

Recently: every ~29 days

Total

50

Last Release

59d ago

Major Versions

1.16.0 → 2.0.12020-03-24

1.17.0 → 2.2.02020-08-27

1.18.0 → 2.5.02021-09-17

2.12.0 → 3.0.02025-03-04

2.13.0 → 3.2.02026-01-04

PHP version history (4 changes)0.0.1PHP &gt;= 5.4.0

1.6.1PHP &gt;= 5.6.0

2.0.0PHP &gt;= 7.1.0

3.3.0PHP &gt;= 8.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/875f8397233f01d81479a45bf6a64ca995f04d8ee9e72118f2ffcf129c502f12?d=identicon)[tomaj](/maintainers/tomaj)

---

Top Contributors

[![tomaj](https://avatars.githubusercontent.com/u/446736?v=4)](https://github.com/tomaj "tomaj (227 commits)")[![lulco](https://avatars.githubusercontent.com/u/9377319?v=4)](https://github.com/lulco "lulco (122 commits)")[![raky2702](https://avatars.githubusercontent.com/u/127527898?v=4)](https://github.com/raky2702 "raky2702 (11 commits)")[![KavajNaruj](https://avatars.githubusercontent.com/u/22551250?v=4)](https://github.com/KavajNaruj "KavajNaruj (10 commits)")[![romanmatyus](https://avatars.githubusercontent.com/u/1110294?v=4)](https://github.com/romanmatyus "romanmatyus (6 commits)")[![Martin-Beranek](https://avatars.githubusercontent.com/u/89643709?v=4)](https://github.com/Martin-Beranek "Martin-Beranek (4 commits)")[![martinjinda](https://avatars.githubusercontent.com/u/9948632?v=4)](https://github.com/martinjinda "martinjinda (3 commits)")[![jzernovic](https://avatars.githubusercontent.com/u/7045023?v=4)](https://github.com/jzernovic "jzernovic (2 commits)")[![riki137](https://avatars.githubusercontent.com/u/1223388?v=4)](https://github.com/riki137 "riki137 (2 commits)")[![rootpd](https://avatars.githubusercontent.com/u/812909?v=4)](https://github.com/rootpd "rootpd (2 commits)")[![ricco24](https://avatars.githubusercontent.com/u/1409647?v=4)](https://github.com/ricco24 "ricco24 (1 commits)")[![marcelvrana](https://avatars.githubusercontent.com/u/47558347?v=4)](https://github.com/marcelvrana "marcelvrana (1 commits)")[![mgemmel](https://avatars.githubusercontent.com/u/26734633?v=4)](https://github.com/mgemmel "mgemmel (1 commits)")[![pety888](https://avatars.githubusercontent.com/u/52415720?v=4)](https://github.com/pety888 "pety888 (1 commits)")[![mikoczy](https://avatars.githubusercontent.com/u/14105084?v=4)](https://github.com/mikoczy "mikoczy (1 commits)")

---

Tags

apinette

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/tomaj-nette-api/health.svg)

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

###  Alternatives

[apigen/apigen

PHP source code API generator.

2.2k627.9k225](/packages/apigen-apigen)[yajra/laravel-datatables-fractal

Laravel DataTables Fractal Plugin.

966.9M29](/packages/yajra-laravel-datatables-fractal)[contributte/comgate

Comgate Payment Gateway for Nette Framework

19839.7k1](/packages/contributte-comgate)[kelemen/api-nette

Api for Nette framework

181.9k](/packages/kelemen-api-nette)

PHPackages © 2026

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