graphql-santa v0.0.0-master.ede0727
Please beware that this is a PROTOTYPE. Do NOT use this for serious work. Thanks! 🎄graphql-santa
Introduction
graphql-santa is a GraphQL API framework. It takes a code-first approach (as opposed
to schema-first) and brings together a set of tools that provide robust type
safety so that if your app compiles, you have a much higher degree of confidence
than with vanilla JavaScript or just TypeScript.
graphql-santa brings Nexus, Prisma, Apollo Server and more together into a pluggable
system (in fact Prisma features are implemented as a plugin).
Get started
For this tutorial we will use postgres. Install it if needed and then get its connection URL. Check out our db setup guide if unsure.
Kick off a new project. Say yes (
y) to the prisma option. ChoosePostgreSQLfor the db option. Take a few moments to look around, poke things. But don't feel pressure to understand everything right away : )npx graphql-santa
Get a sense for db-to-api workflow
Our Hello World schema doesn't account for information about moons, lets change that.
Start by updating our data layer to model information about moons. We don't want to go crazy scientific here but a bit of modelling will serve us well. A world may have more than one moon, and a moon may have properites in its own right. So lets give moons a first class model representation. Then, we can connect them to their respective worlds:
model World { id Int @id name String @unique population Float + moons Moon[] } + model Moon { + id Int @id + name String + world World + }graphql-santareacts to changes in your Prisma schema. By saving the above, your dev database will be automatically migrated and photon regenerated. You literally now just move on to updating your GraphQL API.We have data about
Earthfrom before, but now we need to update it with information about its moon. Instead of working with photon inside one-off scripts, lets enhance our API and make the update as if a client app were.We're going to need to expose the
moonsworld field to clientsapp.objectType({ name: "World", definition(t) { t.model.id() t.model.name() t.model.population() + t.model.moons() } })Upon doing this however, we will see a warning in our dev mode logs:
Warning: Your GraphQL `World` object definition is projecting a field `moons` with `Moon` as output type, but `Moon` is not defined in your GraphQL Schema Warning: in /Users/jasonkuhrt/foobar/src/schema.ts:10:13 6 definition(t) { 7 t.model.id(); 8 t.model.name(); 9 t.model.population(); → 10 t.model.moons();The feedback is pretty clear already but to restate: The problem is that we're project a Prisma model field (
moons) that is a connection to another Prisma model (Moon) that has not been projected on our API layer. So let's do that now:+app.objectType({ + name:'Moon', + definition(t){ + t.model.id() + t.model.name() + t.model.world() + } +})Do not copy-paste. Instead type this out yourself and take note how autcompletion within the
definitionblock ont.modeleffectively guides you to success.Once you have projected
Moonfrom your data layer to your API layer, you will see that the dev mode warning and TypeScript error are now resolved. 🙌If you go to your GraphQL Playground now you will see that your GraphQL schema now contains your Moon data shape too. But of course we still need to update
Earthwith data about its moon. To achieve that we're going to expose CRUD actions that clients can use to updateEarth.+app.mutationType({ + definition(t){ + t.crud.updateOneWorld() + } +})Again do not copy-paste. Type this out and see how it feels. Notice how auto-completion guides you from start to finish.
If we go back to our schema in GraphQL Playground now, we'll see a significant number of additions to the schema, a result of the CRUD features we've just enabled.
Now, let's give
Earthits moon!mutation addMoonToEarth { updateOneWorld( where: { name: "Earth" } data: { moons: { create: { name: "moon" } } } ) { name moons { name } } }You should see a result like:
{ "data": { "updateOneWorld": { "name": "Earth", "moons": [ { "name": "moon" } ] } } }Deploy to Heroku
For this step, create an account at Heroku and setup the CLI.
- Create a new app:
heroku apps:create - Attach your project to the app:
heroku git:remote --app <app-name> - Add a postgres database to it:
heroku addons:create heroku-postgresql --app <app-name> - Get the postgres database credentials:
heroku pg:credentials:url --app <app-name> - Initialize the postgres database:
npx graphql-santa db init --connection-url <connection-url> - Deploy using the git push to master workflow. See your app running in the cloud!
- Create a new app:
Conclusion
Hopefully that gives you a taste of the power under your finger tips. There's a ton more to discover. Happy coding! 🙌
Guide
Adding Prisma
Overview
Prisma Framework is a next-generation developer-centric tool chain focused on making the data layer easy. In turn, graphql-santa makes it easy to integrate Prisma Framework into your app. You opt-in by creating a schema.prisma file somewhere in your project. Then, the following things automatically happen:
- graphql-santa CLI workflows are extended: db, dev, build
- On build, Prisma generators are run
- During dev, Prisma generators are run after prisma schema file changes
dbcommand becomes powered byprisma2 lift
- The
nexus-prismaNexus plugin is automatically used. This you get access tot.modelandt.crud. - An instance of the generated Photon.JS client is a added to context under
photonproperty - The TypeScript types representing your Prisma models are registered as a Nexus data source. In short this enables proper typing of
parentparameters in your resolves. They reflect the data of the correspondingly named Prisma model.
Example
Install the prisma plugin:
npm install graphql-santa-plugin-prismaAdd a schema.prisma file and fill it out with some content
mkdir -p prisma
touch prisma/schema.prisma// prisma/schema.prisma
datasource db {
provider = "sqlite"
url = "file:dev.db"
}
model User {
id Int @id
name String
}Enter dev mode:
npx graphql-santa devThe following shows an example of transitioning your API codebase to use the extensions brought on by the Prisma extension.
Using the model DSL:
objectType({
name: 'User',
definition(t) {
- t.id('id)
- t.string('name')
+ t.model.id()
+ t.model.name()
},
})Using the photon instance on ctx:
queryType({
definition(t) {
t.list.field('users', {
type: 'User',
- resolve() {
- return [{ id: '1643', name: 'newton' }]
+ resolve(_root, _args, ctx) {
+ return ctx.photon.users.findMany()
},
})
},
})Databases
Setup a local PostgreSQL
The reccommended way to run postgres locally is with docker, because it is easy flexible and reliable.
Start a postgres server for your app:
docker run --detach --publish 5432:5432 --name 'myapp-db' --env POSTGRES_PASSWORD=postgres postgresNow you can use a connection URL like:
postgresql://postgres:postgres@localhost:5432/myapp
If you don't want to use a docker, here are some links to alternative approaches:
Going to Proudction
Once you're ready to go to production just build your app and run the start module with node.
$ npx graphql-santa build$ node node_modules/.buildHeroku
"scripts": {
"build": "graphql-santa build",
"start": "node node_modules/.build"
}Conventions
schema.ts | schema/*
Optional –– Your GraphQL type definitions.
About
It can be a single module or folder of modules. Multiple instances of module/folder-modules throughout your source tree is supported.
In dev mode schema modules are synchronously found and imported at server boot time. At build time however static imports for all schema modules are inlined for boot performance.
Aliases
n/a
app.ts
Optional –– The entrypoint to your app
About
There can only be at most a single app.ts/server.ts/service.ts module in your source tree.
This module is optional when you just have schema modules and so graphql-santa already knows how import them into the final build. Otherwise you'll need this module to import your custom modules etc.
Aliases
server.ts service.tsExample Layouts
Nothing!
Nano
schema.tsMicro
app.ts
schema.tsBasic
app/
server.ts
schema.ts
prisma/
schema.prismaAPI
app
A singleton graphql-santa app. Use this to build up your GraphQL schema and configure your server.
Example
// schema.ts
import { app } from 'graphql-santa'
app.objectType({
name: 'Foo',
definition(t) {
t.id('id')
},
})app.addToContext
Add context to your graphql resolver functions. The objects returned by your context contributor callbacks will be shallow-merged into ctx. The ctx type will also accurately reflect the types you return from callbacks passed to addToContext.
Example
// app.ts
import { app } from 'graphql-santa'
app.addToContext(req => {
return {
foo: 'bar',
}
})
app.objectType({
name: 'Foo',
definition(t) {
t.string('foo', (_parent, _args, ctx) => ctx.foo)
},
})app.<nexusDefBlock>
Add types to your GraphQL Schema. The available nexus definition block functions include objectType inputObjectType enumType and so on. Refer to the official Nexus API documentation for more information about these functions.
Example
// schema.ts
import { app } from 'graphql-santa'
app.objectType({
name: 'Foo',
definition(t) {
t.id('id')
},
})app.server.start
Start the server. If you don't call this graphql-santa will. Usually you should not have to call it. Please share your use-case with us if you do!
CLI
Development
Overview
yarn
yarn test
yarn devTesting
Integration tests rely on npm link. This means those integration tests cannot
work on a machine that has not done npm link inside the root of the cloned
repo.
The reason we do not use yarn link is that yarn does not symlink the bin into
local node_modules.
Working With Example Apps via Linking
Refer to https://github.com/prisma-labs/graphql-santa-examples
Working with create command
In any example you can use this workflow:
rm -rf test-create && mcd test-create && ../node_modules/.bin/graphql-santa create6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago