Using multiple GraphQL servers with one, shared service

prisma

#1

Hello Prisma forum! :slightly_smiling_face:

I’m fairly new to Prisma ecosystem and I’m just trying it out and checking if it can be a fit for a project I’m working on. So far I’ve played around with graphql-yoga and prisma-bindings and I love how easy it is to have them working together. Great stuff!

For the upcoming project my infrastructure will consist of two different server side API’s with different business logic. However, both of them will be connected to one dataset with same data. What I would imagine would be the solution is to create two graphql-yoga servers, connect them through prisma-bindings to 1 service = profit!

As far as I understand I have to have prisma-binding’s for each API, which means I need to maintain data models + database schema in both API’s. Obviously, it’s not ideal and co go out of sync very quickly and preferable solution would be to extract that somehow.

Is there any tool or approach which could help me maintaining one database schema which then i could connect two different API’s?

Thanks in advance!


#2

Hey @wojciech and welcome to the Prisma Forum :wave:

You can connect many GraphQL Yoga servers to the same Prisma API.
Whenever you change the datamodel of your Prisma service, you need to regenerate the Prisma bindings that is used in your GraphQL Yoga servers.

You can run graphql get-schema and/or graphql codegen to do so. Here is a simple example that uses post deployment hooks to run these commands: https://github.com/prismagraphql/prisma/tree/master/examples/hooks

You don’t have to use hooks, you can also run the commands directly.
You will need to adjust the example to your setup with multiple GraphQL Yoga servers :slight_smile:


#3

Hi @nilan, I’m sorry to follow up with a different but related question. Is it possible to connect one GraphQL Yoga server with multiple Prisma APIs? Thanks.


#4

Thanks @nilan, i didn’t know about the graphql get-schema and that could work. I just need to make sure that I have that in a flow somewhere so I wouldn’t have yoga servers out of sync. I would imagine that yoga servers would be in separate repositories so hooks on post-deploy wouldn’t work.


#5

Hey, sure that’s possible! Have a look at how a prisma-binding instance is usually hooked up to the GraphQL Yoga server. Here I’ll show the JavaScript case, it works a bit differently for TypeScript.

// 1
const db = new Prisma({
  typeDefs: 'src/generated/prisma.graphql',
  endpoint: process.env.PRISMA_ENDPOINT,
})

// 2
const server = new GraphQLServer({
  typeDefs: './src/schema.graphql',
  resolvers,
  context: req => ({ ...req, db }),
})

What happens here?

  1. We initialize an instance of prisma-binding using the Prisma constructor
    • We are passing in the endpoint where the queries will be sent to
    • and the type definitions from the previously generated schema prisma.graphql of the Prisma API.
  2. We initialize a new instance of graphql-yoga using the GraphQLServer constructor
    • We pass in the type definitions that we defined ourselves in schema.graphql,
    • the resolvers we implemented ourselves (with the help of prisma-binding),
    • and, now comes the interesting part, we attach the prisma-binding we created in 1. to the context of the request, using the db identifier (arbitrarily chosen in 1.).

So, how can we attach one or more Prisma bindings to the context?

Well, we repeat step 1. once for every Prisma API, and attach all Prisma bindings to the context in step 2. Quick example:

// 1a
const user-data = new Prisma({
  typeDefs: 'src/generated/user-data.graphql',
  endpoint: process.env.PRISMA_USER_DATA_ENDPOINT,
})

//1b
const email-data = new Prisma({
  typeDefs: 'src/generated/email-data.graphql',
  endpoint: process.env.PRISMA_EMAIL_DATA_ENDPOINT,
})

// 2
const server = new GraphQLServer({
  typeDefs: './src/schema.graphql',
  resolvers,
  context: req => ({ ...req, user-data, email-data }),
})

#6

Yes, that could be a post-commit hook on the version control level, or your CI environment. :slight_smile:


#7

thank you @nilan, this is totally the beauty of GraphQL and Prisma.


#8

Hi @nilan,
Could you elaborate on how you connect 2 Yoga servers to 1 Prisma service? I know you can regenerate the the Prisma bindings, but how can these be available for 2 Yoga servers?
Using git submodules or an external npm package?
Thank you


#9

Hi Michael,

EDIT: When falling asleep last night, I had an “oh no, your post doesn’t really answer Michael’s question. He wants to know how to run and regenerate prisma bindings, not stitch in another server.” However, the use cases are somewhat related, so I’ll leave this post up with the hopes that it helps someone out. :slight_smile:

It’s all set up in the Yoga server(s). I’m running a file server micro service, and here’s how it connects to my main gateway. You’ll note that mine is dynamically constructed at start up, but it’s generally recommended to have a static build (as Nilan mentioned with get schema hooks, but I don’t have a ready made example to show you)

const {
  makeRemoteExecutableSchema,
  introspectSchema,
  makeExecutableSchema,
} = require(`graphql-tools`)
const fetch = require(`node-fetch`)
const { HttpLink } = require(`apollo-link-http`)
const { resolvers, fragmentReplacements } = require(`./resolvers`)

....

const makeFileServiceLink = new HttpLink({
  uri: `http://...`,
  fetch
})

  const remoteSchema = makeRemoteExecutableSchema({
    schema: await introspectSchema(makeFileServiceLink),
    link: makeFileServiceLink
  })

  const fileServer = new Binding({
    schema: remoteSchema,
    fragmentReplacements
  })

...

const server = new GraphQLServer({
    schema,
    context: req => ({
      ...req,
      db,
      fileServer
    })
  })

Hopefully that helps!


#10

@LawJolla
That made me laugh out loud :laughing: . Your post did help me get a better insight to how Prisma works, thank you :wink:
In the end I have the right understanding on how prisma works as a service and it can be used for multiple API’s. At the moment I am sharing the prisma yaml file and datamodel between APIs and generating bindings per API.


#11

:rofl:

I’m about to be in your same boat (two APIs, one Prisma) and the question is a little more nuanced than it appears.

How are you sharing the YAML and data model files?


#12

I share the prisma YAML and datamodel in a monorepo, when I deploy prisma it will generate the bindings in each package. As you can see in my screenshot:
CloudApp


#13

Cool, thanks for the info! Good idea.

Thinking about this a little more clearly, you could have a repo with just the YAML and data model. Then point both servers at that Prisma endpoint.

Wouldn’t that work?


#14

Could you share some more on how you get this right? Where I’m falling off is with importing the typeDefs for generated and api graphql files.

How do you pull those typedefs in?


#15

Hi Nilan, could you elaborate a bit more on this way around? And what do you think of Michael1’s approach.

Right now this forum post seems to be the most authoritative resource on the web for Multiple yoga Servers one prisma Service architecture. If I find the “right” way I’ll volunteer to do a tutorial on it. :pray:


#16

when I created a new prism binding, I get an error message

const graphcms-db = new Prisma({
^^^^^^^^

SyntaxError: Missing initializer in const declaration


#18

const { GraphQLServer } = require(‘graphql-yoga’)
const { Prisma } = require(‘prisma-binding’)

const resolvers = require(’./resolvers’)

const commerceqldb = new Prisma({
typeDefs: ‘src/generated/prisma.graphql’,
endpoint: process.env.PRISMA_ENDPOINT,
debug: true
// secret: process.env.PRISMA_SECRET
})

//1b
const graphcmsdb = new Prisma({
typeDefs: ‘src/generated/graphcms.graphql’,
endpoint: process.env.GRAPHCMS_ENDPOINT,
})

const server = new GraphQLServer({
typeDefs: ‘./src/schema.graphql’,
resolvers,
context: req => ({ …req, commerceqldb, graphcmsdb })
})

server.start(() => console.log(‘Server is running on http://localhost:4000’))

I am not able to generate the typedefs for the headless graphql CMS, I keep getting a Graphql 404 error.

databaseCMS:
schemaPath: “src/generated/graphcms.graphql”
extensions:
endpoints:
master: “https://api-useast.graphcms.com/v1/cjiacyow100ob01eqwnghonw2/master
prisma: database/graphcms.yml

.graphqlconfig above


The endpoint to your Prisma API

endpoint: ${env:GRAPHCMS_ENDPOINT}

The data model

datamodel: datamodelCMS.graphql

This will download the GraphQL schema

into src/generated/prisma.graphql

hooks:
post-deploy:
- echo “Deployment finished”
- graphql get-schema --project databaseCMS
- graphql prepare

The secret is used to generate a JWT

for HTTP Authorization header requests

secret: ${env:PRISMA_SECRET}

graphcms.yml


#19

Please consider to open a new topic and provide the entire context, I cannot follow what you are saying :slight_smile:


#20

Hey @nilan. Could you give demo repo with this kind of approach? Current i’m trying to do this but i can’t reach how you do your graphqlconfig.yaml for instance.

I would like to understand how the same graph server can server different apis/db/prisma.

Here some examples that i’m doing, but a demo repo would be awesome.

Or if @Michael1 could point me how is doing is approach would be great.

Many thanks.


#21

And i’m able to deploy one but the second one got errors: