帮酷LOGO
  • 显示原文与译文双语对照的内容
文章标签:Laravel  PACK  Transformer  Laravel 5  API  Json Api  PAC  
Laravel 5 JSON API Transformer Package

  • 源代码名称:laravel5-jsonapi
  • 源代码网址:http://www.github.com/nilportugues/laravel5-jsonapi
  • laravel5-jsonapi源代码文档
  • laravel5-jsonapi源代码下载
  • Git URL:
    git://www.github.com/nilportugues/laravel5-jsonapi.git
  • Git Clone代码到本地:
    git clone http://www.github.com/nilportugues/laravel5-jsonapi
  • Subversion代码到本地:
    $ svn co --depth empty http://www.github.com/nilportugues/laravel5-jsonapi
    Checked out revision 1.
    $ cd repo
    $ svn up trunk
  • Laravel 5 JSON API服务器包

    Scrutinizer Code QualitySensioLabsInsightLatest Stable VersionTotal DownloadsLicenseDonate

    兼容于 Laravel 5.0,5.1 & 5.2

    安装

    使用 Composer插件安装软件包:

    composer require nilportugues/laravel5-json-api

    现在运行以下工匠命令:

    php artisan vendor:publish

    配置( Laravel 5 &流明)

    为了 Having的真实生活示例,这个配置将指导你如何为两个资源( EmployeesOrders ) 为两个资源设置端点。

    EmployeesOrders 资源都是 Eloquent的模型,与其他资源相关。

    这里外,Employees 将使用一个有力的特性,appended fields 演示如何将最大的功能和这个包组合在一起。

    Laravel 5的配置

    步骤 1: 添加服务提供程序

    打开 config/app.php 并在 providers array 下添加以下行:

    'providers'=> [//...NilPortuguesLaravel5JsonApiLaravel5JsonApiServiceProvider::class,],
    步骤 2: 定义路由

    我们将在它的实现前规划资源。 所有路由都需要有名称。

    这是我们的app/Http/routes.php的外观:

    <?phpRoute::group(['namespace'=>'Api'], function() {Route::resource('employees', 'EmployeesController'); Route::get('employees/{employee_id}/orders', ['as'=>'employees.orders','uses'=>'EmployeesController@getOrdersByEmployee' ]);});//...
    步骤 3: 定义

    首先,让我们使用Eloquent来定义 EmployeesOrders的模型。

    雇员( Eloquent模型)

    <?phpnamespaceAppModelDatabase;useIlluminateDatabaseEloquentModel;useIlluminateFoundationValidationValidatesRequests;classEmployeesextendsModel{public$timestamps=false;protected$table='employees'; protected$primaryKey='id';protected$appends= ['full_name'];/** * @return IlluminateDatabaseEloquentRelationsHasOne*/publicfunctionlatestOrders() {return$this->hasMany(Orders::class, 'employee_id')->limit(10); }/** * @return string*/publicfunctiongetFullNameAttribute() {return$this->first_name.''.$this->last_name; }}

    雇员 SQL

    CREATETABLE `employees` (
     `id`int(11) NOT NULL AUTO_INCREMENT,
     `company`varchar(50) DEFAULT NULL,
     `last_name`varchar(50) DEFAULT NULL,
     `first_name`varchar(50) DEFAULT NULL,
     `email_address`varchar(50) DEFAULT NULL,
     `job_title`varchar(50) DEFAULT NULL,
     `business_phone`varchar(25) DEFAULT NULL,
     `home_phone`varchar(25) DEFAULT NULL,
     `mobile_phone`varchar(25) DEFAULT NULL,
     `fax_number`varchar(25) DEFAULT NULL,
     `address` longtext,
     `city`varchar(50) DEFAULT NULL,
     `state_province`varchar(50) DEFAULT NULL,
     `zip_postal_code`varchar(15) DEFAULT NULL,
     `country_region`varchar(50) DEFAULT NULL,
     `web_page` longtext,
     `notes` longtext,
     `attachments` longblob,
     PRIMARY KEY (`id`),
     KEY `city` (`city`),
     KEY `company` (`company`),
     KEY `first_name` (`first_name`),
     KEY `last_name` (`last_name`),
     KEY `zip_postal_code` (`zip_postal_code`),
     KEY `state_province` (`state_province`)
    ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;INSERT INTO`employees` (`id`, `company`, `last_name`, `first_name`, `email_address`, `job_title`, `business_phone`, `home_phone`, `mobile_phone`, `fax_number`, `address`, `city`, `state_province`, `zip_postal_code`, `country_region`, `web_page`, `notes`, `attachments`)VALUES (10, 'Acme Industries', 'Smith', 'Mike', 'mike.smith@mail.com', 'Horticultarlist', '0118 9843212', NULL, NULL, NULL, '343 Friary Road', 'Manchester', 'Lancs.', 'M3 3DL', 'United Kingdom', NULL, NULL, NULL);

    订单( Eloquent模型)

    <?phpnamespaceAppModelDatabase;useIlluminateDatabaseEloquentModel;classOrdersextendsModel{ public$timestamps=false;protected$table='orders';protected$primaryKey='id';/** * @return IlluminateDatabaseEloquentRelationsHasOne*/publicfunctionemployee() {return$this->belongsTo(Employees::class, 'employee_id'); }}

    订单 SQL

    CREATETABLE `orders` (
     `id`int(11) NOT NULL AUTO_INCREMENT,
     `employee_id`int(11) DEFAULT NULL,
     `customer_id`int(11) DEFAULT NULL,
     `order_date` datetime DEFAULT NULL,
     `shipped_date` datetime DEFAULT NULL,
     `shipper_id`int(11) DEFAULT NULL,
     `ship_name`varchar(50) DEFAULT NULL,
     `ship_address` longtext,
     `ship_city`varchar(50) DEFAULT NULL,
     `ship_state_province`varchar(50) DEFAULT NULL,
     `ship_zip_postal_code`varchar(50) DEFAULT NULL,
     `ship_country_region`varchar(50) DEFAULT NULL,
     `shipping_fee`decimal(19,4) DEFAULT '0.0000',
     `taxes`decimal(19,4) DEFAULT '0.0000',
     `payment_type`varchar(50) DEFAULT NULL,
     `paid_date` datetime DEFAULT NULL,
     `notes` longtext,
     `tax_rate` double DEFAULT '0',
     `tax_status_id`tinyint(4) DEFAULT NULL,
     `status_id`tinyint(4) DEFAULT '0',
     PRIMARY KEY (`id`),
     KEY `customer_id` (`customer_id`),
     KEY `employee_id` (`employee_id`),
     KEY `id` (`id`),
     KEY `shipper_id` (`shipper_id`),
     KEY `tax_status` (`tax_status_id`),
     KEY `ship_zip_postal_code` (`ship_zip_postal_code`),
     KEY `fk_orders_orders_status1` (`status_id`), 
     CONSTRAINT`fk_orders_employees1`FOREIGN KEY (`employee_id`) REFERENCES`employees` (`id`) ON DELETE NO ACTION ONUPDATE NO ACTION
    ) ENGINE=InnoDB AUTO_INCREMENT=82 DEFAULT CHARSET=utf8;INSERT INTO`orders` (`id`, `employee_id`, `customer_id`, `order_date`, `shipped_date`, `shipper_id`, `ship_name`, `ship_address`, `ship_city`, `ship_state_province`, `ship_zip_postal_code`, `ship_country_region`, `shipping_fee`, `taxes`, `payment_type`, `paid_date`, `notes`, `tax_rate`, `tax_status_id`, `status_id`)VALUES (82, 10, NULL, '2015-03-12 00:00:00', '2015-03-12 00:00:00', NULL, NULL, '43, Borrowed Drive', 'New Oreleans', 'Louisiana', '4322', 'USA', 1.4000, 0.0000, NULL, NULL, NULL, 0, NULL, 0);

    接下来,我们将创建变压器。 每个类都需要一个转换器,并且它必须实现 NilPortuguesApiMappingsJsonApiMapping 接口。

    我们将把这些文件放在 app/Model/Api 上:

    EmployeesTransformer

    <?phpnamespaceAppModelApi;useAppModelDatabaseEmployees;useNilPortuguesApiMappingsJsonApiMapping;classEmployeesTransformerimplementsJsonApiMapping{/** * Returns a string with the full class name, including namespace. * * @return string*/publicfunctiongetClass() {returnEmployees::class; }/** * Returns a string representing the resource name  * as it will be shown after the mapping. * * @return string*/publicfunctiongetAlias() {return'employee'; }/** * Returns an array of properties that will be renamed. * Key is current property from the class.  * Value is the property's alias name. * * @return array*/publicfunctiongetAliasedProperties() {return ['last_name'=>'surname', ]; }/** * List of properties in the class that will be ignored by the mapping. * * @return array*/publicfunctiongetHideProperties() {return ['attachments' ]; }/** * Returns an array of properties that are used as an ID value. * * @return array*/publicfunctiongetIdProperties() {return ['id']; }/** * Returns a list of URLs. This urls must have placeholders  * to be replaced with the getIdProperties() values. * * @return array*/publicfunctiongetUrls() {return ['self'=> ['name'=>'employees.show', 'as_id'=>'id'],'employees'=> ['name'=>'employees.index'],'employee_orders'=> ['name'=>'employees.orders', 'as_id'=>'id'] ]; }/** * Returns an array containing the relationship mappings as an array. * Key for each relationship defined must match a property of the mapped class. * * @return array*/publicfunctiongetRelationships() {return []; }} 

    Orders 也一样,这些文件也将放在 app/Model/Api 中:

    OrdersTransformer

    <?phpnamespaceAppModelApi;useAppModelDatabaseOrders;useNilPortuguesApiMappingsJsonApiMapping;classOrdersTransformerimplementsJsonApiMapping{/** * {@inheritDoc}*/publicfunctiongetClass() {returnOrders::class; }/** * {@inheritDoc}*/publicfunctiongetAlias() {return'order'; }/** * {@inheritDoc}*/publicfunctiongetAliasedProperties() {return []; }/** * {@inheritDoc}*/publicfunctiongetHideProperties() {return []; }/** * {@inheritDoc}*/publicfunctiongetIdProperties() {return ['id']; }/** * {@inheritDoc}*/publicfunctiongetUrls() {return ['self'=> ['name'=>'orders.show', 'as_id'=>'id'],'employee'=> ['name'=>'employees.show', 'as_id'=>'employee_id'], ]; }/** * {@inheritDoc}*/publicfunctiongetRelationships() {return []; }/** * List the fields that are mandatory in a persitence action (POST/PUT).  * If empty array is returned, all fields are mandatory.*/publicfunctiongetRequiredProperties() {return []; } } 
    步骤 4: 用法

    创建文件 config/jsonapi.php 。该文件应返回返回所有类映射的array 。

    <?phpuseAppModelApiEmployeesTransformer;useAppModelApiOrdersTransformer;return [EmployeesTransformer::class,OrdersTransformer::class,];

    的流明配置

    步骤 1: 添加服务提供程序

    打开 bootstrap/app.php 并在 return $app; 语句之前添加以下行:

    $app->register(NilPortuguesLaravel5JsonApiLaravel5JsonApiServiceProvider::class);$app->configure('jsonapi');

    另外,通过取消注释启用立面:

    $app->withFacades();
    步骤 2: 定义路由

    我们将在它的实现前规划资源。 所有路由都需要有名称。

    这是我们的app/Http/routes.php的外观:

    <?php$app->group( ['namespace'=>'Api'], function($app) {$app->get('employees', ['as'=>'employees.index','uses'=>'EmployeesController@index' ]);$app->post('employees', ['as'=>'employees.store','uses'=>'EmployeesController@store' ]);$app->get('employees/{employee_id}', ['as'=>'employees.show', 'uses'=>'EmployeesController@show' ]);$app->put('employees/{employee_id}', ['as'=>'employees.update', 'uses'=>'EmployeesController@update' ]);$app->patch('employees/{employee_id}', ['as'=>'employees.patch','uses'=>'EmployeesController@update' ]);$app->delete('employees/{employee_id}', ['as'=>'employees.destroy','uses'=>'EmployeesController@destroy' ]);$app->get('employees/{employee_id}/orders', ['as'=>'employees.orders', 'uses'=>'EmployeesController@getOrdersByEmployee' ]); });//...
    步骤 3: 定义

    Laravel 5相同。

    步骤 4: 用法

    Laravel 5相同。

    JsonApiController

    无论是 Laravel 5还是流明,用法都是一样的。

    让我们创建一个扩展这里软件包提供的JsonApiController的新控制器,如下所示:

    流明用户必须从 LumenJsonApiController 扩展到 JsonApiController

    <?phpnamespaceAppHttpControllers;useAppModelDatabaseEmployees;useNilPortuguesLaravel5JsonApiControllerJsonApiController;classEmployeesControllerextendsJsonApiController{/** * Return the Eloquent model that will be used  * to model the JSON API resources.  * * @return IlluminateDatabaseEloquentModel*/publicfunctiongetDataModel() {returnnewEmployees(); }}

    如果你需要覆盖任何默认行为,则 JsonApiController 方法为:

    //Constructor and defined actionspublicfunction__construct(JsonApiSerializer$serializer);publicfunctionlistAction();publicfunctiongetAction(Request$request);publicfunctionpostAction(Request$request);publicfunctionpatchAction(Request$request);publicfunctionputAction(Request$request);publicfunctiondeleteAction(Request$request);//Methods returning callables that access the persistence layerprotectedfunctiontotalAmountResourceCallable();protectedfunctionlistResourceCallable();protectedfunctionfindResourceCallable(Request$request);protectedfunctioncreateResourceCallable();protectedfunctionupdateResourceCallable();//Allows modification of the response objectprotectedfunctionaddHeaders(Response$response);

    但是等等我们漏掉了一个动作 ! EmployeesController@getOrdersByEmployee

    正如 NAME 所建议的,它应该列出订单,所以行为应该与 ListAction 之一相同。

    查看 ListAction 内部的代码,可以找到类似下面的代码,但我们只是ajusted行为并在控制器中使用它来支持附加操作:

    <?phpnamespaceAppHttpControllers;useAppModelDatabaseEmployees;useAppModelDatabaseOrders;useNilPortuguesLaravel5JsonApiControllerJsonApiController;classEmployeesControllerextendsJsonApiController{/** * Return the Eloquent model that will be used  * to model the JSON API resources.  * * @return IlluminateDatabaseEloquentModel*/publicfunctiongetDataModel() {returnnewEmployees(); } /** * @param Request $request * * @return SymfonyComponentHttpFoundationResponse*/publicfunctiongetOrdersByEmployee(Request$request) { $apiRequest=RequestFactory::create();$page=$apiRequest->getPage();if (!$page->size()) {$page->setSize(10); //Default elements per page }$resource=newListResource($this->serializer,$page,$apiRequest->getFields(),$apiRequest->getSort(),$apiRequest->getIncludedRelationships(),$apiRequest->getFilters() );$totalAmount=function() use ($request) {$id= (newOrders())->getKeyName();returnOrders::query()->where('employee_id', '=', $request->employee_id)->get([$id])->count(); };$results=function() use ($request) {returnEloquentHelper::paginate($this->serializer,Orders::query()->where('employee_id', '=', $request->employee_id) )->get(); };$uri= route('employees.orders', ['employee_id'=>$request->employee_id]);return$resource->get($totalAmount, $results, $uri, Orders::class); }}

    你已经准备好了。 是的,simple !

    示例:使用 API

    这是使用命令行方法发出的EmployeesController@getAction的输出: curl -X GET"http://localhost:9000/employees/1"

    输出:

    HTTP/1.1 200 OK
    Cache-Control: private, max-age=0, must-revalidate
    Content-type: application/vnd.api+json
    {
     "data": {
     "type": "employee",
     "id": "1",
     "attributes": {
     "company": "Northwind Traders",
     "surname": "Freehafer",
     "first_name": "Nancy",
     "email_address": "nancy@northwindtraders.com",
     "job_title": "Sales Representative",
     "business_phone": "(123)555-0100",
     "home_phone": "(123)555-0102",
     "mobile_phone": null,
     "fax_number": "(123)555-0103",
     "address": "123 1st Avenue",
     "city": "Seattle",
     "state_province": "WA",
     "zip_postal_code": "99999",
     "country_region": "USA",
     "web_page": "http://northwindtraders.com",
     "notes": null,
     "full_name": "Nancy Freehafer" },
     "links": {
     "self": {
     "href": "http://localhost:9000/employees/1" },
     "employee_orders": {
     "href": "http://localhost:9000/employees/1/orders" }
     },
     "relationships": {
     "latest_orders": [
     {
     "data": {
     "type": "order",
     "id": "71" }
     }
     ]
     }
     },
     "included": [ 
     {
     "type": "order",
     "id": "71",
     "attributes": {
     "employee_id": "1",
     "customer_id": "1",
     "order_date": "2006-05-24 00:00:00",
     "shipped_date": null,
     "shipper_id": "3",
     "ship_name": "Anna Bedecs",
     "ship_address": "123 1st Street",
     "ship_city": "Seattle",
     "ship_state_province": "WA",
     "ship_zip_postal_code": "99999",
     "ship_country_region": "USA",
     "shipping_fee": "0.0000",
     "taxes": "0.0000",
     "payment_type": null,
     "paid_date": null,
     "notes": null,
     "tax_rate": "0",
     "tax_status_id": null,
     "status_id": "0" },
     "links": {
     "self": {
     "href": "http://localhost:9000/orders/71" },
     "employee": {
     "href": "http://localhost:9000/employees/1" }
     }
     }
     ],
     "links": {
     "employees": {
     "href": "http://localhost:9000/employees" },
     "employee_orders": {
     "href": "http://localhost:9000/employees/1/orders" }
     },
     "jsonapi": {
     "version": "1.0" }
    }

    电子邮件发布

    POST要求接受所有成员属性,即使是由mapper隐藏的成员属性。

    例如,attachments 成员被隐藏,但是需要它,因这里需要通过有效值进行传递。 另一方面,full_name 成员值不能作为属性传入,否则资源创建将会失败。

    pass和 id 是可选的,如果提供的话,它将代替服务器端生成的值。

    使用 POST 将以下数据发送到以下 URI http://localhost:9000/employees:

    {
     "data": {
     "type": "employee",
     "attributes": {
     "company": "NilPortugues.com",
     "surname": "Portugués",
     "first_name": "Nil",
     "email_address": "nilportugues@example.com",
     "job_title": "Web Developer",
     "business_phone": "(123)555-0100",
     "home_phone": "(123)555-0102",
     "mobile_phone": null,
     "fax_number": "(123)555-0103",
     "address": "Plaça Catalunya 1",
     "city": "Barcelona",
     "state_province": "Barcelona",
     "zip_postal_code": "08028",
     "country_region": "Spain",
     "web_page": "http://nilportugues.com",
     "notes": null,
     "attachments": null }
     } 
    } 

    将产生:

    HTTP/1.1 201 Created
    Cache-Control: private, max-age=0, must-revalidate
    Content-type: application/vnd.api+json
    Location: http://localhost:9000/employees/10

    请注意 201 HTTP状态码是如何返回的,并且。 而且 attachments 已经不存在了,full_name 也被显示。

    {
     "data": {
     "type": "employee",
     "id": "10",
     "attributes": {
     "company": "NilPortugues.com",
     "surname": "Portugués",
     "first_name": "Nil",
     "email_address": "nilportugues@example.com",
     "job_title": "Web Developer",
     "business_phone": "(123)555-0100",
     "home_phone": "(123)555-0102",
     "mobile_phone": null,
     "fax_number": "(123)555-0103",
     "address": "Plaça Catalunya 1",
     "city": "Barcelona",
     "state_province": "Barcelona",
     "zip_postal_code": "08028",
     "country_region": "Spain",
     "web_page": "http://nilportugues.com",
     "notes": null,
     "full_name": "Nil Portugués" },
     "links": {
     "self": {
     "href": "http://localhost:9000/employees/10" },
     "employee_orders": {
     "href": "http://localhost:9000/employees/10/orders" }
     }
     },
     "links": {
     "employees": {
     "href": "http://localhost:9000/employees" },
     "employee_orders": {
     "href": "http://localhost:9000/employees/10/orders" }
     },
     "jsonapi": {
     "version": "1.0" }
    }

    PUT要求接受所有成员属性,就像 POST 。

    为了实现这个示例,我们将只发送一个新的job_title 值,并将它的他所有内容保持完全相同。

    重要的是要注意,这次我们需要传入 id,即使它已经经通过URI传递,但 id 值必须是 MATCH 。 否则会失败的。

    使用 PUT 将以下数据发送到以下 URI http://localhost:9000/employees/10:

    {
     "data": {
     "type": "employee",
     "id": 10,
     "attributes": {
     "company": "NilPortugues.com",
     "surname": "Portugués",
     "first_name": "Nil",
     "email_address": "nilportugues@example.com",
     "job_title": "Full Stack Web Developer",
     "business_phone": "(123)555-0100",
     "home_phone": "(123)555-0102",
     "mobile_phone": null,
     "fax_number": "(123)555-0103",
     "address": "Plaça Catalunya 1",
     "city": "Barcelona",
     "state_province": "Barcelona",
     "zip_postal_code": "08028",
     "country_region": "Spain",
     "web_page": "http://nilportugues.com",
     "notes": null,
     "attachments": null }
     }
    }

    将产生:

    HTTP/1.1 200 OK
    Cache-Control: private, max-age=0, must-revalidate
    Content-type: application/vnd.api+json
    {
     "data": {
     "type": "employee",
     "id": "10",
     "attributes": {
     "company": "NilPortugues.com",
     "surname": "Portugués",
     "first_name": "Nil",
     "email_address": "contact@nilportugues.com",
     "job_title": "Full Stack Web Developer",
     "business_phone": "(123)555-0100",
     "home_phone": "(123)555-0102",
     "mobile_phone": null,
     "fax_number": "(123)555-0103",
     "address": "Plaça Catalunya 1",
     "city": "Barcelona",
     "state_province": "Barcelona",
     "zip_postal_code": "08028",
     "country_region": "Spain",
     "web_page": "http://nilportugues.com",
     "notes": null,
     "full_name": "Nil Portugués" },
     "links": {
     "self": {
     "href": "http://localhost:9000/employees/10" },
     "employee_orders": {
     "href": "http://localhost:9000/employees/10/orders" }
     }
     },
     "included": [],
     "links": {
     "employees": {
     "href": "http://localhost:9000/employees" },
     "employee_orders": {
     "href": "http://localhost:9000/employees/10/orders" }
     },
     "jsonapi": {
     "version": "1.0" }
    }

    补丁

    补丁允许部分更新,不同于 PUT 。

    我们需要传入 id 成员,即使它已经经通过URI传递,当然 id 值必须是 MATCH 。 否则会失败的。

    例如使用以下 URI http://localhost:9000/employees/10 将以下数据发送到服务器:

    {
     "data": {
     "type": "employee",
     "id": 10,
     "attributes": {
     "email_address": "contact@nilportugues.com" }
     }
    }

    将产生:

    HTTP/1.1 200 OK
    Cache-Control: private, max-age=0, must-revalidate
    Content-type: application/vnd.api+json
    {
     "data": {
     "type": "employee",
     "id": "10",
     "attributes": {
     "company": "NilPortugues.com",
     "surname": "Portugués",
     "first_name": "Nil",
     "email_address": "contact@nilportugues.com",
     "job_title": "Full Stack Web Developer",
     "business_phone": "(123)555-0100",
     "home_phone": "(123)555-0102",
     "mobile_phone": null,
     "fax_number": "(123)555-0103",
     "address": "Plaça Catalunya 1",
     "city": "Barcelona",
     "state_province": "Barcelona",
     "zip_postal_code": "08028",
     "country_region": "Spain",
     "web_page": "http://nilportugues.com",
     "notes": null,
     "full_name": "Nil Portugués" },
     "links": {
     "self": {
     "href": "http://localhost:9000/employees/10" },
     "employee_orders": {
     "href": "http://localhost:9000/employees/10/orders" }
     }
     },
     "included": [],
     "links": {
     "employees": {
     "href": "http://localhost:9000/employees" },
     "employee_orders": {
     "href": "http://localhost:9000/employees/10/orders" }
     },
     "jsonapi": {
     "version": "1.0" }
    }

    删除

    删除是使用最简单的方法,因为它不需要正文。 只需发出删除 http://localhost:9000/employees/10/id 10Employee 也会消失。

    它将产生以下输出:

    HTTP/1.1 204 No Content
    Cache-Control: private, max-age=0, must-revalidate
    Content-type: application/vnd.api+json

    注意响应将是空的:


    获取查询参数: 包含。字段。排序和页面

    根据标准,对于获取方法,可以执行以下操作:

    • 仅显示使用 fields 查询参数请求的字段。
      • &字段 [resource] =field1,field2

    例如通过 /employees/10?fields[employee]=company,first_name 将产生以下输出:

    {
     "data": {
     "type": "employee",
     "id": "10",
     "attributes": {
     "company": "NilPortugues.com",
     "first_name": "Nil" },
     "links": {
     "self": {
     "href": "http://localhost:9000/employees/10" },
     "employee_orders": {
     "href": "http://localhost:9000/employees/10/orders" }
     }
     },
     "links": {
     "employees": {
     "href": "http://localhost:9000/employees" },
     "employee_orders": {
     "href": "http://localhost:9000/employees/10/orders" }
     },
     "jsonapi": {
     "version": "1.0" }
    }
    • 只显示这些 include 资源,通过点之间分隔的关系,或者者通过逗号分隔的资源列表。
      • & include=resource1
      • & include=resource1.resource2.resource2.resource3

    例如 /employees?include=order 将只加载 include 成员中的订单类型数据,但是 /employees?include=order.employee 将只加载与 Employee 类型相关的那些订单。

    • 使用 sort 排序结果并传入 data[type] 成员中定义的主资源的成员名。 如果以 - 顺序开始,则为 DESCENDING,否则为 ASCENDING

      • & sort=field1,-field2
      • & sort=-field1,field2

    举个例子: /employees?sort=surname,-first_name

    • 分页也被定义为允许进行页面分页。光标分页或者偏移分页。
      • &页 [number ]
      • &页 [limit ]
      • &页 [cursor ]
      • &页 [offset ]
      • &页 [size ]

    举个例子: /employees?page[number]=1&page[size]=10

    带关系的 POST/PUT/PATCH

    JSON API允许创建和修改资源,并传递 relationships 来创建或者更改现有资源。

    假设我们想创建一个新的Employee 并传入它的第一个 Order

    在结束点( 一个用于员工,一个用于订单) 时,可以将 2 POST issuing,或者通过我们的Employee 将第一个 Order 作为 relationship 传递,比如:

    {
     "data": {
     "type": "employee",
     "attributes": {
     "company": "Northwind Traders",
     "surname": "Giussani",
     "first_name": "Laura",
     "email_address": "laura@northwindtraders.com",
     "job_title": "Sales Coordinator",
     "business_phone": "(123)555-0100",
     "home_phone": "(123)555-0102",
     "mobile_phone": null,
     "fax_number": "(123)555-0103",
     "address": "123 8th Avenue",
     "city": "Redmond",
     "state_province": "WA",
     "zip_postal_code": "99999",
     "country_region": "USA",
     "web_page": "http://northwindtraders.com",
     "notes": "Reads and writes French.",
     "full_name": "Laura Giussani" }, 
     "relationships": {
     "order": {
     "data": [
     {
     "type": "order",
     "attributes": {
     "customer_id": "28",
     "order_date": "2006-05-11 00:00:00",
     "shipped_date": "2006-05-11 00:00:00",
     "shipper_id": "3",
     "ship_name": "Amritansh Raghav",
     "ship_address": "789 28th Street",
     "ship_city": "Memphis",
     "ship_state_province": "TN",
     "ship_zip_postal_code": "99999",
     "ship_country_region": "USA",
     "shipping_fee": "10.0000",
     "taxes": "0.0000",
     "payment_type": "Check",
     "paid_date": "2006-05-11 00:00:00",
     "notes": null,
     "tax_rate": "0",
     "tax_status_id": null,
     "status_id": "0" }
     }
     ]
     }
     } 
     }
    } 

    在使用这里用例时,我们将不得不重写控制器实现,覆盖的JsonApiController 提供的某些方法: createResourceCallableupdateResourceCallablepatchResourceCallable

    下面是 createResourceCallable的工作原理。

    <?phpnamespaceAppHttpControllers;useAppModelDatabaseEmployees;useIlluminateDatabaseEloquentModel;useIlluminateSupportFacadesDB;useNilPortuguesApiJsonApiServerErrorsError;useNilPortuguesApiJsonApiServerErrorsErrorBag;useNilPortuguesLaravel5JsonApiControllerJsonApiController;classEmployeesControllerextendsJsonApiController{/** * Now you can actually create Employee and Orders at once. * Use transactions - DB::beginTransaction() for data integrity! * * @return callable*/protectedfunctioncreateResourceCallable() {$createOrderResource=function (Model$model, array$data) {if (!empty($data['relationships']['order']['data'])) {$orderData=$data['relationships']['order']['data'];if (!empty($orderData['type'])) {$orderData= [$orderData]; }foreach ($orderDataas$order) {$attributes=array_merge($order['attributes'], ['employee_id'=>$model->getKey()]);Orders::create($attributes); } } };returnfunction (array$data, array$values, ErrorBag$errorBag) use ($createOrderResource) {$attributes= [];foreach ($valuesas$name=>$value) {$attributes[$name] =$value; }if (!empty($data['id'])) {$attributes[$this->getDataModel()->getKeyName()] =$values['id']; }DB::beginTransaction();try {$model=$this->getDataModel()->create($attributes); $createOrderResource($model, $data);DB::commit();return$model; } catch(Exception$e) {DB::rollback();$errorBag[] =newError('creation_error', 'Resource could not be created');throw$e; } }; }}

    为了使用事务,在 Eloquent 中定义 $fillable 值是很重要的。

    下面是 EmployeesOrders 在定义 $fillable 时的样子。

    带 $fillable的员工( Eloquent模型)

    <?phpnamespaceAppModelDatabase;useIlluminateDatabaseEloquentModel;useIlluminateFoundationValidationValidatesRequests;classEmployeesextendsModel{public$timestamps=false;protected$table='employees'; protected$primaryKey='id';protected$appends= ['full_name'];/** * @var array*/protected$fillable= ['company','last_name','first_name','email_address','job_title','business_phone','home_phone','mobile_phone','fax_number','address','city','state_province','zip_postal_code','country_region','web_page','notes','attachments', ];/** * @return IlluminateDatabaseEloquentRelationsHasOne*/publicfunctionlatestOrders() {return$this->hasMany(Orders::class, 'employee_id')->limit(10); }/** * @return string*/publicfunctiongetFullNameAttribute() {return$this->first_name.''.$this->last_name; }}

    订单( Eloquent模型),$fillable

    <?phpnamespaceAppModelDatabase;useIlluminateDatabaseEloquentModel;classOrdersextendsModel{ public$timestamps=false;protected$table='orders';protected$primaryKey='id';/** * @var array*/protected$fillable= ['employee_id','customer_id','order_date','shipped_date','shipper_id','ship_name','ship_address','ship_city','ship_state_province','ship_zip_postal_code','ship_country_region','shipping_fee','taxes','payment_type','paid_date','notes','tax_rate','tax_status_id','status_id', ];/** * @return IlluminateDatabaseEloquentRelationsHasOne*/publicfunctionemployee() {return$this->belongsTo(Employees::class, 'employee_id'); }}

    自定义响应头

    添加自定义响应标头的原因有多种: 基于服务的版本管理,设置头,缓存,设置或者 public 服务内容。

    因此,要做到这一点,就像覆盖 JsonApiController addHeaders 方法一样简单。 例如让我们使用EmployeeController作为示例:

    <?phpnamespaceAppHttpControllers;useAppModelDatabaseEmployees;useNilPortuguesLaravel5JsonApiControllerJsonApiController;useSymfonyComponentHttpFoundationResponse;classEmployeesControllerextendsJsonApiController{//All your supported methods.../** * @param Response $response * * @return SymfonyComponentHttpFoundationResponse*/protectedfunctionaddHeaders(Response$response) {$response->headers->set('X-API-Version', '1.0');$response->setPublic();$response->setMaxAge(60);$response->setSharedMaxAge(60);return$response; }} 

    现在所有受支持的操作都将包括添加的自定义头。

    常见错误和解决方案

    未定义的索引:@type"

    这通常发生,因为你没有在 config/jsonapi.php 中编写你的Mapping的名称空间。 如果缺少,请将它的添加并刷新资源。 应该消失了 !

    对软件包的贡献始终欢迎 !

    • 报告你在问题跟踪程序上找到的任何 Bug 或者问题。
    • 你可以在包的Git存储库的中获取源代码。

    支持

    使用以下方法之一与我联系:

    作者

    许可证

    代码库是许可证下的许可证。



    文章标签:API  PAC  PACK  Laravel  Laravel 5  Json Api  Transformer  

    Copyright © 2011 HelpLib All rights reserved.    知识分享协议 京ICP备05059198号-3  |  如果智培  |  酷兔英语