@accounts/graphql-api 中文文档教程
@accounts/graphql-api
带有 JSAccounts 的 GraphQL 服务器的架构、解析器和实用程序
这个包不需要任何网络接口/express 来与你的 GraphQL 结合 -它只是 GraphQL 模式、解析器和实用程序的集合!
How to use this package?
此包导出 GraphQL 架构和 GraphQL 解析器,您可以使用现有的 GraphQL 架构服务器对其进行扩展。
首先从 NPM / Yarn 安装它:
// Npm
npm install --save @accounts/server @accounts/graphql-api @graphql-modules/core
// Yarn
yarn add @accounts/server @accounts/graphql-api @graphql-modules/core
这个包不会创建传输或其他任何东西,只会创建模式和字符串以及作为对象的解析器。
首先根据需要配置您的 AccountsServer
。 例如,使用 MongoDB:
import mongoose from 'mongoose'
import AccountsServer from '@accounts/server'
import AccountsPassword from '@accounts/password'
import MongoDBInterface from '@accounts/mongo'
const db = mongoose.connection
const password = new AccountsPassword()
const accountsServer = new AccountsServer({
{
db: new MongoDBInterface(db),
tokenSecret: 'SECRET',
},
{
password,
}
});
接下来,从此包中导入 AccountsModule
,并使用您的 AccountsServer
运行它:
import { AccountsModule } from '@accounts/graphql-api';
const accountsGraphQL = AccountsModule.forRoot({
accountsServer,
});
现在,将 accountsGraphQL.typeDefs
添加到您的模式定义(就在将其与 makeExecutableSchema
一起使用之前),并使用 @graphql-tools/epoxy
将您的解析器对象与 accountsGraphQL.resolvers
合并,例如:
import { makeExecutableSchema } from '@graphql-tools/schema';
import { mergeGraphQLSchemas, mergeResolvers } from '@graphql-tools/epoxy';
const typeDefs = [
`
type Query {
myQuery: String
}
type Mutation {
myMutation: String
}
schema {
query: Query,
mutation: Mutation
}
`,
accountsGraphQL.typeDefs,
];
let myResolvers = {
Query: {
myQuery: () => 'Hello',
},
Mutation: {
myMutation: () => 'Hello',
},
};
const schema = makeExecutableSchema({
resolvers: mergeResolvers([accountsGraphQL.resolvers, myResolvers]),
typeDefs: mergeGraphQLSchemas([typeDefs]),
});
最后一步是使用上下文中间件扩展您的 graphqlExpress
,它从 HTTP 请求中提取身份验证令牌,因此 AccountsServer 将自动验证它:
app.use(
GRAPHQL_ROUTE,
bodyParser.json(),
graphqlExpress((request) => {
return {
context: {
...accountsGraphQL(request),
// your context
},
schema,
};
})
);
Authenticating Resolvers
您可以使用 验证您自己的解析器JSAccounts
身份验证流程,使用此包中的 authenticated
方法。
此方法作曲家还使用当前经过身份验证的用户扩展了 context
!
这是受保护突变的示例:
import AccountsServer from '@accounts/server';
import { authenticated } from '@accounts/graphql-api';
export const resolver = {
Mutation: {
updateUserProfile: authenticated((rootValue, args, context) => {
// Write your resolver here
// context.user - the current authenticated user!
}),
},
};
Customization
此包允许您自定义 GraphQL 架构及其解析器。
例如,某些应用程序主查询称为 MyQuery
或 RootQuery
而不是查询,因此您可以自定义名称,而无需修改应用程序的架构。
这些是可用的自定义:
rootQueryName
(string) - The name of the root query, default:Query
.rootMutationName
(string) - The name of the root mutation, default:Mutation
.extend
(boolean) - whether to addextend
before the root type declaration, default:true
.withSchemaDefinition
(boolean): whether to addschema { ... }
declaration to the generation schema, default:false
.
将第二个对象传递给 createAccountsGraphQL
,例如:
另一种可能的自定义是修改身份验证标头的名称,将其与 accountsContext
(默认is Authorization
):
const myCustomGraphQLAccounts = AccountsModule.forRoot({
accountsServer,
rootQueryName: 'RootQuery',
rootMutationName: 'RootMutation',
headerName: 'MyCustomHeader',
});
Extending User
要使用自定义字段和逻辑扩展 User
对象,请添加您自己的 User
GraphQL 类型定义,前缀为 扩展
,并添加您的字段:
extend type User {
firstName: String
lastName: String
}
同时为您添加的字段实现一个常规解析器:
const UserResolver = {
firstName: () => 'Dotan',
lastName: () => 'Simha',
};
Extending User
during password creation
要在用户创建期间扩展用户对象,您需要扩展CreateUserInput
类型并添加您的字段:
extend input CreateUserInput {
profile: CreateUserProfileInput!
}
input CreateUserProfileInput {
firstName: String!
lastName: String!
}
用户将保存在数据库中,并设置了配置文件键。
Example: Authenticate with a Service
mutation Authenticate {
authenticate(serviceName: "password", params: { password: "<pw>", user: { email: "<email>" } })
}
serviceName
- corresponds to the package you are using to authenticate (e.g. oauth, password, twitter, instagram, two factor, token, etc).params
- These will be different depending on the service you are using.
- Twitter/Instagram
mutation Authenticate {
authenticate(
serviceName: "twitter"
params: { access_token: "<access-token>", access_token_secret: "<access-token-secret>" }
)
}
- OAuth
mutation Authenticate {
authenticate(serviceName: "oauth", params: { provider: "<your-provider>" })
}
- Password: Below the
user
containsemail
but can contain one or more ofid
,email
orusername
too.
mutation Authenticate {
authenticate(serviceName: "password", params: { password: "<pw>", user: { email: "<email>" } })
}
- Two Factor
mutation Authenticate {
authenticate(serviceName: "two-factor", params: { code: "<two-factor-code>" })
}
- Token
mutation Authenticate {
authenticate(serviceName: "token", params: { token: "<token>" })
}
Verify Authentication
检查用户是否已成功通过身份验证的方法是相同的,除了 verifyAuthentication
返回一个 boolean
而不是 LoginResult
:
mutation Verify {
verifyAuthentication(
serviceName: "password"
params: { password: "<pw>", user: { email: "<email>" } }
)
}
这将如果您的用户已成功通过身份验证,则返回类似于此的结果:
{
"data": {
"verifyAuthentication": true
}
}
@accounts/graphql-api
Schema, Resolvers and Utils for GraphQL server with JSAccounts
This package does not requires any network interface / express in order to combine with your GraphQL - it's just a collection of GraphQL schema, resolvers and utils!
How to use this package?
This package exports GraphQL schema and GraphQL resolvers, which you can extend with your existing GraphQL schema server.
Start by installing it from NPM / Yarn:
// Npm
npm install --save @accounts/server @accounts/graphql-api @graphql-modules/core
// Yarn
yarn add @accounts/server @accounts/graphql-api @graphql-modules/core
This package does not create a transport or anything else, only schema and string and resolvers as object.
Start by configuring your AccountsServer
as you wish. For example, using MongoDB:
import mongoose from 'mongoose'
import AccountsServer from '@accounts/server'
import AccountsPassword from '@accounts/password'
import MongoDBInterface from '@accounts/mongo'
const db = mongoose.connection
const password = new AccountsPassword()
const accountsServer = new AccountsServer({
{
db: new MongoDBInterface(db),
tokenSecret: 'SECRET',
},
{
password,
}
});
Next, import AccountsModule
from this package, and run it with your AccountsServer
:
import { AccountsModule } from '@accounts/graphql-api';
const accountsGraphQL = AccountsModule.forRoot({
accountsServer,
});
Now, add accountsGraphQL.typeDefs
to your schema definition (just before using it with makeExecutableSchema
), and merge your resolvers object with accountsGraphQL.resolvers
by using @graphql-tools/epoxy
, for example:
import { makeExecutableSchema } from '@graphql-tools/schema';
import { mergeGraphQLSchemas, mergeResolvers } from '@graphql-tools/epoxy';
const typeDefs = [
`
type Query {
myQuery: String
}
type Mutation {
myMutation: String
}
schema {
query: Query,
mutation: Mutation
}
`,
accountsGraphQL.typeDefs,
];
let myResolvers = {
Query: {
myQuery: () => 'Hello',
},
Mutation: {
myMutation: () => 'Hello',
},
};
const schema = makeExecutableSchema({
resolvers: mergeResolvers([accountsGraphQL.resolvers, myResolvers]),
typeDefs: mergeGraphQLSchemas([typeDefs]),
});
The last step is to extend your graphqlExpress
with a context middleware, that extracts the authentication token from the HTTP request, so AccountsServer will automatically validate it:
app.use(
GRAPHQL_ROUTE,
bodyParser.json(),
graphqlExpress((request) => {
return {
context: {
...accountsGraphQL(request),
// your context
},
schema,
};
})
);
Authenticating Resolvers
You can authenticate your own resolvers with JSAccounts
authentication flow, by using authenticated
method from this package.
This method composer also extends context
with the current authenticated user!
This is an example for a protected mutation:
import AccountsServer from '@accounts/server';
import { authenticated } from '@accounts/graphql-api';
export const resolver = {
Mutation: {
updateUserProfile: authenticated((rootValue, args, context) => {
// Write your resolver here
// context.user - the current authenticated user!
}),
},
};
Customization
This package allow you to customize the GraphQL schema and it's resolvers.
For example, some application main query called MyQuery
or RootQuery
instead of query, so you can customize the name, without modifying you application's schema.
These are the available customizations:
rootQueryName
(string) - The name of the root query, default:Query
.rootMutationName
(string) - The name of the root mutation, default:Mutation
.extend
(boolean) - whether to addextend
before the root type declaration, default:true
.withSchemaDefinition
(boolean): whether to addschema { ... }
declaration to the generation schema, default:false
.
Pass a second object to createAccountsGraphQL
, for example:
Another possible customization is to modify the name of the authentication header, use it with accountsContext
(the default is Authorization
):
const myCustomGraphQLAccounts = AccountsModule.forRoot({
accountsServer,
rootQueryName: 'RootQuery',
rootMutationName: 'RootMutation',
headerName: 'MyCustomHeader',
});
Extending User
To extend User
object with custom fields and logic, add your own GraphQL type definition of User
with the prefix of extend
, and add your fields:
extend type User {
firstName: String
lastName: String
}
And also implement a regular resolver, for the fields you added:
const UserResolver = {
firstName: () => 'Dotan',
lastName: () => 'Simha',
};
Extending User
during password creation
To extend the user object during the user creation you need to extend the CreateUserInput
type and add your fields:
extend input CreateUserInput {
profile: CreateUserProfileInput!
}
input CreateUserProfileInput {
firstName: String!
lastName: String!
}
The user will be saved in the db with the profile key set.
Example: Authenticate with a Service
mutation Authenticate {
authenticate(serviceName: "password", params: { password: "<pw>", user: { email: "<email>" } })
}
serviceName
- corresponds to the package you are using to authenticate (e.g. oauth, password, twitter, instagram, two factor, token, etc).params
- These will be different depending on the service you are using.
- Twitter/Instagram
mutation Authenticate {
authenticate(
serviceName: "twitter"
params: { access_token: "<access-token>", access_token_secret: "<access-token-secret>" }
)
}
- OAuth
mutation Authenticate {
authenticate(serviceName: "oauth", params: { provider: "<your-provider>" })
}
- Password: Below the
user
containsemail
but can contain one or more ofid
,email
orusername
too.
mutation Authenticate {
authenticate(serviceName: "password", params: { password: "<pw>", user: { email: "<email>" } })
}
- Two Factor
mutation Authenticate {
authenticate(serviceName: "two-factor", params: { code: "<two-factor-code>" })
}
- Token
mutation Authenticate {
authenticate(serviceName: "token", params: { token: "<token>" })
}
Verify Authentication
The way to check if a user has been successfully authenticated is identical, with the exception that verifyAuthentication
returns a boolean
instead of a LoginResult
:
mutation Verify {
verifyAuthentication(
serviceName: "password"
params: { password: "<pw>", user: { email: "<email>" } }
)
}
This will return a result similar to this, if your user has been successfully authenticated:
{
"data": {
"verifyAuthentication": true
}
}