diff --git a/composer.json b/composer.json index 370dd0e593331071d029fa5fa1cde66c3910bd13..2225274d958238f61d784c3516ca64d5bd6f8850 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,8 @@ "Netmon\\JsonApi\\": "src/", "Netmon\\JsonApi\\Http\\Controllers\\": "src/Http/Controllers/", "Netmon\\JsonApi\\Serializers\\": "src/Serializers/", - "Netmon\\JsonApi\\Traits\\": "src/Traits/" + "Netmon\\JsonApi\\Traits\\": "src/Traits/", + "Netmon\\JsonApi\\Exceptions\\Exceptions": "src/Exceptions/Exceptions/" } }, "require": { diff --git a/resources/schemas/schema b/resources/schemas/schema new file mode 100644 index 0000000000000000000000000000000000000000..7fe78cd5a5c33e4087aaa17547a9636e77d62b22 --- /dev/null +++ b/resources/schemas/schema @@ -0,0 +1,380 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "JSON API Schema", + "description": "This is a schema for responses in the JSON API format. For more, see http://jsonapi.org", + "oneOf": [ + { + "$ref": "file://schema#/definitions/success" + }, + { + "$ref": "file://schema#/definitions/failure" + }, + { + "$ref": "file://schema#/definitions/info" + } + ], + + "definitions": { + "success": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "file://schema#/definitions/data" + }, + "included": { + "description": "To reduce the number of HTTP requests, servers **MAY** allow responses that include related resources along with the requested primary resources. Such responses are called \"compound documents\".", + "type": "array", + "items": { + "$ref": "file://schema#/definitions/resource" + }, + "uniqueItems": true + }, + "meta": { + "$ref": "file://schema#/definitions/meta" + }, + "links": { + "description": "Link members related to the primary data.", + "allOf": [ + { + "$ref": "file://schema#/definitions/links" + }, + { + "$ref": "file://schema#/definitions/pagination" + } + ] + }, + "jsonapi": { + "$ref": "file://schema#/definitions/jsonapi" + } + }, + "additionalProperties": false + }, + "failure": { + "type": "object", + "required": [ + "errors" + ], + "properties": { + "errors": { + "type": "array", + "items": { + "$ref": "file://schema#/definitions/error" + }, + "uniqueItems": true + }, + "meta": { + "$ref": "file://schema#/definitions/meta" + }, + "jsonapi": { + "$ref": "file://schema#/definitions/jsonapi" + } + }, + "additionalProperties": false + }, + "info": { + "type": "object", + "required": [ + "meta" + ], + "properties": { + "meta": { + "$ref": "file://schema#/definitions/meta" + }, + "links": { + "$ref": "file://schema#/definitions/links" + }, + "jsonapi": { + "$ref": "file://schema#/definitions/jsonapi" + } + }, + "additionalProperties": false + }, + + "meta": { + "description": "Non-standard meta-information that can not be represented as an attribute or relationship.", + "type": "object", + "additionalProperties": true + }, + "data": { + "description": "The document's \"primary data\" is a representation of the resource or collection of resources targeted by a request.", + "oneOf": [ + { + "$ref": "file://schema#/definitions/resource" + }, + { + "description": "An array of resource objects, an array of resource identifier objects, or an empty array ([]), for requests that target resource collections.", + "type": "array", + "items": { + "$ref": "file://schema#/definitions/resource" + }, + "uniqueItems": true + } + ] + }, + + "newResource": { + "description": "\"Resource objects\" appear in a JSON API document to represent resources.", + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string" + }, + "id": { + "description": "A server **MAY** accept a client-generated ID along with a request to create a resource. An ID **MUST** be specified with an id key, the value of which **MUST** be a universally unique identifier. The client **SHOULD** use a properly generated and formatted UUID as described in RFC 4122.", + "type": "string" + }, + "attributes": { + "$ref": "file://schema#/definitions/attributes" + }, + "relationships": { + "$ref": "file://schema#/definitions/relationships" + }, + "links": { + "$ref": "file://schema#/definitions/links" + }, + "meta": { + "$ref": "file://schema#/definitions/meta" + } + }, + "additionalProperties": false + }, + "resource": { + "description": "\"Resource objects\" appear in a JSON API document to represent resources.", + "allOf": [ + { + "$ref": "file://schema#/definitions/newResource" + }, + { + "required": [ + "type", + "id" + ] + } + ] + }, + + "links": { + "description": "A resource object **MAY** contain references to other resource objects (\"relationships\"). Relationships may be to-one or to-many. Relationships can be specified by including a member in a resource's links object.", + "type": "object", + "properties": { + "self": { + "description": "A `self` member, whose value is a URL for the relationship itself (a \"relationship URL\"). This URL allows the client to directly manipulate the relationship. For example, it would allow a client to remove an `author` from an `article` without deleting the people resource itself.", + "type": "string", + "format": "uri" + }, + "related": { + "$ref": "file://schema#/definitions/link" + } + }, + "additionalProperties": true + }, + "link": { + "description": "A link **MUST** be represented as either: a string containing the link's URL or a link object.", + "oneOf": [ + { + "description": "A string containing the link's URL.", + "type": "string", + "format": "uri" + }, + { + "type": "object", + "required": [ + "href" + ], + "properties": { + "href": { + "description": "A string containing the link's URL.", + "type": "string", + "format": "uri" + }, + "meta": { + "$ref": "file://schema#/definitions/meta" + } + } + } + ] + }, + + "attributes": { + "description": "Members of the attributes object (\"attributes\") represent information about the resource object in which it's defined.", + "type": "object", + "patternProperties": { + "^(?!relationships$|links$)\\w[-\\w_]*$": { + "description": "Attributes may contain any valid JSON value." + } + }, + "additionalProperties": false + }, + + "relationships": { + "description": "Members of the relationships object (\"relationships\") represent references from the resource object in which it's defined to other resource objects.", + "type": "object", + "patternProperties": { + "^\\w[-\\w_]*$": { + "properties": { + "links": { + "$ref": "file://schema#/definitions/links" + }, + "data": { + "description": "Member, whose value represents \"resource linkage\".", + "oneOf": [ + { + "$ref": "file://schema#/definitions/relationshipToOne" + }, + { + "$ref": "file://schema#/definitions/relationshipToMany" + } + ] + }, + "meta": { + "$ref": "file://schema#/definitions/meta" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "relationshipToOne": { + "description": "References to other resource objects in a to-one (\"relationship\"). Relationships can be specified by including a member in a resource's links object.", + "anyOf": [ + { + "$ref": "file://schema#/definitions/empty" + }, + { + "$ref": "file://schema#/definitions/linkage" + } + ] + }, + "relationshipToMany": { + "description": "An array of objects each containing \"type\" and \"id\" members for to-many relationships.", + "type": "array", + "items": { + "$ref": "file://schema#/definitions/linkage" + }, + "uniqueItems": true + }, + "empty": { + "description": "Describes an empty to-one relationship.", + "type": ["object", "null"], + "properties": {}, + "additionalProperties": false + }, + "linkage": { + "description": "The \"type\" and \"id\" to non-empty members.", + "type": "object", + "required": [ + "type", + "id" + ], + "properties": { + "type": { + "type": "string" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false + }, + "pagination": { + "type": "object", + "properties": { + "first": { + "description": "The first page of data", + "oneOf": [ + { "type": "string", "format": "uri" }, + { "type": "null" } + ] + }, + "last": { + "description": "The last page of data", + "oneOf": [ + { "type": "string", "format": "uri" }, + { "type": "null" } + ] + }, + "prev": { + "description": "The previous page of data", + "oneOf": [ + { "type": "string", "format": "uri" }, + { "type": "null" } + ] + }, + "next": { + "description": "The next page of data", + "oneOf": [ + { "type": "string", "format": "uri" }, + { "type": "null" } + ] + } + } + }, + + "jsonapi": { + "description": "An object describing the server's implementation", + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "meta": { + "$ref": "file://schema#/definitions/meta" + } + }, + "additionalProperties": false + }, + + "error": { + "type": "object", + "properties": { + "id": { + "description": "A unique identifier for this particular occurrence of the problem.", + "type": "string" + }, + "links": { + "$ref": "file://schema#/definitions/links" + }, + "status": { + "description": "The HTTP status code applicable to this problem, expressed as a string value.", + "type": "string" + }, + "code": { + "description": "An application-specific error code, expressed as a string value.", + "type": "string" + }, + "title": { + "description": "A short, human-readable summary of the problem. It **SHOULD NOT** change from occurrence to occurrence of the problem, except for purposes of localization.", + "type": "string" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.", + "type": "string" + }, + "source": { + "type": "object", + "properties": { + "pointer": { + "description": "A JSON Pointer [RFC6901] to the associated entity in the request document [e.g. \"/data\" for a primary data object, or \"/data/attributes/title\" for a specific attribute].", + "type": "string" + }, + "parameter": { + "description": "A string indicating which query parameter caused the error.", + "type": "string" + } + } + }, + "meta": { + "$ref": "file://schema#/definitions/meta" + } + }, + "additionalProperties": false + } + } +} diff --git a/resources/schemas/schema-create b/resources/schemas/schema-create new file mode 100644 index 0000000000000000000000000000000000000000..e2abd787f376b7ad21046b631851401b1a470abf --- /dev/null +++ b/resources/schemas/schema-create @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "JSON API Schema", + "description": "This is a schema for clients creating resources in the JSON API format. For more, see http://jsonapi.org", + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "file://schema-create#/definitions/newData" + }, + "meta": { + "$ref": "file://schema#/definitions/meta" + }, + "jsonapi": { + "$ref": "file://schema#/definitions/jsonapi" + } + }, + "additionalProperties": false, + + "definitions": { + "newData": { + "description": "A resource can be created by sending a `POST` request to a URL that represents a collection of resources. The request **MUST** include a single resource object as primary data.", + "$ref": "file://schema#/definitions/newResource" + } + } +} diff --git a/src/Exceptions/Exceptions/BodyValidationException.php b/src/Exceptions/Exceptions/BodyValidationException.php new file mode 100644 index 0000000000000000000000000000000000000000..52ced6f563beee13a5b7d48b421782e52a546250 --- /dev/null +++ b/src/Exceptions/Exceptions/BodyValidationException.php @@ -0,0 +1,25 @@ +<?php + +namespace Netmon\JsonApi\Exceptions\Exceptions; + +use Exception; +use Illuminate\Support\MessageBag; + +class BodyValidationException extends Exception +{ + protected $code = 400; + protected $validationErrors; + + public function __construct ( + $message = "Request body validation failed.", + MessageBag $validationErrors, + Exception $previous = NULL + ) { + parent::__construct($message, $this->code, $previous); + $this->validationErrors = $validationErrors; + } + + public function getValidationErrors() { + return $this->validationErrors; + } +} diff --git a/src/Http/Controllers/CollectionResourceController.php b/src/Http/Controllers/CollectionResourceController.php index e27da6baa84fa0ac4d3a5f747637bcf4f99742b3..1dc153b8a4392927fcec80df7168656a28e1bca1 100644 --- a/src/Http/Controllers/CollectionResourceController.php +++ b/src/Http/Controllers/CollectionResourceController.php @@ -1,8 +1,8 @@ <?php -namespace Netmon\Server\App\Http\Controllers\JsonApi; +namespace Netmon\JsonApi\Http\Controllers\JsonApi; -use Netmon\Server\App\Traits\CollectionResourceTrait; +use Netmon\JsonApi\Traits\CollectionResourceTrait; abstract class CollectionResourceController extends JsonApiController { diff --git a/src/Http/Controllers/DefaultResourceController.php b/src/Http/Controllers/DefaultResourceController.php index 06f10456b53245680aadc590322ef5370859fb28..a489958eecda92727acf97aec26e89ce207138f3 100644 --- a/src/Http/Controllers/DefaultResourceController.php +++ b/src/Http/Controllers/DefaultResourceController.php @@ -1,9 +1,9 @@ <?php -namespace Netmon\Server\App\Http\Controllers\JsonApi; +namespace Netmon\JsonApi\Http\Controllers\JsonApi; -use Netmon\Server\App\Traits\StoreResourceTrait; -use Netmon\Server\App\Traits\CollectionResourceTrait; +use Netmon\JsonApi\Traits\StoreResourceTrait; +use Netmon\JsonApi\Traits\CollectionResourceTrait; abstract class DefaultResourceController extends JsonApiController { diff --git a/src/Http/Controllers/DocumentResourceController.php b/src/Http/Controllers/DocumentResourceController.php index c005a8949a26873736f61ba178db92febb35ada4..fd16ec9702576a2afed7a50712f149ba4833100b 100644 --- a/src/Http/Controllers/DocumentResourceController.php +++ b/src/Http/Controllers/DocumentResourceController.php @@ -1,8 +1,8 @@ <?php -namespace Netmon\Server\App\Http\Controllers\JsonApi; +namespace Netmon\JsonApi\Http\Controllers\JsonApi; -use Netmon\Server\App\Traits\DocumentResourceTrait; +use Netmon\JsonApi\Traits\DocumentResourceTrait; abstract class DocumentResourceController extends JsonApiController { diff --git a/src/Http/Controllers/JsonApiController.php b/src/Http/Controllers/JsonApiController.php index 389556f0a7ccfe70e5385a1de572c70dad0ff720..67b43673ee94976fee6f9dd43e6b086edd9f7255 100644 --- a/src/Http/Controllers/JsonApiController.php +++ b/src/Http/Controllers/JsonApiController.php @@ -1,6 +1,6 @@ <?php -namespace Netmon\Server\App\Http\Controllers\JsonApi; +namespace Netmon\JsonApi\Http\Controllers\JsonApi; use Illuminate\Routing\Controller; diff --git a/src/Http/Controllers/OneToOneResourceController.php b/src/Http/Controllers/OneToOneResourceController.php index 089f106721c3e5fe6c164c661386b0aadcc00b36..3f8fba3e0dc53364f15d308b45a0db5019de1ea0 100644 --- a/src/Http/Controllers/OneToOneResourceController.php +++ b/src/Http/Controllers/OneToOneResourceController.php @@ -1,8 +1,8 @@ <?php -namespace Netmon\Server\App\Http\Controllers\JsonApi; +namespace Netmon\JsonApi\Http\Controllers\JsonApi; -use Netmon\Server\App\Traits\StoreResourceTrait; +use Netmon\JsonApi\Traits\StoreResourceTrait; abstract class OneToOneResourceController extends JsonApiController { diff --git a/src/Serializers/BasicSerializer.php b/src/Serializers/BasicSerializer.php index a9cfc286bcb6ae7d0665f18190d40f0494924299..178c741080a91de9668ea41635797737e59b2eb4 100644 --- a/src/Serializers/BasicSerializer.php +++ b/src/Serializers/BasicSerializer.php @@ -1,4 +1,4 @@ -<?php namespace Netmon\Server\App\Serializers; +<?php namespace Netmon\JsonApi\Serializers; use Illuminate\Contracts\Container\Container; use DateTime; diff --git a/src/Traits/CollectionResourceTrait.php b/src/Traits/CollectionResourceTrait.php index 76c77f538e0f741a0663081722f4bd5196b41a7d..d011ecbdbc0ae065ba3e81b2f80d147ac4cd122b 100644 --- a/src/Traits/CollectionResourceTrait.php +++ b/src/Traits/CollectionResourceTrait.php @@ -1,6 +1,6 @@ <?php -namespace Netmon\Server\App\Traits; +namespace Netmon\JsonApi\Traits; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; diff --git a/src/Traits/DocumentResourceTrait.php b/src/Traits/DocumentResourceTrait.php index 630316f973d1ee1937d0aeb57a7ee2e2c2eeec1b..ec685ec24cfe47cff22dfbf5efebbd69d73b856e 100644 --- a/src/Traits/DocumentResourceTrait.php +++ b/src/Traits/DocumentResourceTrait.php @@ -1,6 +1,6 @@ <?php -namespace Netmon\Server\App\Traits; +namespace Netmon\JsonApi\Traits; use Gate; diff --git a/src/Traits/StoreResourceTrait.php b/src/Traits/StoreResourceTrait.php index f351c7ed4253a911ce1620ffbfa24f70175c4675..d8f432cba9765293ed0ab47072e9b1d58c171033 100644 --- a/src/Traits/StoreResourceTrait.php +++ b/src/Traits/StoreResourceTrait.php @@ -1,8 +1,8 @@ <?php -namespace Netmon\Server\App\Traits; +namespace Netmon\JsonApi\Traits; -use Netmon\Server\App\Exceptions\Exceptions\BodyValidationException; +use Netmon\JsonApi\Exceptions\Exceptions\BodyValidationException; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; @@ -42,10 +42,10 @@ trait StoreResourceTrait { $requestBody = $request->getContent(); $requestBodyObject = json_decode($requestBody); - $jsonBaseSchema = file_get_contents(resource_path('schemas/schema')); + $jsonBaseSchema = file_get_contents(base_path('vendor/netmon-server/laravel-jsonapi/resources/schemas/schema')); $jsonBaseSchemaObject = json_decode($jsonBaseSchema); - $jsonCreateSchema = file_get_contents(resource_path('schemas/schema-create')); + $jsonCreateSchema = file_get_contents(base_path('vendor/netmon-server/laravel-jsonapi/resources/schemas/schema')); $jsonCreateSchemaObject = json_decode($jsonCreateSchema); // The SchemaStorage can resolve references, loading additional schemas from file as needed, etc.