Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .docs/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Apitte

An opinionated and enjoyable API framework based on Nette Framework. Supporting content negotiation, debugging, middlewares, attributes, annotations and loving openapi/swagger.
An opinionated and enjoyable API framework based on Nette Framework. Supporting content negotiation, debugging, middlewares, attributes and loving openapi/swagger.

Need to start with Apitte
- [Setup](index.md)
Expand Down
2 changes: 1 addition & 1 deletion .docs/decorators.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ class RequestAuthenticationDecorator implements IRequestDecorator

**Tip**

You could also authenticate only some endpoints thanks to [tags](endpoints.md#list-of-annotations) and [metadata](router.md#request-attributes) from `SimpleRouter`.
You could also authenticate only some endpoints thanks to [tags](endpoints.md#list-of-attributes) and [metadata](router.md#request-attributes) from `SimpleRouter`.

```php
use Apitte\Core\Http\RequestAttributes;
Expand Down
48 changes: 20 additions & 28 deletions .docs/endpoints.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,16 @@ namespace App\Api\V1\Controllers;
use Apitte\Core\Annotation\Controller\Path;
use Apitte\Core\UI\Controller\IController;

/**
* @Path("/api/v1")
*/
#[Path("/api/v1")]
abstract class BaseV1Controller implements IController
{
}
```

Create an endpoint

- Controller must have annotation `@Path()` and be registered as service
- Method must have annotations `@Path()` and `@Method()`
- Controller must have attribute `#[Path()]` and be registered as service
- Method must have attributess `#[Path()]` and `#[Method()]`

```yaml
services:
Expand All @@ -43,16 +41,12 @@ use Apitte\Core\Http\ApiRequest;
use Apitte\Core\Http\ApiResponse;
use Nette\Utils\Json;

/**
* @Path("/users")
*/
#[Path("/users")]
class UsersController extends BaseV1Controller
{

/**
* @Path("/")
* @Method("GET")
*/
#[Path("/")]
#[Method("GET")]
public function index(ApiRequest $request, ApiResponse $response): ApiResponse
{
// This is an endpoint
Expand Down Expand Up @@ -80,48 +74,46 @@ class UsersController extends BaseV1Controller
}
```

**Tip** Use the `@Path("/")` annotation on a Controller and its method to target the homepage, e.q. `example.com/`.
**Tip** Use the `#[Path("/")]` attribute on a Controller and its method to target the homepage, e.q. `example.com/`.

### List of annotations / attributes
### List of attributes

> You can use seamless PHP 8 attributes.

`@Id`
`#[Id]`
- Must consist only of following characters: `a-z`, `A-Z`, `0-9`, `_`
- Not used by Apitte for anything, it may just help you identify, group, etc. your endpoints

`@Path`
`#[Path]`
- See example controllers above
- Must consist only of following characters: `a-z`, `A-Z`, `0-9`, `-_/`
- The `@Path` annotation can be used on:
- The `#[Path]` attribute can be used on:
- abstract controller to define a group path for multiple controllers (e.g. `example.com/v1/...`)
- final controller to define a path for that particular controller (e.g. `example.com/v1/users`)
- method to define a path for a specific endpoint
- This hierarchy is then used to build the schema and make routing possible.

`@Method`
`#[Method]`
- Allowed HTTP method for endpoint
- GET, POST, PUT, OPTION, DELETE, HEAD
- `@Method("GET")`
- `@Method({"POST", "PUT"})`
- `#[Method("GET")]`
- `#[Method({"POST", "PUT"})]`
- Defined on method

`@Tag`
`#[Tag]`
- Used by [OpenApi](schema.md#openapi)
- Could by also used by your custom logic
- `@Tag(name="name")`
- `@Tag(name="string", value="string|null")`
- `#[Tag(name="name")]`
- `#[Tag(name="string", value="string|null")]`
- Defined on class and method

Mapping
- Validate and map data from request and map data to response
- `@RequestParameter`, `@RequestParameters`
- `@RequestBody`
- `#[RequestParameter]`
- `#[RequestBody]`
- See [mapping](mapping.md) chapter for more info.

Negotiations
- Response transformations
- `@Negotiation`, `@Negotiations`
- `#[Negotiation]`
- See [negotiation](negotiation.md) chapter for details.

### Automatic controllers registration
Expand Down
33 changes: 14 additions & 19 deletions .docs/mapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,17 @@ namespace App\Api\V1\Controllers;

use Apitte\Core\Annotation\Controller\Method;
use Apitte\Core\Annotation\Controller\Path;
use Apitte\Core\Annotation\Controller\RequestParameters;
use Apitte\Core\Annotation\Controller\RequestParameter;
use Apitte\Core\Http\ApiRequest;
use Apitte\Core\Http\ApiResponse;

/**
* @Path("/users")
*/
#[Path("/users")]
class UsersController extends BaseV1Controller
{

/**
* @Path("/{id}")
* @Method("GET")
* @RequestParameters({
* @RequestParameter(name="id", type="int", description="My favourite user ID")
* })
*/
#[Path("/{id}")]
#[Method("GET")]
#[RequestParameter(name: "id", type: "int", description: "My favourite user ID")]
public function detail(ApiRequest $request): ApiResponse
{
/** @var int $id Perfectly valid integer */
Expand All @@ -57,7 +50,7 @@ class UsersController extends BaseV1Controller

### Options

`@RequestParameter()` have few available options.
`#[RequestParameter()]` have few available options.

- `name="nameOfParameter"` - same as name of parameter in path, query...
- `type="string|int|float|bool|datetime"` - data type, see [data types](#data-types)
Expand Down Expand Up @@ -144,7 +137,7 @@ class MyEmailTypeMapper implements ITypeMapper
## RequestBody

Imagine you have a data grid with many filter options. You can describe all options manually or
use value object, entity, for it. And it leads us to `@RequestBody`.
use value object, entity, for it. And it leads us to `#[RequestBody]`.

We have an entity with described fields.

Expand All @@ -165,15 +158,17 @@ final class UserFilter extends BasicEntity
}
```

And some endpoint with `@RequestBody` annotation. There's a method `ApiRequest::getEntity()`, it gets
And some endpoint with `#[RequestBody]` attribute. There's a method `ApiRequest::getEntity()`, it gets
the entity from request attributes. So simple, right?

```php
/**
* @Path("/filter")
* @Method("GET")
* @RequestBody(entity="App\Api\Entity\Request\UserFilter")
*/
use Apitte\Core\Annotation\Controller\Method;
use Apitte\Core\Annotation\Controller\Path;
use Apitte\Core\Annotation\Controller\RequestParameter;

#[Path("/filter")]
#[Method("GET")]
#[RequestBody(entity: App\Api\Entity\Request\UserFilter::class)]
public function filter(ApiRequest $request)
{
/** @var UserFilter $entity */
Expand Down
13 changes: 4 additions & 9 deletions .docs/negotiation.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,18 @@ Instead of writing data into response body use `$response->withEntity($entity)`
```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")
*/
#[Path("/users")]
class UsersController extends BaseV1Controller
{

/**
* @Path("/")
* @Method("GET")
*/
#[Path("/")]
#[Method("GET")]
public function index(ApiRequest $request, ApiResponse $response): ApiResponse
{
$entity = ArrayEntity::from([
Expand Down Expand Up @@ -87,7 +82,7 @@ Handle request and based on path suffix or request headers call appropriate tran
`DefaultNegotiator`

- called when none other transform
- require annotation `@Negotiation(default = true, suffix = "json")` defined on endpoint - transformer for given suffix is looked for
- require attribute `#[Negotiation(default = true, suffix = "json")]` defined on endpoint - transformer for given suffix is looked for

`FallbackNegotiator`

Expand Down
Loading