如何连接GraphQL和PostgreSQL

问题描述 投票:0回答:9

GraphQL 有突变,Postgres 有 INSERT; GraphQL 有查询,Postgres 有 SELECT;我还没有找到一个示例来展示如何在项目中使用这两者,例如在 GraphQL 中传递来自前端(React、Relay)的所有查询,但实际上将数据存储在 Postgres 中。

有谁知道 Facebook 使用什么作为数据库以及它如何与 GraphQL 连接?

目前在 Postgres 中存储数据来构建接受 GraphQL 查询并将其转换为 SQL 的自定义“适配器”是唯一的选择吗?

postgresql graphql
9个回答
37
投票

GraphQL 与数据库无关,因此您可以使用通常用来与数据库交互的任何内容,并使用查询或突变的

resolve
方法来调用您定义的函数,该函数将获取/添加某些内容到数据库中。

无继电器

这里是使用基于 Promise 的 Knex SQL 查询构建器的突变示例,首先不使用 Relay 来感受这个概念。我假设您已经在 GraphQL 模式中创建了一个 userType,它具有三个字段:

id
username
created
:全部必需,并且您有一个
getUser
函数已经定义了哪些查询数据库并返回一个用户对象。在数据库中,我还有一个
password
列,但由于我不想查询该列,所以我将其保留在我的
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,
        })
      ),
    },
  }),
});

由于 Postgres 为我创建了

id
并且我计算了
created
时间戳,因此我在突变查询中不需要它们。

接力方式

使用

graphql-relay
中的助手并紧贴Relay Starter Kit 对我很有帮助,因为一次要吸收很多东西。 Relay 要求您以特定的方式设置模式,以便它可以正常工作,但想法是相同的:使用您的函数在解析方法中从数据库中获取或添加到数据库。

一个重要的警告是,Relay 方式期望从

getUser
返回的对象是类
User
的实例,因此您必须修改
getUser
来适应这一点。

使用 Relay 的最后一个示例(

fromGlobalId
globalIdField
mutationWithClientMutationId
nodeDefinitions
均来自
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),
    },
  }),
});

23
投票

我们在 Join Monster 中解决了这个问题,这是我们最近开源的一个库,可以根据您的架构定义自动将 GraphQL 查询转换为 SQL。


8
投票

这个 GraphQL 入门套件 可用于试验 GraphQL.js 和 PostgreSQL:

https://github.com/kriasoft/graphql-starter-kit - Node.js、GraphQL.js、PostgreSQL、Babel、Flow

(免责声明:我是作者)


5
投票

查看 graphql-sequelize 了解如何使用 Postgres。

对于突变(创建/更新/删除),您可以查看中继存储库中的示例


4
投票

Postgraphile https://www.graphile.org/postgraphile/ 是开源的

快速构建高度可定制、快如闪电的 GraphQL API

PostGraphile是一款开源工具,可帮助您快速设计和 提供高性能、安全、面向客户端的 GraphQL API 支持 主要由您的 PostgreSQL 数据库决定。让您的客户满意 令人难以置信的性能,同时保持对数据的完全控制 和你的数据库。使用我们强大的插件系统来定制每一个 根据您的喜好设置 GraphQL API 的各个方面。


0
投票

如果您使用 Javascript,则可以使用像 sequelize 这样的 ORM;如果您使用 Typescript,则可以使用 Typeorm


0
投票
为了扩展 Andy 和 Postgraphile 的响应,有几种工具可以为您自动生成 GraphQL API。其中一些支持其他功能,如访问控制、缓存等,以使该 API(和支持业务逻辑)可用于生产。这里列出其中一些:

  1. Supabase 及其用于 Postgres 的 pg_graphql
     扩展。
  2. Appsync及其对 RDS 的支持
  3. Hasura 及其 对 Postgres 和许多其他数据库的支持。

-6
投票
可能FB在后端使用mongodb或nosql。我最近阅读了一篇博客文章,其中解释了如何连接到 mongodb。基本上,您需要构建一个图形模型来匹配数据库中已有的数据。然后编写resolve、reject函数来告诉GQL在发布查询请求时如何表现。

参见

https://www.compose.io/articles/using-graphql-with-mongodb/


-6
投票
看看

SequelizeJS,它是一个基于 Promise 的 ORM,可以使用多种方言; PostgreSQL、MySQL、SQLite 和 MSSQL

以下代码直接从示例中提取

const Sequelize = require('sequelize'); const sequelize = new Sequelize('database', 'username', 'password', { host: 'localhost', dialect: 'mysql'|'sqlite'|'postgres'|'mssql', pool: { max: 5, min: 0, acquire: 30000, idle: 10000 }, // SQLite only storage: 'path/to/database.sqlite', // http://docs.sequelizejs.com/manual/tutorial/querying.html#operators operatorsAliases: false }); const User = sequelize.define('user', { username: Sequelize.STRING, birthday: Sequelize.DATE }); sequelize.sync() .then(() => User.create({ username: 'janedoe', birthday: new Date(1980, 6, 20) })) .then(jane => { console.log(jane.toJSON()); });
    
© www.soinside.com 2019 - 2024. All rights reserved.