chaplean/api-client-bundle

此包已被废弃且不再维护。没有建议的替代包。

用于定义REST API客户端的库

安装量: 2,334

依赖者: 5

建议者: 0

安全: 0

星标: 0

关注者: 4

分支: 1

公开问题: 6

类型:symfony-bundle

v1.3.0 2019-06-05 07:53 UTC

README

build status Coverage status contributions welcome

用于定义REST API客户端的库。

目录

安装

此束需要至少Symfony 3.0。

您可以使用composer来安装api-client-bundle

composer require chaplean/api-client-bundle

然后将它添加到您的AppKernel.php中

new EightPoints\Bundle\GuzzleBundle\EightPointsGuzzleBundle(),
new Chaplean\Bundle\ApiClientBundle\ChapleanApiClientBundle(),

// If you want to enable Database logging
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),

// If you want to enable Email logging
new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(),
new Symfony\Bundle\TwigBundle\TwigBundle()

基于api-client-bundle创建束

本节描述了如何根据此项目创建您自己的api束。如果您想看示例,请参考我们在packagistgithub上的api束。

配置

首先,您需要配置我们用于执行实际HTTP请求的guzzlehttp。请参阅文档或文档以获取完整选项范围。

config.yml

eight_points_guzzle:
    logging: true
    clients:
        fake_api:
            # We inject guzzle configuration from parameters.yml but we could hardcode it here
            options: %fake_api.options%

您可能还需要创建一些自定义参数。

parameters.yml

parameters:
    # Guzzle configuration
    fake_api.options:
        timeout: 10
        verify: false
        expect: false

    # Your custom configuration, here we just define the base url of our fake_api
    fake_api.url: 'http://fakeapi.com/'

由于您在Api类中注入了guzzle,您可以为每个Api有不同的配置。请参阅下一节创建Api

创建Api类

要使用api-client-bundle,您必须创建一个扩展AbstractApi的类。您可以根据需要创建任意数量的扩展AbstractApi的类,并通过依赖注入使用不同的配置。

<?php

use Chaplean\Bundle\ApiClientBundle\Api\AbstractApi;
use Chaplean\Bundle\ApiClientBundle\Api\Parameter;
use GuzzleHttp\ClientInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

class FakeApi extends AbstractApi
{
    protected $url;

    /**
     * AbstractApi requires you to pass it a GuzzleHttp\ClientInterface and an EventDispatcherInterface,
	 * we also inject the base api of our fake_api
     */
    public function __construct(ClientInterface $client, EventDispatcherInterface $eventDispatcher, $url)
    {
        $this->url = $url;

        // buildApi() is called automatically by the parent constructor, make sure you call it at the END of the construct() function.
        parent::__construct($client, $eventDispatcher);
    }

    /**
     * We define our api here, we'll dig into this in the next section
     */
    public function buildApi()
    {
        $this->globalParameters()
            ->urlPrefix($this->url) // here we set base url
            ->expectsJson();

        $this->get('fake_get', 'fake')
            ->urlParameters([
                'id' => Parameter::id(),
            ]);
    }
}
services:
    App\Bundle\ApiBundle\Api\FakeApi:
        arguments:
            $client: '@guzzle.client.fake_api' # Guzzle client we defined in config.yml
            $url:    '%fake_api.url%'          # the base url of fake_api

这就完成了!我们可以重复这个过程来创建另一个具有完全不同配置的Api。

定义Api

让我们关注您必须填充的buildApi()函数以及我们可以在其中做什么。此函数的作用是使用api-client-bundle的api定义您的Api

<?php

public function buildApi()
{
    /*
     * You have to call this function first to set basic config
     */
    $this->globalParameters()
        ->urlPrefix('http://some.url/')  // set the base url of our api
        ->urlSuffix('/some-suffix')      // Configure a suffix on our url (Optional, default: empty)

    /*
     * We can then set some configurations that will be the default for every route we create later.
     * You have the exact same api available here and available when configuring routes.
     * See route definition for detailed descriptions of headers(), urlParameters(), queryParameters() and requestParameters()
     */
        ->expectsPlain()                 // Declare we expect responses to be plain text
        ->expectsJson()                  // Declare we expect responses to be json
        ->expectsXml()                   // Declare we expect responses to be xml

        ->sendFormUrlEncoded()           // Configure that we post our data as classic form url encoded
        ->sendJson()                     // Configure that we post our data as json
        ->sendXml()                      // Configure that we post our data as xml
        ->sendJSONString()               // Configure that we post our data as a url-encoded key-value pair where the key is JSONString and the value is the request data in json format

        ->headers([])                    // Configure what headers we send
        ->urlParameters([])              // Configure what url placeholders we define
        ->queryParameters([])            // Configure what query strings we send
        ->requestParameters([]);         // Configure what post data we send

    /*
     * Here we define the core of our api, the routes. We can use get(), post(), put(), patch(), delete() functions
     * with a route name and a route url (with placeholders in you want) to define routes.
     */
    $this->get('query_one', 'data/{id}');
    $this->post('create_one', 'data');
    $this->patch('update_one', 'data/{id}');
    $this->put('update_one', 'data/{id}');
    $this->delete('delete_one', 'data/{id}');

    /*
     * Those function return the route object to further configure it.
     * As said previously the route api is the same as the one we get with globalParameters().
     */
    $this->post('create_one', 'data/{id}')
        ->expectsPlain()                 // Declare we expect responses to be plain text
        ->expectsJson()                  // Declare we expect responses to be json
        ->expectsXml()                   // Declare we expect responses to be xml

        ->sendFormUrlEncoded()           // Configure that we post our data as classic form url encoded
        ->sendJson()                     // Configure that we post our data as json
        ->sendXml()                      // Configure that we post our data as xml
        ->sendJSONString()               // Configure that we post our data as a url-encoded key-value pair where the key is JSONString and the value is the request data in json format

        ->headers([])                    // Configure what headers we send
        ->urlParameters([])              // Configure what url placeholders we define
        ->queryParameters([])            // Configure what query strings we send
        ->allowExtraQueryParameters()    // Allow extra field in query parameters
        ->requestParameters([])          // Configure what post data we send
        ->allowExtraQueryParameters();   // Allow extra field in request parameters

    /*
     * Finally calling headers(), urlParameters(), queryParameters() or requestParameters() without configuring parameters is sort of useless.
     * So let's see how to define parameters.
     */
    $this->put('update_data', 'data/{id}')
        ->urlParameters(                 // Define the placeholder parameter for the {id} in the url
            [
                'id' => Parameter::id(),
            ]
        )
    /*
     * We define a list of key => values pairs where key is the name of the parameter and the value is a parameter type.
     */
        ->requestParameters(
            [
                'name'     => Parameter::string(),
                'birthday' => Parameter::dateTime('Y-m-d'),
                'is_human' => Parameter::bool()->defaultValue(true),
                'height'   => Parameter::int(),
                'weight'   => Parameter::float()->optional(),
                'tags'     => Parameter::object(
                    [
                        'id'   => Parameter::id(),
                        'name' => Parameter::string(),
                    ]
                ),
                'friends'  => Parameter::arrayList(Parameter::id()),
                'enum'     => Parameter::enum(['foo', 'bar']),
            ]
        );
    /*
     * Last but not least, you can also directly give any instance of Parameter. Here we use ArrayParameter.
     */
        ->requestParameters(Parameter::arrayList(
            Parameter::object(
                [
                    'id'     => Parameter::id()
                ]
            )
        ))

    /*
     * Passing an array is actually a shortcut that implies ObjectParameter since it's the most common.
     * 
     * The following two definitions are equivalent.
     */
        ->requestParameters(
            [
                'id'     => Parameter::id()
            ]
        )

        ->requestParameters(Parameter::object(
            [
                'id'     => Parameter::id()
            ]
        ));
}

参数选项

参数的选项列表

    // Options available for all types of Parameter
    Parameter::xyz()
        ->optional()             // Define the parameter optional
        ->defaultValue('value')  // Define a default value for the field
        
    // Options specific to object Parameter
    Parameter::object()
        ->allowExtraField()      // Allow sending a field not defined in the configuration

使用基于api-client-bundle的束

本节描述了如何使用基于api-client-bundle的束。

如前文所述章节,API定义了一组路由及其接受的参数。要调用路由,需要提供这些参数。

以下是一个API的定义:

class FakeApi
{
    ...

    public function buildApi()
    {
        $this->get('user', '/user/{id}')
            ->urlParameters(['id' => Parameter::id()])
            ->expectsJson()
    }

    ...
}

我们可以调用getUser()方法,提供参数并运行请求。

$response = $api->getUser()           // the get('user', '/user/{id}') definition added a getUser() method
    ->bindUrlParameters(['id' => 42]) // we provide a value for the 'id' parameter
    ->exec();                         // we can now execute the request

这里我们调用bindUrlParameters()urlParameters()定义的参数提供值。同样,对于用headers()queryParameters()requestParameters()定义的参数,存在相应的bindHeaders()bindQueryParameters()bindRequestParameters()

您需要使用key => value数组来调用这些函数。在运行请求之前,exec()会进行一次验证,确保您提供的值与API中的定义相匹配。

最后,exec()返回一个ResponseInterface。该接口有几个实现。

  • InvalidParameterResponse:提供的参数无效;
  • RequestFailedResponse:请求执行但失败(网络问题或非2xx状态码);
  • PlainResponse:请求成功且路由定义为expectsPlain()或未指定;
  • JsonResponse:请求成功且路由定义为expectsJson()
  • XmlResponse:请求成功且路由定义为expectsXml()

ResponseInterface中的函数中,这里有一些有用的函数以及如何使用它们:

if ($response->succeeded()) {                 // Was the response a 2xx?
    // The request suceeded.
    $content = $response->getContent();       // Get the body of the response,
                                              // will be a string for plain text
                                              // and associative array for json and xml.
    ...
} else {
    $violations = $response->getViolations(); // If the provided parameters were invalid.
                                              // this will contain the violations.
    if (!empty($violations)) {
        // The request failed because of invalid parameters.
        ...
    } else {
        // The request failed due to a network issue or the response was not a 2xx.
        ...
    }
}

附加功能

此捆绑包公开了一些配置,如果您想启用额外功能,可以启用数据库和/或电子邮件请求记录。要使用数据库或电子邮件记录器,您必须在项目中分别设置doctrineswiftmailer。默认配置为:

config.yml

chaplean_api_client:
    # Specify when to log api requests. You can give a boolean to enable or disable globally
    # or give a white list of clients where logging is only enabled for the listed clients (ex: ['foo_api', 'bar_api'])
    # or a black list where logging is enabled for all clients excepted those listed (ex: ['!foo_api', '!bar_api'])
    # or a string of a client where logging is only enabled (ex: 'foo_api') or excepted for this client (ex: '!foo_api')
    # or a ~ equivalent to true value.
    enable_database_logging: false
    enable_email_logging: false
    email_logging:
        # Limit emails to the specified codes.
        # You can either use a code directly like 200, 404, ...
        # or use XX to say all codes in the familly like 5XX to say all server errors.
        # 0 means that the request failed to run (either because of invalid parameters or a networking error)
        codes_listened: ['0', '1XX', '2XX', '3XX', '4XX', '5XX']
        address_from: ~
        address_to:   ~

您可以通过覆盖翻译键或甚至电子邮件体TWIG模板来覆盖默认电子邮件内容。翻译键位于chaplean_api_client.email.request_executed_notification下,模板为Resources/views/Email/request_executed_notification.txt.twig

命令

要清理数据库中的日志,您可以使用命令chaplean:api-logs:clean [minimumDate]。它将删除旧日志,仅保留比给定minimumDate日期更近的日志。默认情况下,此参数日期为now -1 month。它应该格式化为PHP的DateTime字符串

此命令会在您的数据库中进行不可逆更改,因此我们强烈建议在执行之前备份日志。

版本

api-client-bundle遵循语义版本控制。简而言之,方案是MAJOR.MINOR.PATCH,其中

  1. MAJOR在发生破坏性更改时增加;
  2. MINOR在以向后兼容的方式添加新功能时增加;
  3. PATCH在以向后兼容的方式修复错误时增加。

版本低于1.0.0被视为实验性的,并且破坏性更改可能随时发生。

贡献

欢迎贡献!有许多贡献方式,我们非常感谢所有方式。以下是一些主要的贡献方式:

  • 错误报告:虽然我们力求提供高质量的软件,但错误仍然可能发生,我们无法解决我们未意识到的问题。所以,即使您不确定或有疑问,也请进行报告。任何可能表明文档仍有改进空间的问题都值得报告!
  • 功能请求:当前API没有覆盖到您的使用场景?希望提出改进或增加某些功能?我们非常乐意阅读您的建议,并开始讨论以寻找最佳解决方案。
  • 拉取请求:希望贡献代码或文档?我们非常欢迎!如果您需要帮助开始,GitHub有关于拉取请求的文档。我们使用“分叉并拉取”模式,即贡献者将更改推送到他们的个人分叉,然后创建拉取请求到主仓库。请确保您的拉取请求针对的是master分支。

提醒一下,所有贡献者都应遵守我们的行为准则

黑客攻击

在修改此项目时,您可能会发现以下命令很有用。

# Install dependencies
composer install

# Run tests
bin/phpunit

许可证

api-client-bundle遵循MIT许可证的条款进行分发。

有关详细信息,请参阅LICENSE