1 | # prisma-binding
|
2 |
|
3 | [![CircleCI](https://circleci.com/gh/prisma/prisma-binding.svg?style=shield)](https://circleci.com/gh/prisma/prisma-binding) [![npm version](https://badge.fury.io/js/prisma-binding.svg)](https://badge.fury.io/js/prisma-binding)
|
4 |
|
5 | GraphQL Binding for Prisma (using GraphQL schema delegation)
|
6 |
|
7 | > **Note**: Unless you explicitly want to use schema delegation we recommend to use [Prisma client](https://www.prisma.io/docs/prisma-client/) to build a GraphQL server [see tutorial](https://www.prisma.io/docs/get-started/03-build-graphql-servers-with-prisma-JAVASCRIPT-e001/).
|
8 |
|
9 | ## Overview
|
10 |
|
11 | `prisma-binding` provides a convenience layer for building GraphQL servers on top of Prisma services. In short, it simplifies implementing your GraphQL resolvers by _delegating_ execution of queries (or mutations) to the API of the underlying Prisma database service.
|
12 |
|
13 | Here is how it works:
|
14 |
|
15 | 1. Create your Prisma service by defining data model
|
16 | 1. Download generated database schema definition `prisma.graphql` (contains the full CRUD API)
|
17 | 1. Define your application schema, typically called `schema.graphql`
|
18 | 1. Instantiate `Prisma` with information about your Prisma service (such as its endpoint and the path to the database schema definition)
|
19 | 1. Implement the resolvers for your application schema by delegating to the underlying Prisma service using the generated delegate resolver functions
|
20 |
|
21 | ## Install
|
22 |
|
23 | ```sh
|
24 | yarn add prisma-binding
|
25 | # or
|
26 | npm install --save prisma-binding
|
27 | ```
|
28 |
|
29 | ## Example
|
30 |
|
31 | Consider the following data model for your Prisma service:
|
32 |
|
33 | ```graphql
|
34 | type User {
|
35 | id: ID! @unique
|
36 | name: String
|
37 | }
|
38 | ```
|
39 |
|
40 | If you instantiate `Prisma` based on this service, you'll be able to send the following queries/mutations:
|
41 |
|
42 | ```js
|
43 | // Instantiate `Prisma` based on concrete service
|
44 | const prisma = new Prisma({
|
45 | typeDefs: 'schemas/database.graphql',
|
46 | endpoint: 'https://us1.prisma.sh/demo/my-service/dev',
|
47 | secret: 'my-super-secret-secret'
|
48 | })
|
49 |
|
50 | // Retrieve `name` of a specific user
|
51 | prisma.query.user({ where: { id: 'abc' } }, '{ name }')
|
52 |
|
53 | // Retrieve `id` and `name` of all users
|
54 | prisma.query.users(null, '{ id name }')
|
55 |
|
56 | // Create new user called `Sarah` and retrieve the `id`
|
57 | prisma.mutation.createUser({ data: { name: 'Sarah' } }, '{ id }')
|
58 |
|
59 | // Update name of a specific user and retrieve the `id`
|
60 | prisma.mutation.updateUser({ where: { id: 'abc' }, data: { name: 'Sarah' } }, '{ id }')
|
61 |
|
62 | // Delete a specific user and retrieve the `id`
|
63 | prisma.mutation.deleteUser({ where: { id: 'abc' } }, '{ id }')
|
64 | ```
|
65 |
|
66 | Under the hood, each of these function calls is simply translated into an actual HTTP request against your Prisma service (using [`graphql-request`](https://github.com/prisma/graphql-request)).
|
67 |
|
68 | The API also allows to ask whether a specific node exists in your Prisma database:
|
69 |
|
70 | ```js
|
71 | // Ask whether a post exists with `id` equal to `abc` and whose
|
72 | // `author` is called `Sarah` (return boolean value)
|
73 | prisma.exists.Post({
|
74 | id: 'abc',
|
75 | author: {
|
76 | name: 'Sarah'
|
77 | }
|
78 | })
|
79 | ```
|
80 |
|
81 | ## API
|
82 |
|
83 | ### `constructor(options: PrismaOptions): Prisma`
|
84 |
|
85 | The `PrismaOptions` type has the following fields:
|
86 |
|
87 | | Key | Required | Type | Default | Note |
|
88 | | --- | --- | --- | --- | --- |
|
89 | | `typeDefs` | Yes | `string` | - | Type definition string or file path to the schema definition of your Prisma service (typically a file called `database.graphql` or `prisma.graphql`) |
|
90 | | `endpoint` | Yes | `string` | - | The endpoint of your Prisma service |
|
91 | | `secret` | Yes | `string` | - | The secret of your Prisma service |
|
92 | | `fragmentReplacements` | No | `FragmentReplacements` | `null` | A list of GraphQL fragment definitions, specifying fields that are required for the resolver to function correctly |
|
93 | | `debug` | No | `boolean` | `false` | Log all queries/mutations to the console |
|
94 |
|
95 | ### `query` and `mutation`
|
96 |
|
97 | `query` and `mutation` are public properties on your `Prisma` instance. They both are of type `Query` and expose a number of auto-generated delegate resolver functions that are named after the fields on the `Query` and `Mutation` types in your Prisma database schema.
|
98 |
|
99 | Each of these delegate resolvers in essence provides a convenience API for sending queries/mutations to your Prisma service, so you don't have to spell out the full query/mutation from scratch and worry about sending it over HTTP. This is all handled by the delegate resolver function under the hood.
|
100 |
|
101 | Delegate resolver have the following interface:
|
102 |
|
103 | ```js
|
104 | (args: any, info: GraphQLResolveInfo | string): Promise<T>
|
105 | ```
|
106 |
|
107 | The input arguments are used as follows:
|
108 |
|
109 | - `args`: An object carrying potential arguments for the query/mutation
|
110 | - `info`: An object representing the selection set of the query/mutation, either expressed directly as a string or in the form of `GraphQLResolveInfo` (you can find more info about the `GraphQLResolveInfo` type [here](http://graphql.org/graphql-js/type/#graphqlobjecttype))
|
111 |
|
112 | The generic type `T` corresponds to the type of the respective field.
|
113 |
|
114 | ### `exists`
|
115 |
|
116 | `exists` also is a public property on your `Prisma` instance. Similar to `query` and `mutation`, it also exposes a number of auto-generated functions. However, it exposes only a single function per type. This function is named according to the root field that allows the retrieval of a single node of that type (e.g. `User` for a type called `User`). It takes a `where` object as an input argument and returns a `boolean` value indicating whether the condition expressed with `where` is met.
|
117 |
|
118 | This function enables you to easily check whether a node of a specific type exists in your Prisma database.
|
119 |
|
120 | ### `request`
|
121 |
|
122 | The `request` method lets you send GraphQL queries/mutations to your Prisma service. The functionality is identical to the auto-generated delegate resolves, but the API is more verbose as you need to spell out the full query/mutation. `request` uses [`graphql-request`](https://github.com/graphcool/graphql-request) under the hood.
|
123 |
|
124 | Here is an example of how it can be used:
|
125 |
|
126 | ```js
|
127 | const query = `
|
128 | query ($userId: ID!){
|
129 | user(id: $userId) {
|
130 | id
|
131 | name
|
132 | }
|
133 | }
|
134 | `
|
135 |
|
136 | const variables = { userId: 'abc' }
|
137 |
|
138 | prisma.request(query, variables)
|
139 | .then(result => console.log(result))
|
140 | // sample result:
|
141 | // {"data": { "user": { "id": "abc", "name": "Sarah" } } }
|
142 | ```
|
143 |
|
144 | ### `forwardTo`
|
145 |
|
146 | If you just want to forward a query to the exact same underlying prisma query, you can use `forwardTo`:
|
147 |
|
148 | ```js
|
149 | const {forwardTo} = require('prisma-binding')
|
150 |
|
151 | const resolvers = {
|
152 | Query: {
|
153 | posts: forwardTo('db')
|
154 | }
|
155 | }
|
156 |
|
157 | const server = new GraphQLServer({
|
158 | typeDefs: './src/schema.graphql',
|
159 | resolvers,
|
160 | context: req => ({
|
161 | ...req,
|
162 | db: new Prisma({
|
163 | typeDefs: 'src/generated/prisma.graphql',
|
164 | endpoint: '...',
|
165 | secret: 'mysecret123',
|
166 | }),
|
167 | debug: true,
|
168 | }),
|
169 | })
|
170 |
|
171 | server.start(
|
172 | () => console.log(`Server is running on http://localhost:4000`),
|
173 | )
|
174 | ```
|
175 |
|
176 | <p align="center"><a href="https://oss.prisma.io"><img src="https://imgur.com/IMU2ERq.png" alt="Prisma" height="170px"></a></p>
|
177 |
|