Skip to content

Commit fbecdd9

Browse files
committed
Refactor, docs
1 parent 467239c commit fbecdd9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+12389
-492
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
composer.lock
22
vendor
3-
.phpunit.result.cache
3+
node_modules
4+
.phpunit.result.cache

README.md

Lines changed: 244 additions & 80 deletions
Large diffs are not rendered by default.

composer.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
"require": {
55
"php": "^7.2",
66
"doctrine/inflector": "^1.3",
7-
"json-api-php/json-api": "^2.0",
7+
"json-api-php/json-api": "^2.2",
8+
"nyholm/psr7": "^1.3",
89
"psr/http-message": "^1.0",
9-
"psr/http-server-handler": "^1.0",
10-
"zendframework/zend-diactoros": "^2.1"
10+
"psr/http-server-handler": "^1.0"
1111
},
1212
"license": "MIT",
1313
"authors": [

docs/.vuepress/config.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
module.exports = {
2+
base: '/json-api-server/',
3+
title: 'json-api-server',
4+
description: 'A fully automated JSON:API server implementation in PHP.',
5+
evergreen: true,
6+
themeConfig: {
7+
search: false,
8+
nav: [
9+
{ text: 'Guide', link: '/' }
10+
],
11+
sidebar: [
12+
{
13+
title: 'Getting Started',
14+
collapsable: false,
15+
children: [
16+
'/',
17+
'install',
18+
'requests',
19+
]
20+
},
21+
{
22+
title: 'Defining Resources',
23+
collapsable: false,
24+
children: [
25+
'adapters',
26+
'scopes',
27+
'attributes',
28+
'relationships',
29+
'visibility',
30+
'writing',
31+
'filtering',
32+
'sorting',
33+
'pagination',
34+
'meta',
35+
]
36+
},
37+
{
38+
title: 'Endpoints',
39+
collapsable: false,
40+
children: [
41+
'list',
42+
'create',
43+
'update',
44+
'delete',
45+
]
46+
},
47+
{
48+
title: 'Advanced',
49+
collapsable: false,
50+
children: [
51+
'errors',
52+
'laravel',
53+
]
54+
}
55+
],
56+
repo: 'tobyz/json-api-server',
57+
editLinks: true,
58+
docsDir: 'docs'
59+
}
60+
}

docs/.vuepress/styles/index.styl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.theme-default-content > h1 + p {
2+
font-size: 140%;
3+
line-height: 1.5;
4+
}

docs/adapters.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Adapters
2+
3+
Adapters connect your API schema to your application's data persistence layer.
4+
5+
You'll need to supply an adapter for each [resource type](https://jsonapi.org/format/#document-resource-object-identification) you define. You can define resource types using the `resource` method. For example:
6+
7+
```php
8+
use Tobyz\JsonApiServer\Schema\Type;
9+
10+
$api->resource('users', $adapter, function (Type $type) {
11+
// define your schema
12+
});
13+
```
14+
15+
### Eloquent Adapter
16+
17+
An `EloquentAdapter` is provided out of the box to hook your resources up with Laravel [Eloquent](https://laravel.com/docs/8.x/eloquent) models. Instantiate it with the model class that corresponds to your resource.
18+
19+
```php
20+
use App\Models\User;
21+
use Tobyz\JsonApiServer\Adapter\EloquentAdapter;
22+
23+
$adapter = new EloquentAdapter(User::class);
24+
```
25+
26+
When using the Eloquent Adapter, the `$model` passed around in the schema will be an instance of the given model, and the `$query` will be a `Illuminate\Database\Eloquent\Builder` instance querying the model's table:
27+
28+
```php
29+
$type->scope(function (Builder $query) { });
30+
31+
$type->attribute('name')
32+
->get(function (User $user) { });
33+
```
34+
35+
### Custom Adapters
36+
37+
For other ORMs or data persistence layers, you can [implement your own adapter](https://github.com/tobyz/json-api-server/blob/master/src/Adapter/AdapterInterface.php).

docs/attributes.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Attributes
2+
3+
Define an [attribute field](https://jsonapi.org/format/#document-resource-object-attributes) on your resource using the `attribute` method.
4+
5+
```php
6+
$type->attribute('firstName');
7+
```
8+
9+
By default, the attribute will read and write to the property on your model with the same name. (The Eloquent adapter will `snake_case` it automatically for you.) If you'd like it to correspond to a different property, use the `property` method:
10+
11+
```php
12+
$type->attribute('firstName')
13+
->property('fname');
14+
```
15+
16+
## Getters
17+
18+
Use the `get` method to define custom retrieval logic for your attribute, instead of just reading the value straight from the model property.
19+
20+
```php
21+
use Psr\Http\Message\ServerRequestInterface as Request;
22+
use Tobyz\JsonApiServer\Schema\Attribute;
23+
24+
$type->attribute('firstName')
25+
->get(function ($model, Request $request, Attribute $attribute) {
26+
return ucfirst($model->first_name);
27+
});
28+
```
29+
30+
::: tip
31+
If you're using Eloquent, you could also define attribute [casts](https://laravel.com/docs/8.x/eloquent-mutators#attribute-casting) or [accessors](https://laravel.com/docs/8.x/eloquent-mutators#defining-an-accessor) on your model to achieve a similar thing. However, the Request instance will not be available in this context.
32+
:::

docs/create.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Creating Resources
2+
3+
You can allow resources to be [created](https://jsonapi.org/format/#crud-creating) using the `creatable` and `notCreatable` methods on the schema builder.
4+
5+
Optionally pass a closure that returns a boolean value.
6+
7+
```php
8+
$type->creatable();
9+
10+
$type->creatable(function (Request $request) {
11+
return $request->getAttribute('user')->isAdmin();
12+
});
13+
```
14+
15+
## Customizing the Model
16+
17+
When creating a resource, an empty model is supplied by the adapter. You may wish to override this and provide a custom model in special circumstances. You can do so using the `newModel` method:
18+
19+
```php
20+
$type->newModel(function (Request $request) {
21+
return new CustomModel;
22+
});
23+
```
24+
25+
## Events
26+
27+
### `onCreating`
28+
29+
Run before the model is saved.
30+
31+
```php
32+
$type->onCreating(function ($model, Request $request) {
33+
// do something
34+
});
35+
```
36+
37+
### `onCreated`
38+
39+
Run after the model is saved.
40+
41+
```php
42+
$type->onCreated(function ($model, Request $request) {
43+
// do something
44+
});
45+
```

docs/delete.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Deleting Resources
2+
3+
You can allow resources to be [deleted](https://jsonapi.org/format/#crud-deleting) using the `deletable` and `notDeletable` methods on the schema builder.
4+
5+
Optionally pass a closure that returns a boolean value.
6+
7+
```php
8+
$type->deletable();
9+
10+
$type->deletable(function (Request $request) {
11+
return $request->getAttribute('user')->isAdmin();
12+
});
13+
```
14+
15+
## Events
16+
17+
### `onDeleting`
18+
19+
Run before the model is deleted.
20+
21+
```php
22+
$type->onDeleting(function ($model, Request $request) {
23+
// do something
24+
});
25+
```
26+
27+
### `onDeleted`
28+
29+
Run after the model is deleted.
30+
31+
```php
32+
$type->onDeleted(function ($model, Request $request) {
33+
// do something
34+
});
35+
```

docs/errors.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Error Handling
2+
3+
The `JsonApi` class can produce [JSON:API error responses](https://jsonapi.org/format/#errors) from exceptions.
4+
5+
This is achieved by passing the caught exception into the `error` method.
6+
7+
```php
8+
try {
9+
$response = $api->handle($request);
10+
} catch (Exception $e) {
11+
$response = $api->error($e);
12+
}
13+
```
14+
15+
## Error Providers
16+
17+
Exceptions can implement the `ErrorProviderInterface` to determine what status code will be used in the response, and any JSON:API error objects to be rendered in the document.
18+
19+
The interface defines two methods:
20+
21+
* `getJsonApiStatus` which must return a string.
22+
* `getJsonApiErrors` which must return an array of JSON-serializable content, such as [json-api-php](https://github.com/json-api-php/json-api) error objects
23+
24+
```php
25+
use JsonApiPhp\JsonApi\Error;
26+
use Tobyz\JsonApiServer\ErrorProviderInterface;
27+
28+
class ImATeapotException implements ErrorProviderInterface
29+
{
30+
public function getJsonApiErrors(): array
31+
{
32+
return [
33+
new Error(
34+
new Error\Title("I'm a teapot"),
35+
new Error\Status($this->getJsonApiStatus())
36+
)
37+
];
38+
}
39+
40+
public function getJsonApiStatus(): string
41+
{
42+
return '418';
43+
}
44+
}
45+
```
46+
47+
Exceptions that do not implement this interface will result in a generic `500 Internal Server Error` response.

0 commit comments

Comments
 (0)