PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comment connecter GraphQL et PostgreSQL

GraphQL est indépendant de la base de données, vous pouvez donc utiliser tout ce que vous utilisez normalement pour interagir avec la base de données et utiliser la requête ou la mutation resolve méthode pour appeler une fonction que vous avez définie qui obtiendra/ajoutera quelque chose à la base de données.

Sans relais

Voici un exemple de mutation utilisant le générateur de requêtes Knex SQL basé sur des promesses, d'abord sans relais pour avoir une idée du concept. Je vais supposer que vous avez créé un userType dans votre schéma GraphQL qui a trois champs :id , username , et created :tous requis, et que vous avez un getUser fonction déjà définie qui interroge la base de données et renvoie un objet utilisateur. Dans la base de données j'ai aussi un password colonne, mais comme je ne veux pas que cela soit interrogé, je le laisse en dehors de mon 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,
        })
      ),
    },
  }),
});

Puisque Postgres crée le id pour moi et je calcule le created horodatage, je n'en ai pas besoin dans ma requête de mutation.

La voie du relais

Utilisation des aides dans graphql-relay et rester assez près du kit de démarrage de relais m'a aidé, car il y avait beaucoup à assimiler en même temps. Relay vous oblige à configurer votre schéma d'une manière spécifique pour qu'il puisse fonctionner correctement, mais l'idée est la même :utilisez vos fonctions pour extraire ou ajouter à la base de données dans les méthodes de résolution.

Une mise en garde importante est que la méthode Relay s'attend à ce que l'objet renvoyé par getUser est une instance d'une classe User , vous devrez donc modifier getUser pour accommoder cela.

Le dernier exemple utilisant Relay (fromGlobalId , globalIdField , mutationWithClientMutationId , et nodeDefinitions proviennent tous de 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),
    },
  }),
});