-
-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Combine all apitte packages to contributte/apitte
- Loading branch information
Showing
297 changed files
with
19,864 additions
and
100 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Console | ||
|
||
Console commands for Apitte. | ||
|
||
## Content | ||
|
||
- [Setup](#setup) | ||
- [Commands](#commands) | ||
|
||
## Setup | ||
|
||
Install and register console plugin. | ||
|
||
```neon | ||
api: | ||
plugins: | ||
Apitte\Console\DI\ConsolePlugin: | ||
``` | ||
|
||
You also need setup an integration of [symfony/console](https://symfony.com/doc/current/components/console.html), try [contributte/console](https://github.com/contributte/console/) | ||
|
||
## Commands | ||
|
||
### Route dump | ||
|
||
List all endpoints and their details | ||
|
||
```bash | ||
php bin/console apitte:route:dump | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# Debug | ||
|
||
Debug tools for Apitte, based on [Tracy debugger](https://github.com/nette/tracy). | ||
|
||
## Setup | ||
|
||
Install and register debug plugin. | ||
|
||
```neon | ||
api: | ||
plugins: | ||
Apitte\Debug\DI\DebugPlugin: | ||
debug: | ||
panel: %debugMode% | ||
negotiation: %debugMode% | ||
``` | ||
|
||
## Tracy | ||
|
||
- bar panel - displays all router | ||
- blue screen panel - displays endpoint with invalid schema | ||
|
||
## Negotiation | ||
|
||
If you have [negotiation](./negotiation.md) plugin installed then you will be able to use two new suffixes. | ||
|
||
With these suffixes you will also be able to see **Tracy bar** | ||
|
||
`.debug` | ||
|
||
- dumps response | ||
- `example.com/api/v1/users.debug` | ||
|
||
`.debugdata` | ||
|
||
- dumps response entity | ||
- `example.com/api/v1/users.debugdata` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# Middlewares | ||
|
||
Middlewares for Apitte. | ||
|
||
Transform and validate request or early return response before it is handled by dispatcher. | ||
|
||
## Setup | ||
|
||
Install and register middlewares plugin. | ||
|
||
```neon | ||
api: | ||
plugins: | ||
Apitte\Middlewares\DI\MiddlewaresPlugin: | ||
``` | ||
|
||
In `index.php` replace `Apitte\Core\Application\IApplication` with `Contributte\Middlewares\Application\IApplication`. | ||
|
||
## Configuration | ||
|
||
[TracyMiddleware](https://github.com/contributte/middlewares/blob/master/.docs/README.md#tracymiddleware) (with priority 100) | ||
and [AutoBasePathMiddleware](https://github.com/contributte/middlewares/blob/master/.docs/README.md#autobasepathmiddleware) (with priority 200) | ||
are registered by default, but you could disable them if you want. | ||
|
||
```neon | ||
api: | ||
plugins: | ||
Apitte\Middlewares\DI\MiddlewaresPlugin: | ||
tracy: true | ||
autobasepath: true | ||
``` | ||
|
||
`Apitte\Middlewares\ApiMiddleware` which run whole Apitte application is registered with priority 500. Make sure there is no middleware with higher priority. | ||
|
||
## Middlewares | ||
|
||
If you want to add another middleware, just register a class with appropriate tags. | ||
|
||
```neon | ||
services: | ||
m1: | ||
factory: App\Api\Middleware\ExampleMiddleware | ||
tags: [middleware: [priority: 10]] | ||
``` | ||
|
||
```php | ||
namespace App\Api\Middleware; | ||
|
||
use Contributte\Middlewares\IMiddleware; | ||
use Psr\Http\Message\ResponseInterface; | ||
use Psr\Http\Message\ServerRequestInterface; | ||
|
||
class ExampleMiddleware implements IMiddleware | ||
{ | ||
|
||
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next): ResponseInterface | ||
{ | ||
// Call next middleware in a row | ||
$response = $next($request, $response); | ||
// Return response | ||
return $response; | ||
} | ||
|
||
} | ||
``` | ||
|
||
See [contributte/middlewares](https://github.com/contributte/middlewares) documentation for more info and useful middlewares |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
# Negotiation | ||
|
||
Content negotiation for Apitte. | ||
|
||
Transform response entity into response with unified format in dependence on `Accept` header and uri path suffix `/api/v1/users(.json|.xml)` | ||
|
||
## Setup | ||
|
||
Install and register negotiation plugin. | ||
|
||
```neon | ||
api: | ||
plugins: | ||
Apitte\Negotiation\DI\NegotiationPlugin: | ||
``` | ||
|
||
## Response | ||
|
||
Instead of writing data into response body use `$response->withEntity($entity)` so transformers could handle transformation for you. | ||
|
||
```php | ||
namespace App\Api\V1\Controllers; | ||
|
||
use Apitte\Core\Annotation\Controller\ControllerPath; | ||
use Apitte\Core\Annotation\Controller\Method; | ||
use Apitte\Core\Annotation\Controller\Path; | ||
use Apitte\Core\Http\ApiRequest; | ||
use Apitte\Core\Http\ApiResponse; | ||
use Apitte\Negotiation\Http\ArrayEntity; | ||
|
||
/** | ||
* @ControllerPath("/users") | ||
*/ | ||
class UsersController extends BaseV1Controller | ||
{ | ||
|
||
/** | ||
* @Path("/") | ||
* @Method("GET") | ||
*/ | ||
public function index(ApiRequest $request, ApiResponse $response): ApiResponse | ||
{ | ||
$entity = ArrayEntity::from([ | ||
[ | ||
'id' => 1, | ||
'firstName' => 'John', | ||
'lastName' => 'Doe', | ||
'emailAddress' => '[email protected]', | ||
], | ||
[ | ||
'id' => 2, | ||
'firstName' => 'Elon', | ||
'lastName' => 'Musk', | ||
'emailAddress' => '[email protected]', | ||
], | ||
]); | ||
|
||
return $response | ||
->withStatus(ApiResponse::S200_OK) | ||
->withEntity($entity); | ||
} | ||
|
||
} | ||
``` | ||
|
||
## Entities | ||
|
||
Value objects which are used to create response | ||
|
||
- `ArrayEntity` - create from array | ||
- `ObjectEntity` - create from stdClass | ||
- `ScalarEntity` - create from raw data | ||
|
||
## Error handling | ||
|
||
Negotiations are implemented through an `IErrorDecorator`, which have higher priority than internal `ErrorHandler` | ||
so response is created from exception in an `ITransformer` and `ErrorHandler` only log that exception (if you use `PsrLogErrorHandler`) | ||
|
||
### Negotiators | ||
|
||
Handle request and based on path suffix or request headers call appropriate transformer. | ||
|
||
`SuffixNegotiator` | ||
|
||
- used for request with path suffix like `/api/v1/users.json` -> transformer for `json` suffix is used | ||
|
||
`DefaultNegotiator` | ||
|
||
- called when none other transform | ||
- require annotation `@Negotiation(default = true, suffix = "json")` defined on endpoint - transformer for given suffix is looked for | ||
|
||
`FallbackNegotiator` | ||
|
||
- used last if no other negotiator transformed response | ||
- uses json transformer by default | ||
|
||
### Transformers | ||
|
||
Transformers convert entities and exceptions into response. | ||
|
||
`JsonTransformer` | ||
|
||
- transform into json | ||
|
||
`JsonUnifyTransformer` | ||
|
||
- transform into json with unified format | ||
|
||
```neon | ||
api: | ||
plugins: | ||
Apitte\Negotiation\DI\NegotiationPlugin: | ||
unification: true | ||
``` | ||
|
||
`CsvTransformer` | ||
|
||
- transform into csv | ||
- known limitation: data need to be a flat structure | ||
|
||
#### Implementing transformer | ||
|
||
```neon | ||
services: | ||
- factory: App\Api\Transformer\XmlTransformer | ||
tags: [apitte.negotiator.transformer: [suffix: xml, fallback: true]] | ||
``` | ||
|
||
- register transformer for suffix `xml`, used for uris like `/api/v1/users.xml` | ||
- if `fallback: true` is defined and none of transformers matched then use that transformer | ||
|
||
```php | ||
namespace App\Api\Transformer; | ||
|
||
use Apitte\Core\Exception\ApiException; | ||
use Apitte\Core\Http\ApiRequest; | ||
use Apitte\Core\Http\ApiResponse; | ||
use Apitte\Core\Http\ResponseAttributes; | ||
use Apitte\Negotiation\Http\ArrayEntity; | ||
use Apitte\Negotiation\Transformer\AbstractTransformer; | ||
use Throwable; | ||
|
||
class XmlTransformer extends AbstractTransformer | ||
{ | ||
|
||
/** | ||
* Encode given data for response | ||
* | ||
* @param mixed[] $context | ||
*/ | ||
public function transform(ApiRequest $request, ApiResponse $response, array $context = []) : ApiResponse | ||
{ | ||
if (isset($context['exception'])) { | ||
return $this->transformError($context['exception'], $request, $response); | ||
} | ||
|
||
return $this->transformResponse($request, $response); | ||
} | ||
|
||
protected function transformResponse(ApiRequest $request, ApiResponse $response): ApiResponse | ||
{ | ||
$data = $this->getEntity($response)->getData(); | ||
$content = $this->dataToXmlString($data); | ||
$response->getBody()->write($content); | ||
|
||
return $response | ||
->withHeader('Content-Type', 'application/xml'); | ||
} | ||
|
||
protected function transformError(Throwable $error, ApiRequest $request, ApiResponse $response): ApiResponse | ||
{ | ||
if ($error instanceof ApiException) { | ||
$code = $error->getCode(); | ||
$message = $error->getMessage(); | ||
} else { | ||
$code = 500; | ||
$message = 'Application encountered an internal error. Please try again later.'; | ||
} | ||
|
||
return $response | ||
->withStatus($code) | ||
->withAttribute(ResponseAttributes::ATTR_ENTITY, ArrayEntity::from([ | ||
'status' => 'error', | ||
'message' => $message, | ||
])); | ||
} | ||
|
||
} | ||
``` |
Oops, something went wrong.