chaplean / api-client-bundle
用于定义REST API客户端的库
Requires
- php: >=7.0.8
- eightpoints/guzzle-bundle: ^7.0
- symfony/config: ^3.0 || ^4.0
- symfony/console: ^3.0 || ^4.0
- symfony/dependency-injection: ^3.0 || ^4.0
- symfony/yaml: ^3.0 || ^4.0
Requires (Dev)
- chaplean/coding-standard: ^1.1
- doctrine/doctrine-bundle: ^1.6
- doctrine/orm: ^2.5
- friendsofsymfony/rest-bundle: ^2.0
- mockery/mockery: dev-master
- php-coveralls/php-coveralls: ^2.1
- phpunit/phpunit: ^7.0
- symfony/http-kernel: ^3.0 || ^4.0
- symfony/swiftmailer-bundle: ^3.0 || ^4.0
- symfony/var-dumper: ^3.0 || ^4.0
This package is auto-updated.
Last update: 2022-07-21 17:58:24 UTC
README
用于定义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束。如果您想看示例,请参考我们在packagist或github上的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. ... } }
附加功能
此捆绑包公开了一些配置,如果您想启用额外功能,可以启用数据库和/或电子邮件请求记录。要使用数据库或电子邮件记录器,您必须在项目中分别设置doctrine或swiftmailer。默认配置为:
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,其中
- MAJOR在发生破坏性更改时增加;
- MINOR在以向后兼容的方式添加新功能时增加;
- PATCH在以向后兼容的方式修复错误时增加。
版本低于1.0.0被视为实验性的,并且破坏性更改可能随时发生。
贡献
欢迎贡献!有许多贡献方式,我们非常感谢所有方式。以下是一些主要的贡献方式:
- 错误报告:虽然我们力求提供高质量的软件,但错误仍然可能发生,我们无法解决我们未意识到的问题。所以,即使您不确定或有疑问,也请进行报告。任何可能表明文档仍有改进空间的问题都值得报告!
- 功能请求:当前API没有覆盖到您的使用场景?希望提出改进或增加某些功能?我们非常乐意阅读您的建议,并开始讨论以寻找最佳解决方案。
- 拉取请求:希望贡献代码或文档?我们非常欢迎!如果您需要帮助开始,GitHub有关于拉取请求的文档。我们使用“分叉并拉取”模式,即贡献者将更改推送到他们的个人分叉,然后创建拉取请求到主仓库。请确保您的拉取请求针对的是
master
分支。
提醒一下,所有贡献者都应遵守我们的行为准则。
黑客攻击
在修改此项目时,您可能会发现以下命令很有用。
# Install dependencies composer install # Run tests bin/phpunit
许可证
api-client-bundle遵循MIT许可证的条款进行分发。
有关详细信息,请参阅LICENSE。