如何在KeyStoneJS v6中调用REST API并对接NextJS GraphQL客户端
KeystoneJS v6 调用外部REST API并通过GraphQL返回的实现思路
1. 扩展GraphQL Schema
在Keystone v6主配置文件(keystone.ts)中,通过extendGraphQLSchema选项添加自定义查询(Query)和突变(Mutation),作为调用外部API的入口。
示例代码:
import { config } from '@keystone-6/core'; import { extendGraphQLSchema } from '@keystone-6/core/graphql'; export default config({ // 其他配置(如数据库、列表定义)... extendGraphQLSchema: (schema) => { return schema.extend({ types: [ // 定义外部API返回数据的GraphQL类型 `type ExternalData { id: ID! title: String! content: String }`, // 定义POST请求的输入参数类型 `input ExternalPostInput { title: String! content: String! }`, // 定义POST请求的返回结果类型 `type ExternalPostResponse { success: Boolean! message: String data: ExternalData }`, ], queries: [ // 添加GET请求对应的查询 { schema: 'getExternalData(id: ID!): ExternalData', resolver: async (parent, args, context) => { // 此处编写外部API调用逻辑 }, }, ], mutations: [ // 添加POST请求对应的突变 { schema: 'postToExternal(input: ExternalPostInput!): ExternalPostResponse', resolver: async (parent, args, context) => { // 此处编写外部API POST逻辑 }, }, ], }); }, });
2. 在Resolver中实现外部API调用
使用node-fetch或axios在Resolver里发送HTTP请求,处理异步逻辑。
GET请求示例
// 先安装依赖:npm install node-fetch import fetch from 'node-fetch'; // 填充getExternalData的resolver逻辑 resolver: async (parent, { id }, context) => { try { const response = await fetch(`https://your-external-api.com/data/${id}`); if (!response.ok) { throw new Error(`外部API请求失败:${response.statusText}`); } const rawData = await response.json(); // 映射外部API数据到GraphQL定义的类型结构 return { id: rawData.id.toString(), title: rawData.title, content: rawData.content || '', }; } catch (error) { // 抛出GraphQL错误,供客户端捕获 throw new Error(`获取外部数据失败:${(error as Error).message}`); } },
POST请求示例
// 填充postToExternal的resolver逻辑 resolver: async (parent, { input }, context) => { try { const response = await fetch('https://your-external-api.com/submit', { method: 'POST', headers: { 'Content-Type': 'application/json', // 若外部API需要认证,在此添加token // 'Authorization': `Bearer ${process.env.EXTERNAL_API_TOKEN}` }, body: JSON.stringify(input), }); if (!response.ok) { throw new Error(`外部API POST请求失败:${response.statusText}`); } const result = await response.json(); return { success: true, message: '数据提交成功', data: { id: result.id.toString(), title: result.title, content: result.content, }, }; } catch (error) { return { success: false, message: `提交数据失败:${(error as Error).message}`, data: null, }; } },
3. 权限控制(可选)
通过context.session校验用户身份,限制接口调用权限:
resolver: async (parent, args, context) => { // 检查用户是否登录 if (!context.session?.itemId) { throw new Error('请登录后访问'); } // 可选:校验用户角色 const user = await context.db.User.findOne({ where: { id: context.session.itemId }, select: { role: true }, }); if (user?.role !== 'admin') { throw new Error('权限不足'); } // 后续API调用逻辑... },
4. NextJS客户端调用
在NextJS中通过GraphQL客户端(如Apollo Client)或直接fetch调用Keystone的GraphQL API:
示例:用fetch调用GET查询
async function fetchExternalData(id: string) { const response = await fetch('http://your-keystone-api.com/api/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json', // 若Keystone开启认证,添加用户session token // 'Authorization': `Bearer ${userSessionToken}` }, body: JSON.stringify({ query: ` query GetExternalData($id: ID!) { getExternalData(id: $id) { id title content } } `, variables: { id }, }), }); const { data, errors } = await response.json(); if (errors) throw new Error(errors[0].message); return data.getExternalData; }
5. 错误处理与优化
- 添加请求超时机制,避免Resolver长时间阻塞:
const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 5000); // 5秒超时 const response = await fetch(url, { signal: controller.signal }); clearTimeout(timeoutId); - 对高频请求的外部数据添加缓存,减少重复API调用。
内容的提问来源于stack exchange,提问作者Ronier Ramos Sanchez
相关产品推荐
相关产品推荐

