55

GraphQL has mutations, Postgres has INSERT; GraphQL has queries, Postgres has SELECT's; etc., etc.. I haven't found an example showing how you could use both in a project, for example passing all the queries from front end (React, Relay) in GraphQL, but to a actually store the data in Postgres.

Does anyone know what Facebook is using as DB and how it's connected with GraphQL?

Is the only option of storing data in Postgres right now to build custom "adapters" that take the GraphQL query and convert it into SQL?

2
  • 3
    What about PostGraphQL ? Commented Nov 2, 2016 at 0:56
  • @Scott Looks neat Commented Nov 4, 2016 at 11:23

8 Answers 8

37

GraphQL is database agnostic, so you can use whatever you normally use to interact with the database, and use the query or mutation's resolve method to call a function you've defined that will get/add something to the database.

Without Relay

Here is an example of a mutation using the promise-based Knex SQL query builder, first without Relay to get a feel for the concept. I'm going to assume that you have created a userType in your GraphQL schema that has three fields: id, username, and created: all required, and that you have a getUser function already defined which queries the database and returns a user object. In the database I also have a password column, but since I don't want that queried I leave it out of my 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, }) ), }, }), }); 

Since Postgres creates the id for me and I calculate the created timestamp, I don't need them in my mutation query.

The Relay Way

Using the helpers in graphql-relay and sticking pretty close to the Relay Starter Kit helped me, because it was a lot to take in all at once. Relay requires you to set up your schema in a specific way so that it can work properly, but the idea is the same: use your functions to fetch from or add to the database in the resolve methods.

One important caveat is that the Relay way expects that the object returned from getUser is an instance of a class User, so you'll have to modify getUser to accommodate that.

The final example using Relay (fromGlobalId, globalIdField, mutationWithClientMutationId, and nodeDefinitions are all from 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), }, }), }); 
Sign up to request clarification or add additional context in comments.

2 Comments

Wouldn't that have to be async/await for addUser function? I'm talking about non relay way which I prefer.
First link in the "Relay Way" section goes to a deprecated repo.
23

We address this problem in Join Monster, a library we recently open-sourced to automatically translate GraphQL queries to SQL based on your schema definitions.

2 Comments

Is this also constructing tables or just querying them after you already have them - more like what PostgraphQL?
Just querying them after you already have them. The difference is that you still write your own API layer, rather than having the API automatically generated.
8

This GraphQL Starter Kit can be used for experimenting with GraphQL.js and PostgreSQL:

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

(disclaimer: I'm the author)

Comments

5

Have a look at graphql-sequelize for how to work with Postgres.

For mutations (create/update/delete) you can look at the examples in the relay repo for instance.

1 Comment

I wrote up this small article if you would like to have a tutorial style graphql-sequelize to follow through as exploration. medium.com/@leonyapkl/…
4

Postgraphile https://www.graphile.org/postgraphile/ is Open Source

Rapidly build highly customisable, lightning-fast GraphQL APIs

PostGraphile is an open-source tool to help you rapidly design and serve a high-performance, secure, client-facing GraphQL API backed primarily by your PostgreSQL database. Delight your customers with incredible performance whilst maintaining full control over your data and your database. Use our powerful plugin system to customise every facet of your GraphQL API to your liking.

Comments

0

You can use an ORM like sequelize if you're using Javascript or Typeorm if you're using Typescript

3 Comments

Please add further details to expand on your answer, such as working code or documentation citations.
@Irere Em12 I assume you're referring to the server-side code. Can you add that detail, and maybe a link to official documentation for an example ORM?
You can find the documentation for Typeorm Docs and for sequelize Docs also if you need resources on how to set it up i have github repo here Typeorm + Graphql
-6

Probably FB using mongodb or nosql in backend. I've recently read a blog entry which explain how to connect to mongodb. Basically, you need to build a graph model to match the data you already have in your DB. Then write resolve, reject function to tell GQL how to behave when posting a query request.

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

Comments

-6

Have a look at SequelizeJS which is a promise based ORM that can work with a number of dialects; PostgreSQL, MySQL, SQLite and MSSQL

The below code is pulled right from its example

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()); }); 

2 Comments

Where's GraphQL part in this answer?
This have nothing to do with the question, it's just bringing confusion...

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.