加入我们,从10月8日至10日在纽约市,学习有关GraphQL联盟和API平台工程的最新技巧、趋势和新闻。加入我们,参加2024年在纽约市的GraphQL峰会
文档
免费开始

上下文和contextValue

在服务器上共享信息和请求详情


在进行 时,您可以在服务器上共享解析器插件,通过创建一个名为contextValue

对象。contextValue可以通过contextValue传递任何可能需要的有用信息,例如认证作用域数据获取源、数据库连接和自定义获取函数。如果您正在使用数据加载器来批量处理的请求,您还可以将它们附加到共享的contextValue上。

context函数

📣 Apollo Server 4 更改了定义context函数的语法。查看更多详情。

context函数应该是异步的并返回一个对象。这个对象随后可以通过使用名称contextValue在您的服务器解析器和插件中访问。

您可以将一个context函数传递到您的任何集成函数中(例如expressMiddlewarestartStandaloneServer)。

服务器为每个请求调用一次context函数,这使得您可以针对每个请求的详细信息(例如HTTP头)自定义您的contextValue

import { GraphQLError } from 'graphql';
const resolvers = {
Query: {
// Example resolver
adminExample: (parent, args, contextValue, info) => {
if (contextValue.authScope !== ADMIN) {
throw new GraphQLError('not admin!', {
extensions: { code: 'UNAUTHENTICATED' },
});
}
},
},
};
interface MyContext {
// You can optionally create a TS interface to set up types
// for your contextValue
authScope?: String;
}
const server = new ApolloServer<MyContext>({
typeDefs,
resolvers,
});
const { url } = await startStandaloneServer(server, {
// Your async context function should async and
// return an object
context: async ({ req, res }) => ({
authScope: getScope(req.headers.authorization),
}),
});
import { GraphQLError } from 'graphql';
const resolvers = {
Query: {
// Example resolver
adminExample: (parent, args, contextValue, info) => {
if (contextValue.authScope !== ADMIN) {
throw new GraphQLError('not admin!', {
extensions: { code: 'UNAUTHENTICATED' },
});
}
},
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
});
const { url } = await startStandaloneServer(server, {
// Your async context function should async and
// return an object
context: async ({ req, res }) => ({
authScope: getScope(req.headers.authorization),
}),
});

以上示例假设您正在使用 startStandaloneServerexpressMiddleware,这两者都使用底层的 Express。您 context 函数的传入 可能会有所不同,如果您使用的是不同的集成。

如果您使用 TypeScript,您 必须 提供一个命名的 context 函数,如果您通过将类型参数传递给 ApolloServer 来对上下文进行类型化(即您不使用 ApolloServer<BaseContext>)。

由于 context 初始化函数是异步的,您可以使用它来建立数据库连接并等待其他 完成:

context: async () => ({
db: await client.connect(),
})
// Resolver
(parent, args, contextValue, info) => {
return contextValue.db.query('SELECT * FROM table_name');
}

抛出错误

默认情况下,如果您的 context 函数抛出错误, 将以 500 HTTP 状态码在 JSON 响应中返回该错误。如果错误不是 GraphQLError,错误的消息将用 "上下文创建失败:" 预先添加。

您可以通过抛出一个具有 GraphQLError 和一个 http 扩展 来更改错误的 HTTP 状态码。例如:

context: async ({ req }) => {
const user = await getUserFromReq(req);
if (!user) {
throw new GraphQLError('User is not authenticated', {
extensions: {
code: 'UNAUTHENTICATED',
http: { status: 401 },
}
});
}
// If the below throws a non-GraphQLError, the server returns
// `code: "INTERNAL_SERVER_ERROR"` with an HTTP status code 500, and
// a message starting with "Context creation failed: ".
const db = await getDatabaseConnection();
return { user, db };
},

contextValue 对象

context 函数 返回一个对象,contextValue,它对您的插件和解析器都是可访问的。

解析器

解析器不应该破坏性地修改 contextValue 参数。 这确保了所有 resolvers 之间的一致性,并且可以防止出现意外的错误。

您的解析器可以通过它们第三个位置参数访问共享的contextValue对象。正在执行特定操作的解析器都有访问contextValue的权限。

import { AnimalAPI } from './datasources/animals';
const resolvers = {
Query: {
// All of our resolvers can access our shared contextValue!
dogs: (_, __, contextValue) => {
return contextValue.dataSources.animalApi.getDogs();
},
cats: (_, __, contextValue) => {
return contextValue.dataSources.animalApi.getCats();
},
},
};
interface MyContext {
// Context typing
dataSources: {
animalApi: AnimalAPI;
};
}
const server = new ApolloServer<MyContext>({
typeDefs,
resolvers,
});
const { url } = await startStandaloneServer(server, {
context: async () => {
const animalApi = new AnimalAPI();
return {
dataSources: {
animalApi,
},
};
},
});
import { AnimalAPI } from './datasources/animals';
const resolvers = {
Query: {
// All of our resolvers can access our shared contextValue!
dogs: (_, __, contextValue) => {
return contextValue.dataSources.animalApi.getDogs();
},
cats: (_, __, contextValue) => {
return contextValue.dataSources.animalApi.getCats();
},
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
});
const { url } = await startStandaloneServer(server, {
context: async () => {
const animalApi = new AnimalAPI();
return {
dataSources: {
animalApi,
},
};
},
});

插件

内置和自定义插件可以通过请求生命周期函数访问contextValue,如下所示:

interface MyContext {
token: string;
}
const server = new ApolloServer<MyContext>({
typeDefs,
resolvers: {
Query: {
hello: (root, args, { token }) => {
return token;
},
},
},
plugins: [
{
async requestDidStart({ contextValue }) {
// token is properly inferred as a string
console.log(contextValue.token);
},
},
],
});
const { url } = await startStandaloneServer(server, {
context: async ({ req, res }) => ({
token: await getTokenForRequest(req),
}),
});
const server = new ApolloServer({
typeDefs,
resolvers: {
Query: {
hello: (root, args, { token }) => {
return token;
},
},
},
plugins: [
{
async requestDidStart({ contextValue }) {
// token is properly inferred as a string
console.log(contextValue.token);
},
},
],
});
const { url } = await startStandaloneServer(server, {
context: async ({ req, res }) => ({
token: await getTokenForRequest(req),
}),
});
上一页
解析器
下一页
错误处理
评价文章评价在GitHub上编辑编辑论坛Discord

©2024Apollo Graph Inc.,名称简化为Apollo GraphQL。

隐私政策

公司