-
Notifications
You must be signed in to change notification settings - Fork 6
Add initial documentation #38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
54aaa42
0bcb3bd
ae28dea
a03b403
3af929b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# Contribution | ||
|
||
We are always open to contributions. Either in form of Pull Requests to the core package or self-made plugin packages. | ||
We encourage everyone to prefer sending Pull Requests, however we don't promise that every plugin gets | ||
merged into the core. If this is the case, it is not because we think your work is not good enough. We try to keep | ||
the core as small as possible with the most widely used plugin implementations. | ||
|
||
Even if we think that a plugin is not suitable for the core, we want to help you sharing your work with the community. | ||
You can always open a Pull Request to place a link and a small description of your plugin on the | ||
[Third Party Plugins](third-party-plugins.md) page. In special cases, | ||
we might offer you to host your package under the PHP HTTP namespace. | ||
|
||
For more details about contribution, please see our | ||
[contribution guide](http://docs.httplug.io/en/latest/contributing/). |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/* | ||
* Exclude first title from TOC | ||
*/ | ||
li.toctree-l3:first-child { | ||
display: none; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
# Implement your own | ||
|
||
When writing your own Plugin, you need to be aware that the Plugin Client is async first. | ||
This means that every plugin must be written with Promises. More about this later. | ||
|
||
Each plugin must implement the `Http\Client\Plugin\Plugin` interface. | ||
|
||
This interface defines the `handleRequest` method that allows to modify behavior of the call: | ||
|
||
```php | ||
/** | ||
* Handles the request and returns the response coming from the next callable. | ||
* | ||
* @param RequestInterface $request Request to use. | ||
* @param callable $next Callback to call to have the request, it muse have the request as it first argument. | ||
* @param callable $first First element in the plugin chain, used to to restart a request from the beginning. | ||
* | ||
* @return Promise | ||
*/ | ||
public function handleRequest(RequestInterface $request, callable $next, callable $first); | ||
``` | ||
|
||
The `$request` comes from an upstream plugin or Plugin Client itself. | ||
You can replace it and pass a new version downstream if you need. | ||
|
||
!!! note "Note:" | ||
Be aware that the request is immutable. | ||
|
||
|
||
The `$next` callable is the next plugin in the execution chain. When you need to call it, you must pass the `$request` | ||
as the first argument of this callable. | ||
|
||
For example a simple plugin setting a header would look like this: | ||
|
||
``` php | ||
public function handleRequest(RequestInterface $request, callable $next, callable $first) | ||
{ | ||
$newRequest = $request->withHeader('MyHeader', 'MyValue'); | ||
|
||
return $next($newRequest); | ||
} | ||
``` | ||
|
||
The `$first` callable is the first plugin in the chain. It allows you to completely reboot the execution chain, or send | ||
other request if needed, while still going through all the defined plugins. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [...] another request [...] or [...] other requests [...] |
||
Like in case of the `$next` callable, you must pass the `$request` as the first argument. | ||
|
||
``` | ||
public function handleRequest(RequestInterface $request, callable $next, callable $first) | ||
{ | ||
if ($someCondition) { | ||
$newRequest = new Request(); | ||
$promise = $first($newRequest); | ||
|
||
// Use the promise do some jobs ... | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [...] promise to do [...] |
||
} | ||
|
||
return $next($request); | ||
} | ||
``` | ||
|
||
!!! warning "Warning:" | ||
In this example the condition is not superfluous: | ||
you need to have some way to not call the `$first` callable each time | ||
or you will end up in an infinite execution loop. | ||
|
||
The `$next` and `$first` callable will return a Promise (defined in `php-http/promise`). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. callables |
||
You can manipulate the `ResponseInterface` or the `Exception` by using the `then` method of the promise. | ||
|
||
``` | ||
public function handleRequest(RequestInterface $request, callable $next, callable $first) | ||
{ | ||
$newRequest = $request->withHeader('MyHeader', 'MyValue'); | ||
|
||
return $next($request)->then(function (ResponseInterface $response) { | ||
return $response->withHeader('MyResponseHeader', 'value'); | ||
}, function (Exception $exception) { | ||
echo $exception->getMessage(); | ||
|
||
throw $exception; | ||
}); | ||
} | ||
``` | ||
|
||
!!! warning "Warning:" | ||
Contract for the `Http\Promise\Promise` is temporary until | ||
[PSR is released](https://groups.google.com/forum/?fromgroups#!topic/php-fig/wzQWpLvNSjs). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [...] until a PSR [...] |
||
Once it is out, we will use this PSR in HTTPlug and deprecate the old contract. | ||
|
||
|
||
To better understand the whole process check existing implementations in the | ||
[plugin repository](https://github.com/php-http/plugins). |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
# HTTPlug Plugins | ||
|
||
[HTTPlug](http://httplug.io) is an HTTP Client abstraction layer for PHP. | ||
|
||
The plugin system allows to wrap a Client and add some processing logic prior to and/or after sending the actual | ||
request or you can even start a completely new request. This gives you full control over what happens in your workflow. | ||
|
||
|
||
## Install | ||
|
||
Install the plugin client in your project with [Composer](https://getcomposer.org/): | ||
|
||
``` bash | ||
$ composer require "php-http/plugins" | ||
``` | ||
|
||
|
||
## How it works | ||
|
||
In the plugin package, you can find the following content: | ||
|
||
- the Plugin Client itself which acts as a wrapper around any kind of HTTP Client (sync/async) | ||
- a Plugin interface | ||
- a set of core plugins (see the full list in the left side navigation) | ||
|
||
The Plugin Client accepts an HTTP Client implementation and an array of plugins. | ||
|
||
Let's see an example: | ||
|
||
``` php | ||
use Http\Discovery\HttpClientDiscovery; | ||
use Http\Client\Plugin\PluginClient; | ||
use Http\Client\Plugin\RetryPlugin; | ||
use Http\Client\Plugin\RedirectPlugin; | ||
|
||
$retryPlugin = new RetryPlugin(); | ||
$redirectPlugin = new RedirectPlugin(); | ||
|
||
$pluginClient = new PluginClient( | ||
HttpClientDiscovery::find(), | ||
[ | ||
$retryPlugin, | ||
$redirectPlugin, | ||
] | ||
); | ||
``` | ||
|
||
The Plugin Client accepts and implements both `Http\Client\HttpClient` and `Http\Client\HttpAsyncClient`, so you can use | ||
both ways to send a request. In case the passed client implements only one of these interfaces, the Plugin Client | ||
"emulates" the other behavior as a fallback. | ||
|
||
It is important, that the order of plugins matter. During the request, plugins are called in the order they have | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. matters |
||
been added, from first to last. Once a response has been received, they are called again in a reversed order, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [...] in reversed order [...] |
||
from last to first. | ||
|
||
In case of our previous example, the execution chain will look like this: | ||
|
||
``` | ||
Request ---> PluginClient ---> RetryPlugin ---> RedirectPlugin ---> HttpClient ---- | ||
| (processing call) | ||
Response <--- PluginClient <--- RetryPlugin <--- RedirectPlugin <--- HttpClient <--- | ||
``` | ||
|
||
In order to have correct behavior over the global process, you need to understand well how each plugin used, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [...] plugin is used [...] |
||
and manage a correct order when passing the array to the Plugin Client. | ||
|
||
Retry Plugin will be best at the end to optimize the retry process, but it can also be good | ||
to have it as the first plugin, if one of the plugins is inconsistent and may need a retry. | ||
|
||
The recommended way to order plugins is the following: | ||
|
||
1. Plugins that modify the request should be at the beginning (like Authentication or Cookie Plugin) | ||
2. Plugins which intervene in the workflow should be in the "middle" (like Retry or Redirect Plugin) | ||
3. Plugins which log information should be last (like Logger or History Plugin) | ||
|
||
!!! note "Note:" | ||
There can be exceptions to these rules. For example, | ||
for security reasons you might not want to log the authentication information (like `Authorization` header) | ||
and choose to put the Authentication Plugin after the Logger Plugin. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Authentication Plugin | ||
|
||
This plugin uses the [authentication component](http://docs.httplug.io/en/latest/components/authentication/) | ||
from `php-http/message` to authenticate requests sent through the client. | ||
|
||
|
||
``` php | ||
use Http\Discovery\HttpClientDiscovery; | ||
use Http\Message\Authentication\BasicAuth; | ||
use Http\Plugins\PluginClient; | ||
use Http\Plugins\AuthenticationPlugin; | ||
|
||
$authentication = new BasicAuth('username', 'password'); | ||
$authenticationPlugin = new AuthenticationPlugin($authentication); | ||
|
||
$pluginClient = new PluginClient( | ||
HttpClientDiscovery::find(), | ||
[$authenticationPlugin] | ||
); | ||
``` | ||
|
||
Check the [authentication component documentation](http://docs.httplug.io/en/latest/components/authentication/) | ||
for the list of available authentication methods. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Cookie Plugin | ||
|
||
TODO: explain the cookie plugin |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Encoding Plugin | ||
|
||
TODO: explain the encoding plugin |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Error Plugin | ||
|
||
TODO: explain the error plugin |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Redirect Plugin | ||
|
||
TODO: explain the redirect plugin |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Retry Plugin | ||
|
||
TODO: explain the retry plugin |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Stopwatch Plugin | ||
|
||
TODO: explain the stopwatch plugin |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Third Party Plugins |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
site_name: HTTPlug Plugins Documentation | ||
site_favicon: favicon.ico | ||
copyright: © 2015 PHP HTTP Team | ||
theme: readthedocs | ||
extra_css: | ||
- css/extra.css | ||
markdown_extensions: | ||
- toc: | ||
permalink: true | ||
- sane_lists | ||
- admonition |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this actually true? I mean a plugin could also replace the response coming from the next callable (for example, to filter it), couldn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, you also do something like that (modifying the response) in one example below.