1 | # @accounts/graphql-api
|
2 |
|
3 | _Schema, Resolvers and Utils for GraphQL server with JSAccounts_
|
4 |
|
5 | [![npm](https://img.shields.io/npm/v/@accounts/graphql-api.svg?maxAge=2592000)](https://www.npmjs.com/package/@accounts/graphql-api)
|
6 | ![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)
|
7 |
|
8 | > 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!
|
9 |
|
10 | ## How to use this package?
|
11 |
|
12 | This package exports GraphQL schema and GraphQL resolvers, which you can extend with your existing GraphQL schema server.
|
13 |
|
14 | Start by installing it from NPM / Yarn:
|
15 |
|
16 | ```bash
|
17 | // Npm
|
18 | npm install --save @accounts/server @accounts/graphql-api @graphql-modules/core
|
19 |
|
20 | // Yarn
|
21 | yarn add @accounts/server @accounts/graphql-api @graphql-modules/core
|
22 | ```
|
23 |
|
24 | > This package does not create a transport or anything else, only schema and string and resolvers as object.
|
25 |
|
26 | Start by configuring your `AccountsServer` as you wish. For example, using MongoDB:
|
27 |
|
28 | ```js
|
29 | import mongoose from 'mongoose'
|
30 | import AccountsServer from '@accounts/server'
|
31 | import AccountsPassword from '@accounts/password'
|
32 | import MongoDBInterface from '@accounts/mongo'
|
33 |
|
34 | const db = mongoose.connection
|
35 |
|
36 | const password = new AccountsPassword()
|
37 |
|
38 | const accountsServer = new AccountsServer({
|
39 | {
|
40 | db: new MongoDBInterface(db),
|
41 | tokenSecret: 'SECRET',
|
42 | },
|
43 | {
|
44 | password,
|
45 | }
|
46 | });
|
47 | ```
|
48 |
|
49 | Next, import `AccountsModule` from this package, and run it with your `AccountsServer`:
|
50 |
|
51 | ```js
|
52 | import { AccountsModule } from '@accounts/graphql-api';
|
53 |
|
54 | const accountsGraphQL = AccountsModule.forRoot({
|
55 | accountsServer,
|
56 | });
|
57 | ```
|
58 |
|
59 | 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:
|
60 |
|
61 | ```js
|
62 | import { makeExecutableSchema } from 'graphql-tools';
|
63 | import { mergeGraphQLSchemas, mergeResolvers } from '@graphql-tools/epoxy';
|
64 |
|
65 | const typeDefs = [
|
66 | `
|
67 | type Query {
|
68 | myQuery: String
|
69 | }
|
70 |
|
71 | type Mutation {
|
72 | myMutation: String
|
73 | }
|
74 |
|
75 | schema {
|
76 | query: Query,
|
77 | mutation: Mutation
|
78 | }
|
79 | `,
|
80 | accountsGraphQL.typeDefs,
|
81 | ];
|
82 |
|
83 | let myResolvers = {
|
84 | Query: {
|
85 | myQuery: () => 'Hello',
|
86 | },
|
87 | Mutation: {
|
88 | myMutation: () => 'Hello',
|
89 | },
|
90 | };
|
91 |
|
92 | const schema = makeExecutableSchema({
|
93 | resolvers: mergeResolvers([accountsGraphQL.resolvers, myResolvers]),
|
94 | typeDefs: mergeGraphQLSchemas([typeDefs]),
|
95 | });
|
96 | ```
|
97 |
|
98 | 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:
|
99 |
|
100 | ```js
|
101 | app.use(
|
102 | GRAPHQL_ROUTE,
|
103 | bodyParser.json(),
|
104 | graphqlExpress((request) => {
|
105 | return {
|
106 | context: {
|
107 | ...accountsGraphQL(request),
|
108 | // your context
|
109 | },
|
110 | schema,
|
111 | };
|
112 | })
|
113 | );
|
114 | ```
|
115 |
|
116 | ## Authenticating Resolvers
|
117 |
|
118 | You can authenticate your own resolvers with `JSAccounts` authentication flow, by using `authenticated` method from this package.
|
119 |
|
120 | This method composer also extends `context` with the current authenticated user!
|
121 |
|
122 | This is an example for a protected mutation:
|
123 |
|
124 | ```js
|
125 | import AccountsServer from '@accounts/server';
|
126 | import { authenticated } from '@accounts/graphql-api';
|
127 |
|
128 | export const resolver = {
|
129 | Mutation: {
|
130 | updateUserProfile: authenticated(AccountsServer, (rootValue, args, context) => {
|
131 | // Write your resolver here
|
132 | // context.user - the current authenticated user!
|
133 | }),
|
134 | },
|
135 | };
|
136 | ```
|
137 |
|
138 | ## Customization
|
139 |
|
140 | This package allow you to customize the GraphQL schema and it's resolvers.
|
141 |
|
142 | 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.
|
143 |
|
144 | These are the available customizations:
|
145 |
|
146 | - `rootQueryName` (string) - The name of the root query, default: `Query`.
|
147 | - `rootMutationName` (string) - The name of the root mutation, default: `Mutation`.
|
148 | - `extend` (boolean) - whether to add `extend` before the root type declaration, default: `true`.
|
149 | - `withSchemaDefinition` (boolean): whether to add `schema { ... }` declaration to the generation schema, default: `false`.
|
150 |
|
151 | Pass a second object to `createAccountsGraphQL`, for example:
|
152 |
|
153 | Another possible customization is to modify the name of the authentication header, use it with `accountsContext` (the default is `Authorization`):
|
154 |
|
155 | ```js
|
156 | const myCustomGraphQLAccounts = AccountsModule.forRoot({
|
157 | accountsServer,
|
158 | rootQueryName: 'RootQuery',
|
159 | rootMutationName: 'RootMutation',
|
160 | headerName: 'MyCustomHeader',
|
161 | });
|
162 | ```
|
163 |
|
164 | ## Extending `User`
|
165 |
|
166 | 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:
|
167 |
|
168 | ```graphql
|
169 | extend type User {
|
170 | firstName: String
|
171 | lastName: String
|
172 | }
|
173 | ```
|
174 |
|
175 | And also implement a regular resolver, for the fields you added:
|
176 |
|
177 | ```js
|
178 | const UserResolver = {
|
179 | firstName: () => 'Dotan',
|
180 | lastName: () => 'Simha',
|
181 | };
|
182 | ```
|
183 |
|
184 | ## Extending `User` during password creation
|
185 |
|
186 | To extend the user object during the user creation you need to extend the `CreateUserInput` type and add your fields:
|
187 |
|
188 | ```graphql
|
189 | extend input CreateUserInput {
|
190 | profile: CreateUserProfileInput!
|
191 | }
|
192 |
|
193 | input CreateUserProfileInput {
|
194 | firstName: String!
|
195 | lastName: String!
|
196 | }
|
197 | ```
|
198 |
|
199 | The user will be saved in the db with the profile key set.
|