larsmbergvall/json-api-resources-for-laravel

为Laravel提供的简单JSON:API资源包

0.3.0 2023-03-17 07:26 UTC

README

目录

示例

这是此包生成的输出示例

    public function books()
    {
        $books = Book::with(['author.country'])->take(2)->get();

        return JsonApiResourceCollection::make($books)->withIncluded();
    }

返回此内容

{
  "data": [
    {
      "id": "1",
      "type": "books",
      "attributes": {
        "title": "Dolores Dolor Totam",
        "year": 1871
      },
      "relationships": {
        "author": {
          "data": {
            "id": "1",
            "type": "author"
          }
        }
      },
      "links": {},
      "meta": {}
    },
    {
      "id": "2",
      "type": "books",
      "attributes": {
        "title": "Velit Quo Omnis",
        "year": 1969
      },
      "relationships": {
        "author": {
          "data": {
            "id": "2",
            "type": "author"
          }
        }
      },
      "links": {},
      "meta": {}
    }
  ],
  "included": [
    {
      "id": "1",
      "type": "author",
      "attributes": {
        "name": "Rylee Heller DDS",
        "country_id": 18,
        "bio": "Non iusto porro maxime. Quibusdam provident architecto magni sed id et. Voluptatem sint a numquam eius omnis aut.\n\nVoluptas quis voluptatem et fuga aspernatur eaque. Necessitatibus possimus iure corporis et quasi cum. Blanditiis quis sapiente ut dolores. Dolorem odio et quas aut et nihil qui.\n\nAut quod sint numquam. Ullam id odio velit neque non. Aut recusandae sint explicabo ut veritatis aliquid harum.",
        "born_at": "1986-10-22 08:00:02",
        "created_at": "2023-03-09 12:55:20",
        "updated_at": "2023-03-09 12:55:20"
      },
      "relationships": {},
      "links": {},
      "meta": {}
    },
    {
      "id": "2",
      "type": "author",
      "attributes": {
        "name": "Ms. Rosella Quigley Sr.",
        "country_id": 12,
        "bio": "Architecto voluptas nobis sed. Ea qui quas voluptatem est nisi. Voluptatem et quis ut asperiores fuga autem blanditiis repellendus. Qui non sapiente esse quasi corporis fugit ut aut.\n\nDolorem id dolore quis qui ullam dolorem. Qui voluptatibus quia reprehenderit dolor aut est corrupti. Debitis debitis cum vitae nam quis fugit nemo. Quia labore et delectus est qui.\n\nNumquam accusantium et in. Non tenetur iure explicabo expedita sint. Quam sit qui doloremque asperiores ducimus impedit enim. In recusandae et cumque nisi ea laudantium in.",
        "born_at": "1996-08-07 13:15:36",
        "created_at": "2023-03-09 12:55:20",
        "updated_at": "2023-03-09 12:55:20"
      },
      "relationships": {},
      "links": {},
      "meta": {}
    }
  ]
}

安装

您可以通过composer安装此包

composer require larsmbergvall/json-api-resources-for-laravel

建议您使用中间件,要么对所有API调用

// ./app/Http/Kernel.php

protected $middlewareGroups = [
    // ...
    // Web middleware and such
    // ...
    'api' => [
        // Other api middlewares
        JsonApiMiddleware::class,
    ],
]

或者,基于每个路由

// ./routes/api.php

Route::prefix('/v1')
    ->middleware(JsonApiMiddleware::class)
    ->group(function () {
        // Api v1 routes
    });

使用

属性

此包使用PHP 8属性来注释Eloquent模型。不需要额外的资源类。属性的使用方式如下

use Larsmbergvall\JsonApiResourcesForLaravel\Attributes\JsonApiIncludeAttributes;
use Larsmbergvall\JsonApiResourcesForLaravel\Attributes\JsonApiIncludeRelationships;
use Larsmbergvall\JsonApiResourcesForLaravel\Attributes\JsonApiType;

#[JsonApiType('books')] // Change `type` property
#[JsonApiIncludeAttributes(['title', 'isbn', 'year'])] // Which of the models attributes to include
 // Which of the models relationships to include.
 // NOTE: it only includes eager loaded relationships regardless of this attribute
#[JsonApiIncludeRelationships(['author'])]
class Book extends Model
{
    // ...
}

#[JsonApiType(string)]

此属性可以用来更改最终输出JSON中的type属性的值。此属性是可选的。如果没有使用,则将type设置为模型名称的单数形式,即'type' => 'book'

#[JsonApiIncludeAttributes(string[])]

此属性可以用来指定哪些模型属性应该包含在最终的输出JSON中。此属性是可选的。如果没有使用,则将包含所有可见的模型属性。它使用$model->attributesToArray()来获取属性,因此将尊重任何$hidden字段。

#[JsonApiIncludeRelationships(string[])]

此属性可以用来指定哪些模型关系应该包含在内。此属性是可选的。如果没有使用,则不会在最终的输出JSON中包含任何关系。

注意:无论此属性包含什么,JsonApiResource只包含懒加载的关系。

创建JsonApiResources

如果您有一个单个模型,应使用JsonApiResource

use Larsmbergvall\JsonApiResourcesForLaravel\JsonApi\JsonApiResource;

public function show(Book $book): JsonApiResource
{
    return JsonApiResource::make($book);
}

如果您有一组模型,应使用JsonApiResourceCollection

use Larsmbergvall\JsonApiResourcesForLaravel\JsonApi\JsonApiResourceCollection;

public function index(): JsonApiResource
{
    // Can also be used with pagination:
    // return JsonApiResourceCollection::make(Book::orderBy('title')->paginate());
    
    return JsonApiResourceCollection::make(Book::all());
}

如果您需要手动返回JSON:API响应,或者不想使用中间件,可以使用jsonApiResponse()辅助函数

// return jsonApiResponse(JsonApiResource::make($book));
return jsonApiResponse($content, $status, $headers)

它设置了JSON:API响应的正确Content-Type头。请注意,它不会转换验证错误。

中间件

中间件主要处理两件事

  1. 确保返回的响应具有正确的头等。
  2. 将Laravel的验证错误转换为预期的JSON:API错误格式

中间件应该在可能更改响应的Content-Type头的其他中间件之后执行。

JsonApiResource类

此类有几个公开方法,您可以使用。您很可能不需要这样做,因为JsonApiResourceCollection类会自动处理这些。

但是,有一个重要的方法:withIncluded()。默认情况下,JsonApiResource不包含相关数据。但是,如果您运行$resource->withIncluded()(或JsonApiResource::make($book)->withIncluded()),它就会这样做。

注意:它只包含懒加载的关系,因此如果您需要为某个API路由排除某些内容,只需选择不加载关系即可。但是,它会递归地包含相关数据,这意味着它还会包含包含数据的关联数据。

JsonApiResourceCollection类

该类还包含一个withIncluded()方法,您可以使用它将任何相关数据包含到资源中。与JsonApiResource一样,它仅包含已加载的关联关系。然而,它会递归地包含相关数据,这意味着它还会包含与包含数据相关的数据。

错误转换

当Laravel中的验证失败时,通常您会得到如下所示的响应

{
  "message": "The data.attributes.foo field is required.",
  "errors": {
    "data.attributes.foo": [
      "The data.attributes.foo field is required."
    ]
  }
}

但是,使用JsonApiMiddleware后,此响应将变为

{
  "errors": [
    {
      "status": "422",
      "title": "Unprocessable Content",
      "detail": "The data.attributes.foo field is required.",
      "source": {
        "pointer": "data/attributes/foo",
        "parameter": "foo"
      }
    }
  ]
}

测试

JsonApiResourceJsonApiResourceCollection类中提供了一些测试工具,您可以使用它们来测试您的应用程序。

注意,未来版本还将提供更多测试工具!

assertHasData

$author = Author::factory()->create();
$resource = JsonApiResource::make($author);

$id = $author->id;
$type = 'author';
$resource->assertHasData($id, $type);

assertDoesntHaveData

$author = Author::factory()->create();
$resource = JsonApiResourceCollection::make(collect([$author]));

$id = $author->id + 999;
$type = 'author';
$resource->assertDoesntHave($id, $type);

这是assertHasData的相反。如果它找到了预期的数据,则会失败。

变更日志

请参阅变更日志以获取有关最近更改的更多信息。

致谢

许可

MIT许可证(MIT)。有关更多信息,请参阅许可证文件