Setup JSON:API and related routes

This commit is contained in:
Leonard Smith 2020-10-02 18:33:57 -05:00
parent 1df5818f42
commit 9eacb24857
11 changed files with 663 additions and 2 deletions

View File

@ -0,0 +1,54 @@
<?php
namespace App\JsonApi\Books;
use CloudCreativity\LaravelJsonApi\Eloquent\AbstractAdapter;
use CloudCreativity\LaravelJsonApi\Pagination\StandardStrategy;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
class Adapter extends AbstractAdapter
{
/**
* Mapping of JSON API attribute field names to model keys.
*
* @var array
*/
protected $attributes = [];
/**
* Mapping of JSON API filter names to model scopes.
*
* @var array
*/
protected $filterScopes = [];
/**
* Adapter constructor.
*
* @param StandardStrategy $paging
*/
public function __construct(StandardStrategy $paging)
{
parent::__construct(new \App\Book(), $paging);
}
/**
* @param Builder $query
* @param Collection $filters
* @return void
*/
protected function filter($query, Collection $filters)
{
$this->filterWithScopes($query, $filters);
}
/**
* @return \CloudCreativity\LaravelJsonApi\Eloquent\HasMany
*/
protected function chapters()
{
return $this->hasMany();
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace App\JsonApi\Books;
use Neomerx\JsonApi\Schema\SchemaProvider;
class Schema extends SchemaProvider
{
/**
* @var string
*/
protected $resourceType = 'books';
/**
* @param \App\Book $resource
* the domain record being serialized.
* @return string
*/
public function getId($resource)
{
return (string) $resource->getRouteKey();
}
/**
* @param \App\Book $resource
* the domain record being serialized.
* @return array
*/
public function getAttributes($resource)
{
return [
'name' => $resource->name,
'created-at' => $resource->created_at->toAtomString(),
'updated-at' => $resource->updated_at->toAtomString(),
];
}
/**
* @param object $resource
* @param bool $isPrimary
* @param array $includeRelationships
* @return array|\bool[][]
*/
public function getRelationships($resource, $isPrimary, array $includeRelationships)
{
return [
'chapters' => [
self::SHOW_SELF => true,
self::SHOW_RELATED => true,
]
];
}
}

View File

@ -0,0 +1,62 @@
<?php
namespace App\JsonApi\Chapters;
use CloudCreativity\LaravelJsonApi\Eloquent\AbstractAdapter;
use CloudCreativity\LaravelJsonApi\Pagination\StandardStrategy;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
class Adapter extends AbstractAdapter
{
/**
* Mapping of JSON API attribute field names to model keys.
*
* @var array
*/
protected $attributes = [];
/**
* Mapping of JSON API filter names to model scopes.
*
* @var array
*/
protected $filterScopes = [];
/**
* Adapter constructor.
*
* @param StandardStrategy $paging
*/
public function __construct(StandardStrategy $paging)
{
parent::__construct(new \App\Chapter(), $paging);
}
/**
* @param Builder $query
* @param Collection $filters
* @return void
*/
protected function filter($query, Collection $filters)
{
$this->filterWithScopes($query, $filters);
}
/**
* @return \CloudCreativity\LaravelJsonApi\Eloquent\HasMany
*/
protected function verses()
{
return $this->hasMany();
}
/**
* @return \CloudCreativity\LaravelJsonApi\Eloquent\HasOne
*/
protected function book()
{
return $this->hasOne();
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace App\JsonApi\Chapters;
use Neomerx\JsonApi\Schema\SchemaProvider;
class Schema extends SchemaProvider
{
/**
* @var string
*/
protected $resourceType = 'chapters';
/**
* @param \App\Chapter $resource
* the domain record being serialized.
* @return string
*/
public function getId($resource)
{
return (string) $resource->getRouteKey();
}
/**
* @param \App\Chapter $resource
* the domain record being serialized.
* @return array
*/
public function getAttributes($resource)
{
return [
'name' => $resource->name,
'created-at' => $resource->created_at->toAtomString(),
'updated-at' => $resource->updated_at->toAtomString(),
];
}
/**
* @param object $resource
* @param bool $isPrimary
* @param array $includeRelationships
* @return array|\bool[][]
*/
public function getRelationships($resource, $isPrimary, array $includeRelationships)
{
return [
'verses' => [
self::SHOW_SELF => true,
self::SHOW_RELATED => true,
]
];
}
}

View File

@ -0,0 +1,62 @@
<?php
namespace App\JsonApi\Verses;
use CloudCreativity\LaravelJsonApi\Eloquent\AbstractAdapter;
use CloudCreativity\LaravelJsonApi\Pagination\StandardStrategy;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
class Adapter extends AbstractAdapter
{
/**
* Mapping of JSON API attribute field names to model keys.
*
* @var array
*/
protected $attributes = [];
/**
* Mapping of JSON API filter names to model scopes.
*
* @var array
*/
protected $filterScopes = [];
/**
* Adapter constructor.
*
* @param StandardStrategy $paging
*/
public function __construct(StandardStrategy $paging)
{
parent::__construct(new \App\Verse(), $paging);
}
/**
* @param Builder $query
* @param Collection $filters
* @return void
*/
protected function filter($query, Collection $filters)
{
$this->filterWithScopes($query, $filters);
}
/**
* @return \CloudCreativity\LaravelJsonApi\Eloquent\HasMany
*/
protected function verses()
{
return $this->hasMany();
}
/**
* @return \CloudCreativity\LaravelJsonApi\Eloquent\HasOne
*/
protected function chapter()
{
return $this->hasOne();
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace App\JsonApi\Verses;
use Neomerx\JsonApi\Schema\SchemaProvider;
class Schema extends SchemaProvider
{
/**
* @var string
*/
protected $resourceType = 'verses';
/**
* @param \App\Verse $resource
* the domain record being serialized.
* @return string
*/
public function getId($resource)
{
return (string) $resource->getRouteKey();
}
/**
* @param \App\Verse $resource
* the domain record being serialized.
* @return array
*/
public function getAttributes($resource)
{
return [
'name' => $resource->name,
'ulb_text' => $resource->ulb_text,
'greek_text' => $resource->greek_text,
'created-at' => $resource->created_at->toAtomString(),
'updated-at' => $resource->updated_at->toAtomString(),
];
}
/**
* @param object $resource
* @param bool $isPrimary
* @param array $includeRelationships
* @return array|\bool[][]
*/
public function getRelationships($resource, $isPrimary, array $includeRelationships)
{
return [
'words' => [
self::SHOW_SELF => true,
self::SHOW_RELATED => true,
]
];
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace App\JsonApi\Words;
use CloudCreativity\LaravelJsonApi\Eloquent\AbstractAdapter;
use CloudCreativity\LaravelJsonApi\Pagination\StandardStrategy;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
class Adapter extends AbstractAdapter
{
/**
* Mapping of JSON API attribute field names to model keys.
*
* @var array
*/
protected $attributes = [];
/**
* Mapping of JSON API filter names to model scopes.
*
* @var array
*/
protected $filterScopes = [];
/**
* Adapter constructor.
*
* @param StandardStrategy $paging
*/
public function __construct(StandardStrategy $paging)
{
parent::__construct(new \App\Word(), $paging);
}
/**
* @param Builder $query
* @param Collection $filters
* @return void
*/
protected function filter($query, Collection $filters)
{
$this->filterWithScopes($query, $filters);
}
/**
* @return \CloudCreativity\LaravelJsonApi\Eloquent\HasOne
*/
protected function verse()
{
return $this->hasOne();
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace App\JsonApi\Words;
use Neomerx\JsonApi\Schema\SchemaProvider;
class Schema extends SchemaProvider
{
/**
* @var string
*/
protected $resourceType = 'words';
/**
* @param \App\Word $resource
* the domain record being serialized.
* @return string
*/
public function getId($resource)
{
return (string) $resource->getRouteKey();
}
/**
* @param \App\Word $resource
* the domain record being serialized.
* @return array
*/
public function getAttributes($resource)
{
return [
'ulb' => $resource->ulb,
'greek' => $resource->greek,
'lemma' => $resource->lemma,
'morph' => $resource->morph,
'ognt_sort' => $resource->ognt_sort,
'strongs_number' => $resource->strongs_number,
'created-at' => $resource->created_at->toAtomString(),
'updated-at' => $resource->updated_at->toAtomString(),
];
}
}

View File

@ -72,8 +72,7 @@ class RouteServiceProvider extends ServiceProvider
*/
protected function mapApiRoutes()
{
Route::prefix('api')
->middleware('api')
Route::middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
}

207
config/json-api-default.php Normal file
View File

@ -0,0 +1,207 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Resolver
|--------------------------------------------------------------------------
|
| The API's resolver is the class that works out the fully qualified
| class name of adapters, schemas, authorizers and validators for your
| resource types. We recommend using our default implementation but you
| can override it here if desired.
*/
'resolver' => \CloudCreativity\LaravelJsonApi\Resolver\ResolverFactory::class,
/*
|--------------------------------------------------------------------------
| Root Namespace
|--------------------------------------------------------------------------
|
| The root namespace for JSON API classes for this API. If `null`, the
| namespace will default to `JsonApi` within your application's root
| namespace (obtained via Laravel's `Application::getNamespace()`
| method).
|
| The `by-resource` setting determines how your units are organised within
| your root namespace.
|
| - true:
| - e.g. App\JsonApi\Posts\{Adapter, Schema, Validators}
| - e.g. App\JsonApi\Comments\{Adapter, Schema, Validators}
| - false:
| - e.g. App\JsonApi\Adapters\PostAdapter, CommentAdapter}
| - e.g. App\JsonApi\Schemas\{PostSchema, CommentSchema}
| - e.g. App\JsonApi\Validators\{PostValidator, CommentValidator}
|
*/
'namespace' => null,
'by-resource' => true,
/*
|--------------------------------------------------------------------------
| Model Namespace
|--------------------------------------------------------------------------
|
| Here you can decide where your api models live.
| By default (i.e. set to null), the package assumes they will live in
| your application's root namespace, but you could set it to something
| different here. E.g. `App\Models`.
|
*/
'model-namespace' => null,
/*
|--------------------------------------------------------------------------
| Resources
|--------------------------------------------------------------------------
|
| Here you map the list of JSON API resources in your API to the actual
| record (model/entity) classes they relate to.
|
| For example, if you had a `posts` JSON API resource, that related to
| an Eloquent model `App\Post`, your mapping would be:
|
| `'posts' => App\Post::class`
*/
'resources' => [
'books' => \App\Book::class,
'chapters' => \App\Chapter::class,
'verses' => \App\Verse::class,
'words' => \App\Word::class,
],
/*
|--------------------------------------------------------------------------
| Eloquent
|--------------------------------------------------------------------------
|
| Whether your JSON API resources predominantly relate to Eloquent models.
| This is used by the package's generators.
|
| You can override the setting here when running a generator. If the
| setting here is `true` running a generator with `--no-eloquent` will
| override it; if the setting is `false`, then `--eloquent` is the override.
|
*/
'use-eloquent' => true,
/*
|--------------------------------------------------------------------------
| URL
|--------------------------------------------------------------------------
|
| The API's url, made up of a host, URL namespace and route name prefix.
|
| If a JSON API is handling an inbound request, the host will always be
| detected from the inbound HTTP request. In other circumstances
| (e.g. broadcasting), the host will be taken from the setting here.
| If it is `null`, the `app.url` config setting is used as the default.
| If you set `host` to `false`, the host will never be appended to URLs
| for inbound requests.
|
| The name setting is the prefix for route names within this API.
|
*/
'url' => [
'host' => null,
'namespace' => '/api/v1',
'name' => 'api:v1:',
],
/*
|--------------------------------------------------------------------------
| Controllers
|--------------------------------------------------------------------------
|
| The default JSON API controller wraps write operations in transactions.
| You can customise the connection for the transaction here. Or if you
| want to turn transactions off, set `transactions` to `false`.
|
*/
'controllers' => [
'transactions' => true,
'connection' => null,
],
/*
|--------------------------------------------------------------------------
| Jobs
|--------------------------------------------------------------------------
|
| Defines settings for the asynchronous processing feature. We recommend
| referring to the documentation on asynchronous processing if you are
| using this feature.
|
| Note that if you use a different model class, it must implement the
| asynchronous process interface.
|
*/
'jobs' => [
'resource' => 'queue-jobs',
'model' => \CloudCreativity\LaravelJsonApi\Queue\ClientJob::class,
],
/*
|--------------------------------------------------------------------------
| Encoding Media Types
|--------------------------------------------------------------------------
|
| This defines the JSON API encoding used for particular media
| types supported by your API. This array can contain either
| media types as values, or can be keyed by a media type with the value
| being the options that are passed to the `json_encode` method.
|
| These values are also used for Content Negotiation. If a client requests
| via the HTTP Accept header a media type that is not listed here,
| a 406 Not Acceptable response will be sent.
|
| If you want to support media types that do not return responses with JSON
| API encoded data, you can do this at runtime. Refer to the
| Content Negotiation chapter in the docs for details.
|
*/
'encoding' => [
'application/vnd.api+json',
],
/*
|--------------------------------------------------------------------------
| Decoding Media Types
|--------------------------------------------------------------------------
|
| This defines the media types that your API can receive from clients.
| This array is keyed by expected media types, with the value being the
| service binding that decodes the media type.
|
| These values are also used for Content Negotiation. If a client sends
| a content type not listed here, it will receive a
| 415 Unsupported Media Type response.
|
| Decoders can also be calculated at runtime, and/or you can add support
| for media types for specific resources or requests. Refer to the
| Content Negotiation chapter in the docs for details.
|
*/
'decoding' => [
'application/vnd.api+json',
],
/*
|--------------------------------------------------------------------------
| Providers
|--------------------------------------------------------------------------
|
| Providers allow vendor packages to include resources in your API. E.g.
| a Shopping Cart vendor package might define the `orders` and `payments`
| JSON API resources.
|
| A package author will define a provider class in their package that you
| can add here. E.g. for our shopping cart example, the provider could be
| `Vendor\ShoppingCart\JsonApi\ResourceProvider`.
|
*/
'providers' => [],
];

View File

@ -17,3 +17,19 @@ use Illuminate\Support\Facades\Route;
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
JsonApi::register('default')->routes(function ($api) {
$api->resource('books')->readOnly()->relationships(function ($relations) {
$relations->hasMany('chapters')->readOnly();
});
$api->resource('chapters')->readOnly()->relationships(function ($relations) {
$relations->hasMany('verses')->readOnly();
});
$api->resource('verses')->readOnly()->relationships(function ($relations) {
$relations->hasMany('words')->readOnly();
});
$api->resource('words')->readOnly();
});