web-dev-qa-db-fra.com

Comment connecter GraphQL et PostgreSQL

GraphQL a des mutations, Postgres a INSERT; GraphQL a des requêtes, Postgres a SELECT; etc., etc. Je n'ai pas trouvé d'exemple montrant comment utiliser les deux dans un projet, par exemple en transmettant toutes les requêtes de front-end (React, Relay) dans GraphQL, mais dans un magasin pour stocker les données dans Postgres. 

Est-ce que quelqu'un sait ce que Facebook utilise comme base de données et comment il est connecté à GraphQL? 

La seule possibilité de stocker des données dans Postgres est de créer des "adaptateurs" personnalisés qui prennent la requête GraphQL et la convertissent en SQL?

35
Ska

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

Sans relais

Voici un exemple de mutation utilisant le constructeur de requêtes Knex SQL basé sur les promesses, d'abord sans Relay pour avoir une idée du concept. Je vais supposer que vous avez créé un type d'utilisateur dans votre schéma GraphQL comportant trois champs: id, username et created: all required, et que vous avez déjà une fonction getUser qui interroge la base de données et renvoie un objet utilisateur. Dans la base de données, j'ai aussi une colonne password, mais comme je ne veux pas interroger cela, je la laisse en dehors de ma 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 la id pour moi et que je calcule l’horodatage created, je n’en ai pas besoin dans ma requête de mutation.

La voie du relais

Utiliser les assistants dans graphql-relay et me rapprocher du Kit de démarrage du relais m'a aidé, car il y avait beaucoup à prendre en une fois. 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 soit une instance d'une classe User; vous devrez donc modifier getUser pour l'adapter à cela.

Le dernier exemple utilisant Relais (fromGlobalId, globalIdField, mutationWithClientMutationId et nodeDefinitions provient 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),
    },
  }),
});
26
Eric Streeper

Nous traitons ce problème dans Join Monster , une bibliothèque que nous avons récemment ouverte à une source pour traduire automatiquement les requêtes GraphQL en SQL en fonction de vos définitions de schéma.

17
Andy Carlson

Ce GraphQL Starter Kit peut être utilisé pour expérimenter avec GraphQL.js et PostgreSQL:

https://github.com/kriasoft/graphql-starter-kit - Node.js, GraphQL.js, PostgreSq

(disclaimer: je suis l'auteur)

8
Konstantin Tarkus

Consultez graphql-sequelize pour savoir comment travailler avec Postgres. 

Pour les mutations (créer/mettre à jour/supprimer), vous pouvez consulter les exemples dans le référentiel de relais par exemple.

4
Alex

Postgraphile https://www.graphile.org/postgraphile/ est une source ouverte

Créez rapidement des API GraphQL hautement personnalisables et ultra-rapides

PostGraphile est un outil à source ouverte pour vous aider à concevoir rapidement et servir une API GraphQL haute performance, sécurisée et orientée client, soutenue principalement par votre base de données PostgreSQL. Enchantez vos clients avec des performances incroyables tout en maintenant un contrôle total sur vos données et votre base de données. Utilisez notre puissant système de plugins pour personnaliser chaque fichier facette de votre API GraphQL à votre convenance.

0
Todd