@jsondrop /核心
Drupal JSON:API的一个类型化的、与框架无关的客户端。没有依赖关系。
npm install @jsondrop/core
使用
import { JsonApiClient, clientCredentials } from '@jsondrop/core';
const drupal = new JsonApiClient({
baseUrl: 'https://cms.example.com',
auth: clientCredentials({ clientId: '…', clientSecret: '…', scope: 'content:read' }),
});
const articles = await drupal.getCollection('node--article', {
query: {
include: ['field_image', 'uid'],
filter: { status: 1 },
sort: ['-created'],
page: { limit: 10 },
},
});
articles[0].field_image; // the included file--file, with relationshipMeta.alt
响应是反序列化的:属性和关系位于一个响应上
对象和关系被其包含的资源所替换
(递归)。未包含目标的关系是存根
({ id, type, stub: true },看 isStub)。
输入你的资源
通过声明合并注册一次资源类型:
import type { ResourceBase, ToOne, ToMany } from '@jsondrop/core';
interface NodeArticle extends ResourceBase<'node--article'> {
title: string;
body: { value: string; processed: string } | null;
field_tags: ToMany<TaxonomyTerm>;
field_image: ToOne<File>;
}
declare module '@jsondrop/core' {
interface ResourceTypes {
'node--article': NodeArticle;
}
}
const article = await drupal.getResource('node--article', id); // NodeArticle
API
资源: getResource, getCollection, getPage (与 next()),
iterate (异步,遵循 next 链接), createResource, updateResource,
deleteResource, uploadFile.
请求 相对于API前缀,对于自定义资源:
get, post, patch, delete, request. 它们返回原始文档
与 data, meta, links, status 和 headers.
选项 (客户端,每个请求一些):
| 选项 | |
|---|---|
baseUrl | 网站的起源 |
apiPrefix | 默认的 /jsonapi |
locale, defaultLocale | 语言路径前缀(/de/jsonapi/…) |
auth | bearer, basic, sessionCookie, clientCredentials,或者你自己的 AuthStrategy; false 每个请求 |
headers | 对象或(async)函数 |
resourcePaths | Type→path,对于用JSON重命名的类型:API Extras |
fetchOptions | 传递给 fetch,如。 { next: { revalidate: 60, tags: ['node:1'] } } |
onResponse | 在每个请求之后调用,用于记录日志 |
用户登录(OAuth)
OAuthClient 运行simple_oauth 6。x的授权代码流与PKCE
并刷新令牌(6)。X删除了密码和隐式授权):
import { OAuthClient } from '@jsondrop/core';
const oauth = new OAuthClient({ baseUrl, clientId, clientSecret, redirectUri, scope: 'openid profile' });
// 1. Redirect to Drupal; keep state + codeVerifier in an httpOnly cookie.
const { url, state, codeVerifier } = await oauth.startLogin();
// 2. On the redirect back: checks the state, exchanges the code.
const tokens = await oauth.finishLogin({ code, state: returnedState }, { state, codeVerifier });
// 3. Store the tokens server-side; requests as the user:
const asUser = drupal.extend({ auth: oauth.strategy(tokenStore) });
该策略在令牌过期之前和401之后刷新令牌。
刷新令牌是一次性使用的,所以并发刷新共享一个请求:
保持一个 OAuthClient 当Drupal拒绝刷新令牌时
存储被清空并抛出请求 LoginRequiredError:将用户发送到
重新登录。 oauth.userInfo(accessToken) 读取OpenID Connect声明。
看到 例7.
重命名资源 (JSON:API Extras): API的入口点列出了每个 类型的路径,因此让客户端在启动时读取它们一次,而不是 手工映射它们:
const drupal = await new JsonApiClient({ baseUrl }).withDiscoveredPaths();
drupal.resourcePath('products'); // '/products', as the site configures it
client.extend({ headers }) 派生一个添加标题(购物车)的客户端
令牌,一个市场),并共享父级的认证和令牌缓存。
错误:非2xx响应抛出 JsonApiError 与 status, errors
还有文件;它的 message Drupal的 detail. 在401上,策略
使用缓存令牌更新,请求重试一次。
链接:来自文档(links.next)发送至
baseUrl的起源,所以Drupal背后的一个代理,建立链接与
内部主机仍然工作,凭证永远不会到其他地方。
查询 也接受预构建的字符串,例如来自drupal-jsonapi-params。