GraphQL er databaseagnostisk, så du kan bruge det, du normalt bruger til at interagere med databasen, og bruge forespørgslen eller mutationens resolve
metode til at kalde en funktion, du har defineret, som vil få/føje noget til databasen.
Uden relæ
Her er et eksempel på en mutation, der bruger den løftebaserede Knex SQL-forespørgselsbygger, først uden Relay for at få en fornemmelse af konceptet. Jeg vil antage, at du har oprettet en userType i dit GraphQL-skema, der har tre felter:id
, username
, og created
:alt påkrævet, og at du har en getUser
funktion allerede defineret, som forespørger databasen og returnerer et brugerobjekt. I databasen har jeg også et password
kolonne, men da jeg ikke vil have det forespurgt, udelader jeg det fra min userType
.
// db.js
// take a user object and use knex to add it to the database, then return the newly
// created user from the db.
const addUser = (user) => (
knex('users')
.returning('id') // returns [id]
.insert({
username: user.username,
password: yourPasswordHashFunction(user.password),
created: Math.floor(Date.now() / 1000), // Unix time in seconds
})
.then((id) => (getUser(id[0])))
.catch((error) => (
console.log(error)
))
);
// schema.js
// the resolve function receives the query inputs as args, then you can call
// your addUser function using them
const mutationType = new GraphQLObjectType({
name: 'Mutation',
description: 'Functions to add things to the database.',
fields: () => ({
addUser: {
type: userType,
args: {
username: {
type: new GraphQLNonNull(GraphQLString),
},
password: {
type: new GraphQLNonNull(GraphQLString),
},
},
resolve: (_, args) => (
addUser({
username: args.username,
password: args.password,
})
),
},
}),
});
Siden Postgres opretter id
for mig og jeg beregner den created
tidsstempel, jeg har ikke brug for dem i min mutationsforespørgsel.
The Relay Way
Brug af hjælperne i graphql-relay
og det hjalp mig at holde mig ret tæt på Relay Starter Kit, for det var meget at tage ind på én gang. Relay kræver, at du opsætter dit skema på en bestemt måde, så det kan fungere korrekt, men ideen er den samme:Brug dine funktioner til at hente fra eller tilføje til databasen i løsningsmetoderne.
En vigtig advarsel er, at Relay-måden forventer, at objektet returneres fra getUser
er en forekomst af en klasse User
, så du bliver nødt til at ændre getUser
for at imødekomme det.
Det sidste eksempel ved hjælp af Relay (fromGlobalId
, globalIdField
, mutationWithClientMutationId
, og nodeDefinitions
er alle fra graphql-relay
):
/**
* We get the node interface and field from the Relay library.
*
* The first method defines the way we resolve an ID to its object.
* The second defines the way we resolve an object to its GraphQL type.
*
* All your types will implement this nodeInterface
*/
const { nodeInterface, nodeField } = nodeDefinitions(
(globalId) => {
const { type, id } = fromGlobalId(globalId);
if (type === 'User') {
return getUser(id);
}
return null;
},
(obj) => {
if (obj instanceof User) {
return userType;
}
return null;
}
);
// a globalId is just a base64 encoding of the database id and the type
const userType = new GraphQLObjectType({
name: 'User',
description: 'A user.',
fields: () => ({
id: globalIdField('User'),
username: {
type: new GraphQLNonNull(GraphQLString),
description: 'The username the user has selected.',
},
created: {
type: GraphQLInt,
description: 'The Unix timestamp in seconds of when the user was created.',
},
}),
interfaces: [nodeInterface],
});
// The "payload" is the data that will be returned from the mutation
const userMutation = mutationWithClientMutationId({
name: 'AddUser',
inputFields: {
username: {
type: GraphQLString,
},
password: {
type: new GraphQLNonNull(GraphQLString),
},
},
outputFields: {
user: {
type: userType,
resolve: (payload) => getUser(payload.userId),
},
},
mutateAndGetPayload: ({ username, password }) =>
addUser(
{ username, password }
).then((user) => ({ userId: user.id })), // passed to resolve in outputFields
});
const mutationType = new GraphQLObjectType({
name: 'Mutation',
description: 'Functions to add things to the database.',
fields: () => ({
addUser: userMutation,
}),
});
const queryType = new GraphQLObjectType({
name: 'Query',
fields: () => ({
node: nodeField,
user: {
type: userType,
args: {
id: {
description: 'ID number of the user.',
type: new GraphQLNonNull(GraphQLID),
},
},
resolve: (root, args) => getUser(args.id),
},
}),
});