-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
386 additions
and
17 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,37 @@ | ||
Each REST endpoint has its unique logic. Same goes with the data that it needs to work. | ||
|
||
For that reason, WP-FastEndpoints provides dependency injection support for all handlers | ||
e.g. permission handlers, main endpoint handler and middlewares. | ||
|
||
With dependency injection our endpoints do look much cleaner ✨🧹 | ||
|
||
=== "With dependency injection" | ||
|
||
```php | ||
// We only need the ID. So we type $ID | ||
$router->get('/posts/(?P<ID>[\d]+)', function ($ID) { | ||
return get_post($ID); | ||
}); | ||
|
||
// We don't need anything. So no arguments are defined :D | ||
$router->get('/posts/random', function () { | ||
$allPosts = get_posts(); | ||
return $allPosts ? $allPosts[array_rand($allPosts)] : new WpError(404, 'No posts found'); | ||
}); | ||
``` | ||
|
||
=== "No dependency injection" | ||
|
||
```php | ||
// Unable to fetch a dynamic parameter. Have to work with the $request argument | ||
$router->get('/posts/(?P<ID>[\d]+)', function ($request) { | ||
return get_post($request->get('ID')); | ||
}); | ||
|
||
// Forced to accept $request even if not used :( | ||
$router->get('/posts/random', function ($request) { | ||
$allPosts = get_posts(); | ||
return $allPosts ? $allPosts[array_rand($allPosts)] : new WpError(404, 'No posts found'); | ||
}); | ||
``` | ||
|
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,6 @@ | ||
The [Quick Start](/wp-fastendpoints/quick-start/) should be able to get you a feel of | ||
the main features of WP-FastEndpoints. | ||
|
||
However, it's possible that the solution for your use case might not be in the Quick Start | ||
tutorial. In the next sections we will take a look at further functionalities that | ||
WP-FastEndpoints provides. |
65 changes: 65 additions & 0 deletions
65
docs/docs/advanced-user-guide/json-schemas/multiple-root-dirs.md
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,65 @@ | ||
For most projects, all JSON schemas might be kept inside a single root directory, like: | ||
|
||
```text | ||
my-plugin | ||
│ | ||
└───src | ||
│ │ | ||
│ └───Api | ||
│ │ │ | ||
│ │ └───Schemas // Root dir | ||
│ │ │ | ||
│ │ └───Posts | ||
│ │ │ │ (...) | ||
│ │ │ | ||
│ │ └───Users | ||
│ │ │ (...) | ||
``` | ||
|
||
However, when your API starts to grow you might end up having the need for multiple root directories. | ||
|
||
## Example | ||
|
||
Let's imagine that your API consists on two different versions: v1 and v2, like the following: | ||
|
||
```text | ||
my-plugin | ||
│ | ||
└───src | ||
│ │ | ||
│ └───Api | ||
│ │ │ | ||
│ │ └───v1 | ||
│ │ │ └───Schemas // V1 JSON schemas root dir | ||
│ │ │ │ | ||
│ │ │ └───Posts | ||
│ │ │ │ (...) | ||
│ │ │ | ||
│ │ └───v2 | ||
│ │ └───Schemas // V2 JSON schemas root dir | ||
│ │ │ | ||
│ │ └───Posts | ||
│ │ │ (...) | ||
``` | ||
|
||
In this case scenario your code would look something like this: | ||
|
||
```php | ||
$router->appendSchemaDir(MY_PLUGIN_DIR.'Api/v1/Schemas', 'https://www.wp-fastendpoints.com/v1'); | ||
$router->appendSchemaDir(MY_PLUGIN_DIR.'Api/v2/Schemas', 'https://www.wp-fastendpoints.com/v2'); | ||
``` | ||
|
||
Then in all your endpoints you will have to specify the full schema prefix. It's important that | ||
you specify the full prefix because we can't guarantee the order or even if the same schema | ||
directory is returned all the time. | ||
|
||
=== "Using v1 schemas" | ||
```php | ||
$router->get('/test', function(){return true;}) | ||
->returns('https://www.wp-fastendpoints.com/v1/Posts/Get.json'); | ||
``` | ||
=== "Using v2 schemas" | ||
```php | ||
$router->get('/test', function(){return true;}) | ||
->returns('https://www.wp-fastendpoints.com/v2/Posts/Get.json'); | ||
``` |
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,12 @@ | ||
[References](https://opis.io/json-schema/2.x/references.html) is another great feature from | ||
[opis/json-schema](https://opis.io/json-schema/2.x/). | ||
|
||
With references, you are able to point to another JSON schema inside of schema. This can | ||
be useful to reuse the same schema multiple times. | ||
|
||
!!! tip | ||
Bear in mind that when referencing a schema the full prefix must be used e.g. | ||
*https://www.wp-fastendpoints.com/Posts/Get.json* | ||
|
||
Take a look at their [References Docs »](https://opis.io/json-schema/2.x/references.html) | ||
for more information |
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,62 @@ | ||
WP-FastEndpoints uses [opis/json-schema](https://opis.io/json-schema/2.x/) for JSON schema validation. | ||
|
||
The reason we don't use the default | ||
[WordPress JSON schema validation functionality](https://developer.wordpress.org/reference/functions/rest_validate_value_from_schema/) | ||
is because it's quite outdated: it only partially supports [JSON schema draft 4](https://json-schema.org/specification#migrating-from-older-drafts). | ||
[opis/json-schema](https://opis.io/json-schema/2.x/) on the other side, does support the latest JSON schema drafts. | ||
|
||
## Customising validator | ||
|
||
One of the coolest features of [opis/json-schema](https://opis.io/json-schema/2.x/) is that | ||
is super flexible, and supports: | ||
|
||
- [Custom formats](https://opis.io/json-schema/2.x/php-format.html) | ||
- [Custom filters](https://opis.io/json-schema/2.x/php-filter.html) | ||
- [Custom media types](https://opis.io/json-schema/2.x/php-media-type.html) and | ||
- [Custom content encoding](https://opis.io/json-schema/2.x/php-content-encoding.html) | ||
|
||
These, can be super useful when ever you need some custom functionality in your JSON schemas. | ||
|
||
### Available hooks | ||
|
||
There are three WordPress filter hooks that you can use to customise the JSON schema validators | ||
used in WP-FastEndpoints: | ||
|
||
1. `fastendpoints_validator` - Triggered by both middlewares | ||
2. `fastendpoints_schema_validator` - Only triggered for Schema middlewares validators | ||
3. `fastendpoints_response_validator` - Only triggered for Response middlewares validators | ||
|
||
#### Example | ||
|
||
Imagine we only want to accept even numbers. To solve this issue, we might want to create a new custom format | ||
for integers, called `even`, which checks if a given number is even, like: | ||
|
||
```php | ||
use Opis\JsonSchema\Validator; | ||
|
||
/** | ||
* Adds custom format resolvers to all JSON validators: request payload schema and response. | ||
* | ||
* @see fastendpoints_schema_validator - To update only the request payload schema validator, or | ||
* @see fastendpoints_response_validator - To update only the response validator | ||
*/ | ||
add_filter('fastendpoints_validator', function (Validator $validator): Validator { | ||
$formatsResolver = $validator->parser()->getFormatResolver(); | ||
$formatsResolver->registerCallable('integer', 'even', function (int $value): bool { | ||
return $value % 2 === 0; | ||
}); | ||
|
||
return $validator; | ||
}); | ||
``` | ||
|
||
Here is an example of a JSON schema using our custom `even` format: | ||
|
||
```json | ||
{ | ||
"type": "integer", | ||
"format": "even" | ||
} | ||
``` | ||
|
||
More examples can be found in [Custom Formats docs »](https://opis.io/json-schema/2.x/php-format.html) |
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,47 @@ | ||
Another cool feature of WP-FastEndpoints is the support for middlewares. | ||
|
||
Middlewares are pieces of code that can either run before and/or after a request is handled. | ||
|
||
At this stage, you might be already familiar with both the `schema(...)` and `returns(...)` | ||
middlewares. However, you can also create your own. | ||
|
||
```php | ||
use Wp\FastEndpoints\Contracts\Middleware; | ||
|
||
class MyCustomMiddleware extends Middleware | ||
{ | ||
/** | ||
* Create this function if you want that your middleware is | ||
* triggered when it receives a request and after checking | ||
* the user permissions. | ||
*/ | ||
public function onRequest(/* Type what you need */) | ||
{ | ||
return; | ||
} | ||
|
||
/** | ||
* Create this function when you want your middleware to be | ||
* triggered before sending a response to the client | ||
*/ | ||
public function onResponse(/* Type what you need */) { | ||
return; | ||
} | ||
} | ||
|
||
// Attach middleware to endpoint | ||
$router->get('/test', function () { | ||
return true; | ||
}) | ||
->middleware(new MyCustomMiddleware()); | ||
``` | ||
|
||
???+ tip | ||
You can create both methods in a middleware: `onRequest` and `onResponse`. | ||
However, to save some CPU cycles only create the one you need [CPU emoji] | ||
|
||
## Responses | ||
|
||
If you need you can also take advantage of either WP_Error and WP_REST_Response to send | ||
a direct response to the client. See [Responses page](/wp-fastendpoints/advanced-user-guide/responses) | ||
for more info |
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,75 @@ | ||
In WP-FastEndpoints an endpoint can have multiple optional handlers attached to: | ||
|
||
1. Permission handlers via `hasCap(...)` or `permission(...)` - Used to check for user permissions | ||
2. Middlewares | ||
1. Request Payload Schema Middleware via `schema(...)` - Validates the request payload | ||
2. Response Schema Middleware via `returns(...)` - Makes sure that the proper response is sent to the client | ||
3. Custom middlewares via `middleware(...)` - Any other custom logic that you might want to run | ||
|
||
## Permission handlers | ||
|
||
When a request is received the first handlers to run are the permissions handlers. Permission handlers are called | ||
by WordPress via [`permission_callback`](https://developer.wordpress.org/rest-api/extending-the-rest-api/routes-and-endpoints/#callbacks). | ||
|
||
In contrast to WordPress, you can have one or multiple permission handlers attached to the same endpoint. | ||
|
||
???+ note | ||
In the background all permission handlers are wrapped into one callable which is later on used as | ||
`permission_callback` by the endpoint | ||
|
||
These handlers will then be called in the same order as they were attached. For instance: | ||
|
||
```php | ||
$router->get('/test', function () {return true;}) | ||
->hasCap('read') # Called first | ||
->hasCap('edit_posts') # Called second if the first one was successful | ||
->permission('__return_true') # Called last if both the first and second were successful | ||
``` | ||
|
||
## Middlewares | ||
|
||
If all the permission handlers are successful the next set of handlers that run are the middlewares which | ||
implement the `onRequest` function. | ||
|
||
Remember that a middleware can implement `onRequest` and/or `onResponse` functions. The first one, runs before | ||
the main endpoint handler and the later one should run after the main endpoint handler. | ||
|
||
!!! warning | ||
Please bear in mind that if either a [WP_Error](https://developer.wordpress.org/reference/classes/wp_error/) or | ||
a [WP_REST_Response](https://developer.wordpress.org/reference/classes/wp_rest_response/) is returned by | ||
the main endpoint handler following middlewares will not run. See | ||
[Responses page](/wp-fastendpoints/advanced-user-guide/responses) for more info. | ||
|
||
### onRequest | ||
|
||
Same as with the permission handlers, middlewares are called with the same order that they were attached. | ||
|
||
```php | ||
class OnRequestMiddleware extends \Wp\FastEndpoints\Contracts\Middleware | ||
{ | ||
public function onRequest(/* Type what you need */){ | ||
return; | ||
} | ||
} | ||
|
||
$router->post('/test', function () {return true;}) | ||
->middleware(OnRequestMiddleware()) # Called first | ||
->schema('Basics/Bool'); # Called second | ||
``` | ||
|
||
### onResponse | ||
|
||
Likewise, middlewares implementing onResponse functions will be triggered in the same order as they were attached. | ||
|
||
```php | ||
class OnResponseMiddleware extends \Wp\FastEndpoints\Contracts\Middleware | ||
{ | ||
public function onResponse(/* Type what you need */){ | ||
return; | ||
} | ||
} | ||
|
||
$router->post('/test', function () {return true;}) | ||
->returns('Basics/Bool') # Called first | ||
->middleware(OnResponseMiddleware()); # Called second | ||
``` |
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,52 @@ | ||
When building an API sometimes we want to return a response directly to the client. For example: | ||
|
||
```php | ||
$router->get('/posts/(?P<ID>[\d]+)', function ($ID) { | ||
return get_post($ID); | ||
}) | ||
->returns('Posts/Get'); // It will raise a 422 HTTP error when we are unable to find a post | ||
``` | ||
|
||
The code above, will raise a 422 HTTP status code error when ever we are unable to find | ||
a given post. This is where returning a message directly to the client can be useful. | ||
|
||
## Early return | ||
|
||
To trigger those scenarios we can either return a WP_Error or a WP_REST_Response. | ||
|
||
=== "WP_REST_Response" | ||
```php | ||
$router->get('/posts/(?P<ID>[\d]+)', function ($ID) { | ||
$post = get_post($ID); | ||
return $post ?: new WP_REST_Response("No posts found", 404); | ||
}) | ||
->returns('Posts/Get'); // This will not be triggered if no posts are found | ||
``` | ||
=== "WP_Error" | ||
```php | ||
$router->get('/posts/(?P<ID>[\d]+)', function ($ID) { | ||
$post = get_post($ID); | ||
return $post ?: new WpError(404, "No posts found"); | ||
}) | ||
->returns('Posts/Get'); // This will not be triggered if no posts are found | ||
``` | ||
|
||
### Difference between returning WP_REST_Response or WP_Error | ||
|
||
The main difference between returning a WP_Error or a WP_REST_Response | ||
is regarding the JSON returned in the body. | ||
|
||
=== "WP_REST_Response" | ||
```json | ||
"No posts found" | ||
``` | ||
=== "WP_Error" | ||
```json | ||
{ | ||
"error": 404, | ||
"message": "No posts found", | ||
"data": { | ||
"status": 404 | ||
} | ||
} | ||
``` |
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
Oops, something went wrong.