craftcms / element-api
为Craft中的元素创建JSON API
Requires
- craftcms/cms: ^4.3.0|^5.0.0-beta.1
- league/fractal: ^0.20.1
Requires (Dev)
- craftcms/ecs: dev-main
- craftcms/phpstan: dev-main
- craftcms/rector: dev-main
- 4.x-dev
- 4.1.0
- 4.0.0
- 3.x-dev
- 3.0.1.1
- 3.0.1
- 3.0.0
- v2.x-dev
- 2.8.6.1
- 2.8.6
- 2.8.5
- 2.8.4
- 2.8.3
- 2.8.2
- 2.8.1
- 2.8.0
- 2.7.0
- 2.6.0
- 2.5.4
- 2.5.3
- 2.5.2
- 2.5.1
- 2.5.0
- 2.4.3
- 2.4.2
- 2.4.1
- 2.4.0
- 2.3.0
- 2.2.0
- 2.1.0
- 2.0.2
- 2.0.1
- 2.0.0
- v1.x-dev
- 1.6.0
- 1.5.0
- 1.4.0
- 1.3.0
- 1.2.1
- 1.2.0
- 1.1.0
- 1.0.0
- dev-dependabot/npm_and_yarn/braces-3.0.3
- dev-dependabot/composer/composer/composer-2.7.7
- dev-feature/cache-key-storing-site
This package is auto-updated.
Last update: 2024-08-25 03:42:11 UTC
README
此插件使您能够轻松为Craft CMS中的条目(和其他元素类型)创建JSON API。
它由Phil Sturgeon的出色Fractal包提供支持。
要求
此插件需要Craft CMS 4.3.0+或5.0.0+。
安装
您可以从插件商店或使用Composer安装此插件。
从插件商店
前往项目控制面板中的插件商店,搜索“Element API”。然后在模态窗口中点击“安装”按钮。
使用Composer
打开您的终端并运行以下命令
# go to the project directory cd /path/to/my-project.test # tell Composer to load the plugin composer require craftcms/element-api # tell Craft to install the plugin ./craft plugin/install element-api
设置
要定义API端点,请在您的config/
文件夹中创建一个新的element-api.php
文件。此文件应返回一个包含endpoints
键的数组,该键定义了您的网站的API端点。
在endpoints
数组中,键是URL模式,值是定义端点配置的函数。
<?php use craft\elements\Entry; use craft\helpers\UrlHelper; return [ 'endpoints' => [ 'news.json' => function() { return [ 'elementType' => Entry::class, 'criteria' => ['section' => 'news'], 'transformer' => function(Entry $entry) { return [ 'id' => $entry->id, 'title' => $entry->title, 'url' => $entry->url, 'jsonUrl' => UrlHelper::url("news/$entry->id.json"), 'summary' => $entry->summary, ]; }, ]; }, 'news/<entryId:\d+>.json' => function($entryId) { return [ 'elementType' => Entry::class, 'criteria' => ['id' => $entryId], 'one' => true, 'transformer' => function(Entry $entry) { return [ 'title' => $entry->title, 'url' => $entry->url, 'summary' => $entry->summary, 'body' => $entry->body, ]; }, ]; }, ] ];
端点配置设置
端点配置数组可以包含以下设置
class
应用于提供请求的Fractal资源的类名。如果没有设置,将默认为craft\elementapi\resources\ElementResource
。(所有以下配置设置都是针对该默认类的。)
elementType
(必需)
API应关联的元素类型的类名。Craft的内置元素类型类包括
craft\elements\Asset
craft\elements\Category
craft\elements\Entry
craft\elements\GlobalSet
craft\elements\MatrixBlock
craft\elements\Tag
craft\elements\User
'elementType' => craft\elements\Entry::class,
criteria
一个参数数组,应在将检索元素的元素查询上设置。
'criteria' => [ 'section' => 'news', 'type' => 'article', ],
contentType
端点响应应具有的内容类型。
'contentType' => 'application/foo+json',
默认情况下,内容类型将是
application/javascript
对于定义JSONP 回调 的端点application/feed+json
对于将序列化器设置为jsonFeed
的端点application/json
对于所有其他内容
transformer
应用于定义每个元素应返回的数据的转换器。如果您没有设置,将使用默认转换器,该转换器包括所有元素的直接属性值,但不包括自定义字段值。
// Can be set to a function 'transformer' => function(craft\elements\Entry $entry) { return [ 'title' => $entry->title, 'id' => $entry->id, 'url' => $entry->url, ]; }, // Or a string/array that defines a Transformer class configuration 'transformer' => 'MyTransformerClassName', // Or a Transformer class instance 'transformer' => new MyTransformerClassName(),
您的自定义转换器类可能看起来像这样
<?php use craft\elements\Entry; use League\Fractal\TransformerAbstract; class MyTransformerClassName extends TransformerAbstract { public function transform(Entry $entry) { return [ // ... ]; } }
one
是否仅返回第一个匹配的元素。默认设置为false
,表示将返回所有匹配的元素。
'one' => true,
paginate
是否应对结果进行分页。默认设置为true
,这意味着每个响应中只包含匹配元素的一个子集,并伴随描述分页信息的附加元数据。
'paginate' => false,
elementsPerPage
如果启用分页,则每页应包含的最大元素数量。默认设置为100。
'elementsPerPage' => 10,
pageParam
用于标识请求页面的查询字符串参数名称。默认设置为'page'
。
'pageParam' => 'pg',
请注意,不能将其设置为'p'
,因为这将是Craft用来检查请求路径的参数。
resourceKey
元素应在响应数据中嵌套的键。默认情况下,这将设置为'data'
。
'resourceKey' => 'entries',
meta
应包含在响应数据中的任何自定义元值。
'meta' => [ 'description' => 'Recent news from Happy Lager', ],
serializer
应使用序列化器来格式化返回的数据。
可能的值有
'array'
(默认) – 使用ArraySerializer来格式化数据。'dataArray'
– 使用DataArraySerializer来格式化数据。'jsonApi'
– 使用JsonApiSerializer来格式化数据。'jsonFeed'
– 基于以下链接的JSON Feed V1.1格式化数据(请参阅下面的JSON Feed示例):[JSON Feed V1.1](https://www.jsonfeed.org/version/1.1/)。- 自定义序列化器实例。
includes
对于当前请求,应包含的包含名称(如果有的话)。
'includes' => (array)Craft::$app->request->getQueryParam('include'),
请注意,此设置需要一个预置以处理包含的包含的自定义转换器类。
class MyTransformerClassName extends TransformerAbstract { protected $availableIncludes = ['author']; public function includeAuthor(Entry $entry) { return $this->item($entry->author, function(User $author) { return [ 'id' => $author->id, 'name' => $author->name, ]; }); } // ... }
excludes
对于当前请求,应排除的包含名称,否则它们将被包含(例如,如果它们被列为默认包含),如果有的话。
'excludes' => 'author',
与includes
一样,此设置需要一个自定义转换器类。
callback
如果设置此值,则返回JSONP响应,并使用此设置值作为回调函数,内容类型为application/javascript
。
例如,如果您将其设置为
'callback' => 'foo',
则响应将如下所示
foo({ /* ... */ });
请注意,如果您设置此值,则忽略jsonOptions
和pretty
设置。
jsonOptions
将传递给json_encode()
的$options
参数值,以准备响应。默认将传递JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
。
'jsonOptions' => JSON_UNESCAPED_UNICODE,
pretty
为jsonOptions
添加JSON_PRETTY_PRINT
的快捷方式。
'pretty' => true,
cache
输出是否应该被缓存,以及缓存多久。
可能的值有
true
(默认) – 结果根据Craft配置设置中的cacheDuration
指定的持续时间进行缓存,或者直到相关元素被保存或删除。false
– 结果永远不会被缓存。- 整数 – 结果缓存指定秒数。
- interval spec字符串 – 结果根据指定持续时间进行缓存。
请注意,当缓存温暖时,不会触发onBeforeSendData
事件。
'cache' => 'PT1M', // one minute
cacheKey
如果需要自定义,则响应应缓存的键。
动态URL模式
URL模式可以包含动态子模式,格式为<subpatternName:regex>
,其中subpatternName
是子模式的名称,regex
是有效的正则表达式。例如,URL模式“news/<entryId:\d+>.json
”将匹配类似news/100.json
的URL。您也可以在正则表达式中使用{handle}
和{slug}
标记,这些将被替换为匹配处理和元素短语的适当正则表达式模式。
URL模式中的任何子模式匹配都将映射到端点配置函数的参数。例如,如果URL模式包含一个entryId
子模式,那么您可以在端点配置函数中添加一个$entryId
参数,匹配URL子模式的任何内容都将传递给$entryId
。
'news/<entryId:\d+>.json' => function($entryId) { return [ 'elementType' => craft\elements\Entry::class, 'criteria' => ['id' => $entryId], 'one' => true, ]; },
设置默认配置设置
您可以通过在endpoints
键旁边添加一个defaults
键来指定端点配置设置的默认值(不在它内部)。
use craft\elements\Entry; return [ 'defaults' => [ 'elementType' => Entry::class, 'elementsPerPage' => 10, 'pageParam' => 'pg', 'transformer' => function(Entry $entry) { return [ 'title' => $entry->title, 'id' => $entry->id, 'url' => $entry->url, ]; }, ], 'endpoints' => [ 'news.json' => function() { return [ 'criteria' => ['section' => 'news'], ] }, 'news/<entryId:\d+>.json' => function($entryId) { return [ 'criteria' => ['id' => $entryId], 'one' => true, ]; }, ] ];
示例
以下是几个端点示例以及它们的响应示例。
分页条目索引端点
'ingredients.json' => function() { return [ 'criteria' => ['section' => 'ingredients'], 'elementsPerPage' => 10, 'transformer' => function(craft\elements\Entry $entry) { return [ 'title' => $entry->title, 'url' => $entry->url, 'jsonUrl' => UrlHelper::url("ingredients/$entry->slug.json"), ]; }, 'pretty' => true, ]; },
{ "data": [ { "title": "Gin", "url": "/ingredients/gin", "jsonUrl": "/ingredients/gin.json" }, { "title": "Tonic Water", "url": "/ingredients/tonic-water", "jsonUrl": "/ingredients/tonic-water.json" }, // ... ], "meta": { "pagination": { "total": 66, "count": 10, "per_page": 10, "current_page": 1, "total_pages": 7, "links": { "next": "/ingredients.json?p=2" } } } }
单个条目端点
'ingredients/<slug:{slug}>.json' => function($slug) { return [ 'criteria' => [ 'section' => 'ingredients', 'slug' => $slug ], 'one' => true, 'transformer' => function(craft\elements\Entry $entry) { // Create an array of all the photo URLs $photos = []; foreach ($entry->photos->all() as $photo) { $photos[] = $photo->url; } return [ 'title' => $entry->title, 'url' => $entry->url, 'description' => (string)$entry->description, 'photos' => $photos ]; }, 'pretty' => true, ]; },
{ "title": "Gin", "url": "/ingredients/gin", "description": "<p>Gin is a spirit which derives its predominant flavour from juniper berries.</p>", "photos": [ "/images/drinks/GinAndTonic1.jpg" ] }
JSON源
以下是使用Element API为您的站点设置JSON源(版本1.1)的方法。
请注意,photos
、body
、summary
和tags
是虚构的自定义字段。
'feed.json' => function() { return [ 'serializer' => 'jsonFeed', 'elementType' => craft\elements\Entry::class, 'criteria' => ['section' => 'news'], 'transformer' => function(craft\elements\Entry $entry) { $image = $entry->photos->one(); return [ 'id' => (string)$entry->id, 'url' => $entry->url, 'title' => $entry->title, 'content_html' => (string)$entry->body, 'summary' => $entry->summary, 'image' => $image ? $image->url : null, 'date_published' => $entry->postDate->format(\DateTime::ATOM), 'date_modified' => $entry->dateUpdated->format(\DateTime::ATOM), 'authors' => [ ['name' => $entry->author->name], ], 'language' => $entry->getSite()->language, 'tags' => array_map('strval', $entry->tags->all()), ]; }, 'meta' => [ 'description' => 'Recent news from Happy Lager', ], 'pretty' => true, ]; },
{ "version": "https://jsonfeed.org/version/1", "title": "Happy Lager", "home_page_url": "http://domain.com/", "feed_url": "http://domain.com/feed.json", "description": "Craft demo site", "items": [ { "id": "24", "url": "http://domain.com/news/the-future-of-augmented-reality", "title": "The Future of Augmented Reality", "content_html": "<p>Nam libero tempore, cum soluta nobis est eligendi ...</p>", "date_published": "2016-05-07T00:00:00+00:00", "date_modified": "2016-06-03T17:43:36+00:00", "author": { "name": "Liz Murphy" }, "tags": [ "augmented reality", "futurism" ] }, { "id": "4", "url": "http://domain.com/news/barrel-aged-digital-natives", "title": "Barrel Aged Digital Natives", "content_html": "<p>Nam libero tempore, cum soluta nobis est eligendi ...</p>",, "date_published": "2016-05-06T00:00:00+00:00", "date_modified": "2017-05-18T13:20:27+00:00", "author": { "name": "Liz Murphy" }, "tags": [ "barrel-aged" ] }, // ... ] }