Skip to content

Instantly share code, notes, and snippets.

@craicoverflow
Last active May 26, 2020 14:53
Show Gist options
  • Save craicoverflow/8c2631eda88771bff825700dad04bc3b to your computer and use it in GitHub Desktop.
Save craicoverflow/8c2631eda88771bff825700dad04bc3b to your computer and use it in GitHub Desktop.
Pseudo-prototype of new runtime API
import { GraphbackDataProvider, GraphbackPlugin } from "graphback"
import { DocumentNode, GraphQLSchema } from 'graphql'
import { IResolvers, PubSubEngine } from 'apollo-server-express'
import { PgKnexDBDataProvider } from '@graphback/runtime-knex'
import Knex from 'knex'
interface DataProviderModelMap {
[modelName: string]: GraphbackDataProvider
}
/**
* Graphback config that is define by the user in their API code.
*
* modelDefs:
* The input model that Graphback uses as input to create a GraphQL schema and resolvers
* schema:
* The schema if provided will be used instead of modelDefs.
* This is because schema can have more resolvers and other information
* resolvers:
* Supply your own resolvers and we will merge them with Graphback resolvers
* dataProviders:
* Provide your data providers with a mapping to your Model name
* Or provide one and it will be used for all
* pubSub:
* Provide your pubSub. This can be optional since users may not use subscriptions
* schemaPlugins:
* Users can provide an array of custom schema plugins
* They will be executed in the order they are in the array
*/
interface GraphbackConfig {
modelDefs?: DocumentNode | DocumentNode[] | string | string[]
schema?: GraphQLSchema
resolvers?: IResolvers | IResolvers[]
dataProviders: DataProviderModelMap | GraphbackDataProvider
pubSub?: PubSubEngine
schemaPlugins?: GraphbackPlugin[]
}
function makeGraphback(config: GraphbackConfig) {
// do some work and return generated stuff
return { typeDefs: '', resolvers: {}, dataSources: {} }
}
const db = Knex.Config()
const postgresProvider = new PgKnexDBDataProvider(db)
const { typeDefs, resolvers, dataSources } = makeGraphback({
modelDefs: `
"""
@model
"""
type Note {
id: ID!
title: String
}
`,
dataProviders: postgresProvider
})
@wtrocki
Copy link

wtrocki commented May 26, 2020

I typically see schema still being in the project as a file. WHY? because you need to see it to add your own resolvers. Then you merging graphback generated resolvers with your own resolvers and scalars and calling it a day.

const resolversBuilder = new MongoResolvers(...);
...
...
const apolloServer = new ApolloServer({
  typeDefs: schemaString,
  resolvers: [resolversBuilder.getResolvers(), resolversBuilder.getScalars(), myresolvers]

});

@craicoverflow
Copy link
Author

craicoverflow commented May 26, 2020

I typically see schema still being in the project as a file. WHY? because you need to see it to add your own resolvers.

So we would still need two steps in this case?

  1. Run graphback to generate schema file.
  2. run server and load schema string from file into GraphbackResolvers to build resolver context.

This might still be achievable without the need for a file if MongoResolvers actually wraps full runtime implementation and gives you everything:

const graphbackBuilder = new GraphbackResolvers({model, crudService, dbProvider});
resolvers.setDataSource('Note', customDbProvider);

const { schemaSDL, resolvers } = graphbackBuilder.build();

// 1. Execute schema plugins
// 2. Build resolvers with data sources from builder
// 3. Output built schema with resolvers

const apolloServer = new ApolloServer({
  typeDefs: schemaSDL,
  resolvers
});

@wtrocki
Copy link

wtrocki commented May 26, 2020

We will give developers much more than just black box schema and resolvers. They can add this to their project etc.
Plus we actually giving developers starter templates - others do not provide that.

Our templates can ignore the fact of the custom schema/generated one, but people could still generate schema and work with it.
Like if we target to provide single method thing let's:

  • Kill templates
  • Kill services and datasources

Have 2 methods - createMongo and createPostgres, but that is not going to work for us as we need to have more integrations that sometimes will exclude each other.

https://graphql-mesh.com is another good example how those guys resolved similar problem - worth checking their api

@craicoverflow
Copy link
Author

Fair points

graphql-mesh.com is another good example how those guys resolved similar problem - worth checking their api

Their docs are incomplete, I only see YAML configs.

@craicoverflow
Copy link
Author

We will give developers much more than just black box schema and resolvers. They can add this to their project etc.

True, but developers want simplicity and should be able to start with a miminal config API, adding more if they need it.

Plus we actually giving developers starter templates - others do not provide that.

The fewer starter templates we provide, the better in a way. Shouldn't starter templates focus on the non-Graphback elements of the application, like Apollo versus GrahQL.js, Mongo versus Postgres, how developers organise their architecture (we could have a GraphQL modules template).

If we need to have a template for very specific differences in Graphback API it might mean that the API is too difficult to make simple changes without having to change it all?

@craicoverflow
Copy link
Author

craicoverflow commented May 26, 2020

We could combine both approaches, where the resolver building would still be abstracted into the API:

interface GraphbackConfig {
  schema: GraphQLSchema
  resolvers?: ResolverBuilder | ResolverBuilder[]
  pubSub?: PubSubEngine
  schemaPlugins?: GraphbackPlugin[]
}

const modelSchema = buildSchema(`
"""
@model
"""
type Note {
  id: ID!
  title: String
}
`)

const resolverBuilder = new PostgresResolverBuilder(modelSchema, {})

// very minimal Graphback configuration
const { schema, resolvers, dataSources } = makeGraphback({
  schema: modelSchema,
  resolvers: [resolverBuilder] // accepts multiple resolver builders and merges them after doing the building, making it easy to mix data sources
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment