GraphQL är databasagnostisk, så du kan använda vad du normalt använder för att interagera med databasen och använda frågans eller mutationens resolve
metod för att anropa en funktion du har definierat som ska hämta/lägga till något i databasen.
Utan relä
Här är ett exempel på en mutation som använder den löftesbaserade Knex SQL-frågebyggaren, först utan Relay för att få en känsla för konceptet. Jag kommer att anta att du har skapat en userType i ditt GraphQL-schema som har tre fält:id
, username
och created
:allt krävs och att du har en getUser
redan definierad funktion som frågar databasen och returnerar ett användarobjekt. I databasen har jag även ett password
kolumn, men eftersom jag inte vill att det ska frågas utelämnar jag det från 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,
})
),
},
}),
});
Eftersom Postgres skapar id
för mig och jag beräknar den created
tidsstämpel, jag behöver dem inte i min mutationsfråga.
The Relay Way
Använder hjälparna i graphql-relay
och att hålla mig ganska nära Relay Starter Kit hjälpte mig, för det var mycket att ta in på en gång. Relay kräver att du ställer in ditt schema på ett specifikt sätt så att det kan fungera korrekt, men tanken är densamma:använd dina funktioner för att hämta från eller lägga till i databasen i lösningsmetoderna.
En viktig varning är att reläsättet förväntar sig att objektet returneras från getUser
är en instans av en klass User
, så du måste ändra getUser
för att tillgodose det.
Det sista exemplet med Relay (fromGlobalId
, globalIdField
, mutationWithClientMutationId
och nodeDefinitions
är alla från 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),
},
}),
});