diff --git a/docs/1.1/01-Quickstart/01-Backend/01-TypeScript/01-TypeScript.md b/docs/1.1/01-Quickstart/01-Backend/01-TypeScript/01-TypeScript.md new file mode 100644 index 0000000000..7f825ae04c --- /dev/null +++ b/docs/1.1/01-Quickstart/01-Backend/01-TypeScript/01-TypeScript.md @@ -0,0 +1,292 @@ +--- +alias: rohd6ipoo4 +description: Get started with in 5 min Prisma and TypeScript by building a GraphQL backend and deploying it with Docker +github: https://github.com/graphql-boilerplates/typescript-graphql-server/tree/master/basic +--- + +# TypeScript Prisma Quickstart + +In this quickstart tutorial, you'll learn how to build a GraphQL server with TypeScript. You will use [`graphql-yoga`](https://github.com/graphcool/graphql-yoga/) as your web server which is connected to a "GraphQL database" using [`prisma-binding`](https://github.com/graphcool/prisma-binding). + +> The code for this project can be found as a _GraphQL boilerplate_ project on [GitHub](https://github.com/graphql-boilerplates/typescript-graphql-server/tree/master/basic). + +## Step 1: Install required command line tools + +Throughout the course of this tutorial, you'll use the Prisma CLI to create and manage your Prisma database service. So, the first step is to install the CLI. + + + +Open your terminal and globally install the Prisma CLI: + +```sh +npm install -g prisma +``` + + + +You also need to have [Docker](https://www.docker.com/) installed on your machine. + + + +If you don't have Docker installed on your machine yet, go and download it now from the official website: + +- [Mac OS](https://www.docker.com/docker-mac) +- [Windows](https://www.docker.com/docker-windows) + + + +After it's downloaded, you can install it right away. Note that this also gives you access to the `docker` CLI. + +## Step 2: Bootstrap your GraphQL server + +Now you can use `prisma init` to bootstrap your GraphQL server. Note that this command will trigger an interactive prompt that allows to select a template your project should be based on. + + + +Because you're passing `my-app` as an argument to `prisma init`, the Prisma CLI will create a new directory called `my-app` where it will place all the files for your project: + +```sh +prisma init my-app +``` + + + + + +When prompted how you want to set up your Prisma service, choose `GraphQL server/fullstack boilerplate (recommended)`. + + + + + +The CLI now prompts you to select a [GraphQL boilerplate](https://github.com/graphql-boilerplates) as foundation for your project. Select the [`typescript-basic`](https://github.com/graphql-boilerplates/typescript-graphql-server/tree/master/basic) boilerplate here. + + + + + +Finally, when prompted which cluster you want to deploy to, choose the `local` cluster. + + + +After `prisma init` has finished, your Prisma database service is deployed and will be accessible under [`http://localhost:4466/my-app/dev`](http://localhost:4466/my-app/dev). + +As you might recognize, the HTTP endpoint for the database service is composed of the following components: + +- The **cluster's domain** (specified as the `host` property in `~/.prisma/config.yml`): `http://localhost:4466/my-app/dev` +- The **name** of the Prisma `service` specified in `prisma.yml`: `my-app` +- The **stage** to which the service is deployed, by default this is calleds: `dev` + +Note that the endpoint is referenced in `src/index.ts`. There, it is used to instantiate `Prisma` in order to create a binding between the application schema and the Prisma schema: + +```ts(path="src/index.ts"&nocopy) +const server = new GraphQLServer({ + typeDefs: './src/schema.graphql', // points to the application schema + resolvers, + context: req => ({ + ...req, + db: new Prisma({ + endpoint: 'http://localhost:4466/my-app/dev', // the endpoint of the Prisma DB service + secret: 'mysecret123', // specified in `database/prisma.yml` + debug: true, // log all GraphQL queries & mutations + }), + }), +}) +``` + +Here's the file structure of the project: + +![](https://imgur.com/95faUsa.png) + +Let's investigate the generated files and understand their roles: + +- `/` (_root directory_) + - [`.graphqlconfig.yml`](https://github.com/graphql-boilerplates/typescript-graphql-server/tree/master/basic/.graphqlconfig.yml) GraphQL configuration file containing the endpoints and schema configuration. Used by the [`graphql-cli`](https://github.com/graphcool/graphql-cli) and the [GraphQL Playground](https://github.com/graphcool/graphql-playground). See [`graphql-config`](https://github.com/graphcool/graphql-config) for more information. +- `/database` + - [`database/prisma.yml`](https://github.com/graphql-boilerplates/typescript-graphql-server/tree/master/basic/database/prisma.yml): The root configuration file for your database service ([documentation](https://www.prismagraphql.com/docs/reference/prisma.yml/overview-and-example-foatho8aip)). + - [`database/datamodel.graphql`](https://github.com/graphql-boilerplates/typescript-graphql-server/tree/master/basic/database/datamodel.graphql) contains the data model that you define for the project (written in [SDL](https://blog.graph.cool/graphql-sdl-schema-definition-language-6755bcb9ce51)). We'll discuss this next. + - [`database/seed.graphql`](https://github.com/graphql-boilerplates/typescript-graphql-server/tree/master/basic/database/seed.graphql): Contains mutations to seed the database with some initial data. +- `/src` + - [`src/schema.graphql`](https://github.com/graphql-boilerplates/typescript-graphql-server/tree/master/basic/src/schema.graphql) defines your **application schema**. It contains the GraphQL API that you want to expose to your client applications. + - [`src/generated/prisma.graphql`](https://github.com/graphql-boilerplates/typescript-graphql-server/tree/master/basic/src/generated/prisma.graphql) defines the **Prisma schema**. It contains the definition of the CRUD API for the types in your data model and is generated based on your `datamodel.graphql`. **You should never edit this file manually**, but introduce changes only by altering `datamodel.graphql` and run `prisma deploy`. + - [`src/index.ts`](https://github.com/graphql-boilerplates/typescript-graphql-server/tree/master/basic/src/index.ts) is the entry point of your server, pulling everything together and starting the `GraphQLServer` from [`graphql-yoga`](https://github.com/graphcool/graphql-yoga). + +Most important for you at this point are `database/datamodel.graphql` and `src/schema.graphql`. `database/datamodel.graphql` is used to define your data model. This data model is the foundation for the API that's defined in `src/schema.graphql` and exposed to your client applications. + +Here is what the data model looks like: + +```graphql(path="database/datamodel.graphql") +type Post { + id: ID! @unique + isPublished: Boolean! + title: String! + text: String! +} +``` + +Based on this data model Prisma generates the **Prisma schema**, a [GraphQL schema](https://blog.graph.cool/graphql-server-basics-the-schema-ac5e2950214e) that defines a CRUD API for the types in your data model. This schema is stored in `src/generated/prisma.graphql` and will be updated by the CLI every time you [`deploy`](!alias-kee1iedaov) changes to your data model. + +You're now set to start the server! 🚀 + +## Step 4: Start the server + + + +Invoke the `dev` script that's defined in `package.json`. It will start the server and open a [GraphQL Playground](https://github.com/graphcool/graphql-playground) for you. + +```bash(path="") +cd my-app +yarn dev +``` + + + +Note that the Playground let's you interact with two GraphQL APIs side-by-side: + +- `app`: The web server's GraphQL API defined in the **application schema** (from `./src/schema.graphql`) +- `database`: The CRUD GraphQL API of the Prisma database service defined in the **Prisma schema** (from `./src/generated/prisma.graphql`) + +![](https://imgur.com/z7MWZA8.png) + +> Note that each Playground comes with auto-generated documentation which displays all GraphQL operations (i.e. queries, mutations as well as subscriptions) you can send to its API. The documentation is located on the rightmost edge of the Playground. + +Once the Playground opened, you can send queries and mutations. + +### Sending queries and mutations against the application schema + +The GraphQL API defined by your application schema (`src/schema.graphql`) can be accessed using the `app` Playground. + + + +Paste the following mutation into the left pane of the `app` Playground and hit the _Play_-button (or use the keyboard shortcut `CMD+Enter`): + +```grahpql +mutation { + createDraft( + title: "GraphQL is awesome!", + text: "It really is." + ) { + id + } +} +``` + + + +If you now send the `feed` query, the server will still return an empty list. That's because `feed` only returns `Post` nodes where `isPublished` is set to `true` (which is not the case for `Post` nodes that were created using the `createDraft` mutation). You can publish a `Post` by calling the `publish` mutation for it. + + + +Copy the `id` of the `Post` node that was returned by the `createDraft` mutation and use it to replace the `__POST_ID__` placeholder in the following mutation: + +```graphql +mutation { + publish(id: "__POST_ID__") { + id + isPublished + } +} +``` + + + + + +Now you can finally send the `feed` query and the published `Post` will be returned: + +```graphql +query { + feed { + id + title + text + } +} +``` + + + +### Sending queries and mutations against the Prisma API + +The GraphQL CRUD API defined by the Prisma schema (`src/generated/prisma.graphql`) can be accessed using the `database` Playground. + +As you're now running directly against the database API, you're not limited to the operations from the application schema any more. Instead, you can take advantage of full CRUD capabilities to directly create a _published_ `Post` node. + + + +Paste the following mutation into the left pane of the `database` Playground and hit the _Play_-button (or use the keyboard shortcut `CMD+Enter`): +` +```graphql +mutation { + createPost( + data: { + title: "What I love most about GraphQL", + text: "That it is declarative.", + isPublished: true + } + ) { + id + } +} +``` + + + +The `Post` node that was created from this mutation will already be returned by the `feed` query from the application schema since it has the `isPublished` field set to `true`. + +In the `database` Playground, you can also send mutations to _update_ and _delete_ existing posts. In order to do so, you must know their `id`s. + + + +Send the following query in the `database` Playground: + +```graphql +{ + posts { + id + title + } +} +``` + + + + + +From the returned `Post` nodes, copy the `id` of the one that you just created (where the `title` was `What I love most about GraphQL`) and use it to replace the `__POST_ID__` placeholder in the following mutation: + +```graphql +mutation { + updatePost( + where: { id: "__POST_ID__" }, + data: { text: "The awesome community." } + ) { + id + title + text + } +} +``` + + + +With this mutation, you're updating the `text` from `That it is declarative.` to `The awesome community.`. + + + +Finally, to delete a `Post` node, you can send the following mutation (where again `__POST_ID__` needs to be replaced with the actual `id` of a `Post` node): + +```graphql +mutation { + deletePost( + where: { id: "__POST_ID__" } + ) { + id + title + text + } +} +``` + + + diff --git a/docs/1.1/01-Quickstart/01-Backend/02-Node/01-Node.md b/docs/1.1/01-Quickstart/01-Backend/02-Node/01-Node.md new file mode 100644 index 0000000000..dfca8edf34 --- /dev/null +++ b/docs/1.1/01-Quickstart/01-Backend/02-Node/01-Node.md @@ -0,0 +1,292 @@ +--- +alias: phe8vai1oo +description: Get started with in 5 min Prisma and Node.js by building a GraphQL backend and deploying it with Docker +github: https://github.com/graphql-boilerplates/node-graphql-server/tree/master/basic +--- + +# Node.js Prisma Quickstart + +In this quickstart tutorial, you'll learn how to build a GraphQL server with Node.js. You will use [`graphql-yoga`](https://github.com/graphcool/graphql-yoga/) as your web server which is connected to a "GraphQL database" using [`prisma-binding`](https://github.com/graphcool/prisma-binding). + +> The code for this project can be found as a _GraphQL boilerplate_ project on [GitHub](https://github.com/graphql-boilerplates/node-graphql-server/tree/master/basic). + +## Step 1: Install required command line tools + +Throughout the course of this tutorial, you'll use the Prisma CLI to create and manage your Prisma database service. So, the first step is to install the CLI. + + + +Open your terminal and globally install the Prisma CLI: + +```sh +npm install -g prisma +``` + + + +You also need to have [Docker](https://www.docker.com/) installed on your machine. + + + +If you don't have Docker installed on your machine yet, go and download it now from the official website: + +- [Mac OS](https://www.docker.com/docker-mac) +- [Windows](https://www.docker.com/docker-windows) + + + +After it's downloaded, you can install it right away. Note that this also gives you access to the `docker` CLI. + +## Step 2: Bootstrap your GraphQL server + +Now you can use `prisma init` to bootstrap your GraphQL server. Note that this command will trigger an interactive prompt that allows to select a template your project should be based on. + + + +Because you're passing `my-app` as an argument to `prisma init`, the Prisma CLI will create a new directory called `my-app` where it will place all the files for your project: + +```sh +prisma init my-app +``` + + + + + +When prompted how you want to set up your Prisma service, choose `GraphQL server/fullstack boilerplate (recommended)`. + + + + + +The CLI now prompts you to select a [GraphQL boilerplate](https://github.com/graphql-boilerplates) as foundation for your project. Select the [`node-basic`](https://github.com/graphql-boilerplates/node-graphql-server/tree/master/basic) boilerplate here. + + + + + +Finally, when prompted which cluster you want to deploy to, choose the `local` cluster. + + + +After `prisma init` has finished, your Prisma database service is deployed and will be accessible under [`http://localhost:4466/my-app/dev`](http://localhost:4466/my-app/dev). + +As you might recognize, the HTTP endpoint for the database service is composed of the following components: + +- The **cluster's domain** (specified as the `host` property in `~/.prisma/config.yml`): `http://localhost:4466/my-app/dev` +- The **name** of the Prisma `service` specified in `prisma.yml`: `my-app` +- The **stage** to which the service is deployed, by default this is calleds: `dev` + +Note that the endpoint is referenced in `src/index.js`. There, it is used to instantiate `Prisma` in order to create a binding between the application schema and the Prisma schema: + +```js(path="src/index.js"&nocopy) +const server = new GraphQLServer({ + typeDefs: './src/schema.graphql', // points to the application schema + resolvers, + context: req => ({ + ...req, + db: new Prisma({ + typeDefs: 'src/generated/prisma.graphql', // points to the auto-generated Prisma DB schema + endpoint: 'http://localhost:4466/my-app/dev', // the endpoint of the Prisma DB service + secret: 'mysecret123', // specified in `database/prisma.yml` + debug: true, // log all GraphQL queries & mutations + }), + }), +}) +``` + +Here's the file structure of the project: + +![](https://imgur.com/95faUsa.png) + +Let's investigate the generated files and understand their roles: + +- `/` (_root directory_) + - [`.graphqlconfig.yml`](https://github.com/graphql-boilerplates/node-graphql-server/tree/master/basic/.graphqlconfig.yml) GraphQL configuration file containing the endpoints and schema configuration. Used by the [`graphql-cli`](https://github.com/graphcool/graphql-cli) and the [GraphQL Playground](https://github.com/graphcool/graphql-playground). See [`graphql-config`](https://github.com/graphcool/graphql-config) for more information. +- `/database` + - [`database/prisma.yml`](https://github.com/graphql-boilerplates/node-graphql-server/tree/master/basic/database/prisma.yml): The root configuration file for your database service ([documentation](!alias-foatho8aip)). + - [`database/datamodel.graphql`](https://github.com/graphql-boilerplates/node-graphql-server/tree/master/basic/database/datamodel.graphql) contains the data model that you define for the project (written in [SDL](https://blog.graph.cool/graphql-sdl-schema-definition-language-6755bcb9ce51)). We'll discuss this next. + - [`database/seed.graphql`](https://github.com/graphql-boilerplates/node-graphql-server/tree/master/basic/database/seed.graphql): Contains mutations to seed the database with some initial data. +- `/src` + - [`src/schema.graphql`](https://github.com/graphql-boilerplates/node-graphql-server/tree/master/basic/src/schema.graphql) defines your **application schema**. It contains the GraphQL API that you want to expose to your client applications. + - [`src/generated/prisma.graphql`](https://github.com/graphql-boilerplates/node-graphql-server/tree/master/basic/src/generated/prisma.graphql) defines the **Prisma schema**. It contains the definition of the CRUD API for the types in your data model and is generated based on your `datamodel.graphql`. **You should never edit this file manually**, but introduce changes only by altering `datamodel.graphql` and run `prisma deploy`. + - [`src/index.js`](https://github.com/graphql-boilerplates/node-graphql-server/tree/master/basic/src/index.js) is the entry point of your server, pulling everything together and starting the `GraphQLServer` from [`graphql-yoga`](https://github.com/graphcool/graphql-yoga). + +Most important for you at this point are `database/datamodel.graphql` and `src/schema.graphql`. `database/datamodel.graphql` is used to define your data model. This data model is the foundation for the API that's defined in `src/schema.graphql` and exposed to your client applications. + +Here is what the data model looks like: + +```graphql(path="database/datamodel.graphql") +type Post { + id: ID! @unique + isPublished: Boolean! + title: String! + text: String! +} +``` + +Based on this data model Prisma generates the **Prisma schema**, a [GraphQL schema](https://blog.graph.cool/graphql-server-basics-the-schema-ac5e2950214e) that defines a CRUD API for the types in your data model. This schema is stored in `/src/generated/prisma.graphql` and will be updated by the CLI every time you [`deploy`](!alias-kee1iedaov) changes to your data model. + +You're now set to start the server! 🚀 + +## Step 4: Start the server + + + +Invoke the `dev` script that's defined in `package.json`. It will start the server and open a [GraphQL Playground](https://github.com/graphcool/graphql-playground) for you. + +```bash(path="") +cd my-app +yarn dev +``` + + + +Note that the Playground let's you interact with two GraphQL APIs side-by-side: + +- `app`: The web server's GraphQL API defined in the **application schema** (from `./server/src/schema.graphql`) +- `database`: The CRUD GraphQL API of the Prisma database service defined in the **Prisma schema** (from `./server/src/generated/prisma.graphql`) + +![](https://imgur.com/z7MWZA8.png) + +> Note that each Playground comes with auto-generated documentation which displays all GraphQL operations (i.e. queries, mutations as well as subscriptions) you can send to its API. The documentation is located on the rightmost edge of the Playground. + +Once the Playground opened, you can send queries and mutations. + +### Sending queries and mutations against the application schema + +The GraphQL API defined by your application schema (`src/schema.graphql`) can be accessed using the `app` Playground. + + + +Paste the following mutation into the left pane of the `app` Playground and hit the _Play_-button (or use the keyboard shortcut `CMD+Enter`): + +```grahpql +mutation { + createDraft( + title: "GraphQL is awesome!", + text: "It really is." + ) { + id + } +} +``` + + + +If you now send the `feed` query, the server will still return an empty list. That's because `feed` only returns `Post` nodes where `isPublished` is set to `true` (which is not the case for `Post` nodes that were created using the `createDraft` mutation). You can publish a `Post` by calling the `publish` mutation for it. + + + +Copy the `id` of the `Post` node that was returned by the `createDraft` mutation and use it to replace the `__POST_ID__` placeholder in the following mutation: + +```graphql +mutation { + publish(id: "__POST_ID__") { + id + isPublished + } +} +``` + + + + + +Now you can finally send the `feed` query and the published `Post` will be returned: + +```graphql +query { + feed { + id + title + text + } +} +``` + + + +### Sending queries and mutations against the Prisma API + +The GraphQL CRUD API defined by the Prisma schema (`/src/generated/prisma.graphql`) can be accessed using the `database` Playground. + +As you're now running directly against the database API, you're not limited to the operations from the application schema any more. Instead, you can take advantage of full CRUD capabilities to directly create a _published_ `Post` node. + + + +Paste the following mutation into the left pane of the `database` Playground and hit the _Play_-button (or use the keyboard shortcut `CMD+Enter`): + +```graphql +mutation { + createPost( + data: { + title: "What I love most about GraphQL", + text: "That it is declarative.", + isPublished: true + } + ) { + id + } +} +``` + + + +The `Post` node that was created from this mutation will already be returned by the `feed` query from the application schema since it has the `isPublished` field set to `true`. + +In the `database` Playground, you can also send mutations to _update_ and _delete_ existing posts. In order to do so, you must know their `id`s. + + + +Send the following query in the `database` Playground: + +```graphql +{ + posts { + id + title + } +} +``` + + + + + +From the returned `Post` nodes, copy the `id` of the one that you just created (where the `title` was `What I love most about GraphQL`) and use it to replace the `__POST_ID__` placeholder in the following mutation: + +```graphql +mutation { + updatePost( + where: { id: "__POST_ID__" }, + data: { text: "The awesome community." } + ) { + id + title + text + } +} +``` + + + +With this mutation, you're updating the `text` from `That it is declarative.` to `The awesome community.`. + + + +Finally, to delete a `Post` node, you can send the following mutation (where again `__POST_ID__` needs to be replaced with the actual `id` of a `Post` node): + +```graphql +mutation { + deletePost( + where: { id: "__POST_ID__" } + ) { + id + title + text + } +} +``` + + diff --git a/docs/1.1/01-Quickstart/02-Fullstack/01-React/01-Apollo.md b/docs/1.1/01-Quickstart/02-Fullstack/01-React/01-Apollo.md new file mode 100644 index 0000000000..ba5a8f21d6 --- /dev/null +++ b/docs/1.1/01-Quickstart/02-Fullstack/01-React/01-Apollo.md @@ -0,0 +1,222 @@ +--- +alias: tijghei9go +description: Get started in 5 min with [React](https://facebook.github.io/react/), [Apollo Client](https://github.com/apollographql/apollo-client) and [GraphQL](https://www.graphql.org) and learn how to build a simple Instagram clone. +github: https://github.com/graphql-boilerplates/react-fullstack-graphql/tree/master/basic +--- + +# React & Apollo Quickstart + +In this quickstart tutorial, you'll learn how to build a fullstack app with React, GraphQL and Node.js. You will use [`graphql-yoga`](https://github.com/graphcool/graphql-yoga/) as your web server which is connected to a "GraphQL database" using [`prisma-binding`](https://github.com/graphcool/prisma-binding). + +> The code for this project can be found as a _GraphQL boilerplate_ project on [GitHub](https://github.com/graphql-boilerplates/react-fullstack-graphql/tree/master/basic). + +## Step 1: Install required command line tools + +The first thing you need to do is install the command line tools you'll need for this tutorial: + +- `graphql-cli` is used initially to bootstrap the file structure for your fullstack app with `graphql create` +- `prisma` is used continuously to manage your Prisma database service + + + +```sh +npm install -g graphql-cli +``` + + + +> Note that you don't have to globally install the Prisma CLI as it's listed as a _development dependency_ in the boilerplate project you'll use. However, we still recommend that you install it. If you don't install it globally, you can invoke all `prisma` commands by prefixing them with `yarn`, e.g. `yarn prisma deploy` or `yarn prisma playground`. + +## Step 2: Bootstrap your React fullstack app + + + +Now you can use `graphql create` to bootstrap your project. With the following command, you name your project `my-app` and choose to use the `react-fullstack-basic` boilerplate: + +``` +graphql create my-app --boilerplate react-fullstack-basic +cd my-app +``` + +Feel free to get familiar with the code. The app contains the following React [`components`](https://github.com/graphql-boilerplates/react-fullstack-graphql/tree/master/basic/server/src/components): + +- `Post`: Renders a single post item +- `ListPage`: Renders a list of post items +- `CreatePage`: Allows to create a new post item +- `DetailPage`: Renders the details of a post item and allows to update and delete it + +Here is an overview of the generated files in the `server` directory and their roles in your server setup: + +- `/server` + - [`.graphqlconfig.yml`](https://github.com/graphql-boilerplates/react-fullstack-graphql/tree/master/basic/server/.graphqlconfig.yml) GraphQL configuration file containing the endpoints and schema configuration. Used by the [`graphql-cli`](https://github.com/graphcool/graphql-cli) and the [GraphQL Playground](https://github.com/graphcool/graphql-playground). See [`graphql-config`](https://github.com/graphcool/graphql-config) for more information. +- `/server/database` + - [`database/prisma.yml`](https://github.com/graphql-boilerplates/react-fullstack-graphql/tree/master/basic/server/database/prisma.yml): The root configuration file for your database service ([documentation](https://www.prismagraphql.com/docs/reference/prisma.yml/overview-and-example-foatho8aip)). + - [`database/datamodel.graphql`](https://github.com/graphql-boilerplates/react-fullstack-graphql/tree/master/basic/server/database/datamodel.graphql) contains the data model that you define for the project (written in [SDL](https://blog.graph.cool/graphql-sdl-schema-definition-language-6755bcb9ce51)). We'll discuss this next. + - [`database/seed.graphql`](https://github.com/graphql-boilerplates/react-fullstack-graphql/tree/master/basic/server/database/seed.graphql): Contains mutations to seed the database with some initial data. +- `/server/src` + - [`src/schema.graphql`](https://github.com/graphql-boilerplates/react-fullstack-graphql/tree/master/basic/server/src/schema.graphql) defines your **application schema**. It contains the GraphQL API that you want to expose to your client applications. + - [`src/generated/prisma.graphql`](https://github.com/graphql-boilerplates/react-fullstack-graphql/tree/master/basic/server/src/generated/prisma.graphql) defines the **Prisma schema**. It contains the definition of the CRUD API for the types in your data model and is generated based on your `datamodel.graphql`. **You should never edit this file manually**, but introduce changes only by altering `datamodel.graphql` and run `prisma deploy`. + - [`src/index.js`](https://github.com/graphql-boilerplates/react-fullstack-graphql/tree/master/basic/server/src/index.js) is the entry point of your server, pulling everything together and starting the `GraphQLServer` from [`graphql-yoga`](https://github.com/graphcool/graphql-yoga). + +Most important for you at this point are `database/datamodel.graphql` and `src/schema.graphql`. + +`database/datamodel.graphql` is used to define your data model. This data model is the foundation for the API that's defined in `src/schema.graphql` and exposed to your React application. + +Here is what the data model looks like: + +```graphql(path="server/database/datamodel.graphql") +type Post { + id: ID! @unique + createdAt: DateTime! + updatedAt: DateTime! + description: String! + imageUrl: String! +} +``` + +Based on this data model Prisma generates the **database schema**, a [GraphQL schema](https://blog.graph.cool/graphql-server-basics-the-schema-ac5e2950214e) that defines a CRUD API for the types in your data model. In your case, this is only the `Post` type. The database schema is stored in `database/schema.generated.graphql` and will be updated every time you [`deploy`](!alias-kee1iedaov) changes to your data model. + +## Step 3: Deploy the Prisma database service + +Before you can start the server, you first need to make sure your GraphQL database is available. You can do so by deploying the correspdonding Prisma service that's responsible for the database. + +In this case, you'll deploy the Prisma database service to the **free development cluster** of Prisma Cloud. Note that this cluster is not intended for production use, but rather for development and demo purposes. + +> Another option would be to deploy it locally with [Docker](https://www.docker.com/). You can follow the [Node.js Quickstart tutorial](!alias-phe8vai1oo) to learn how that works. + + + +Deploy the database service from the `server` directory of the project: + +```bash(path="") +cd server +prisma deploy +``` + + + + + +When prompted which cluster you want to deploy to, choose the `development` cluster from the **Prisma Cloud** section. + + + +> **Note**: If you haven't authenticated with the Prisma CLI before, this command is going to open up a browser window and ask you to login. Your authentication token will be stored in the global [`~/.prisma`](!alias-zoug8seen4). + +You Prisma database service is now deployed and accessible under [`http://prisma/my-app/dev`](http://prisma/my-app/dev). + +As you might recognize, the HTTP endpoint for the database service is composed of the following components: + +- The **cluster's domain** (specified as the `host` property in `~/.prisma/config.yml`): `http://localhost:4466/my-app/dev` +- The **name** of the Prisma service specified in `prisma.yml`: `my-app` +- The **stage** to which the service is deployed, by default this is calleds: `dev` + +Note that the endpoint is referenced in `server/src/index.js`. There, it is used to instantiate `Prisma` in order to create a binding between the application schema and the database schema: + +```js(path="src/index.js"&nocopy) +const server = new GraphQLServer({ + typeDefs: './src/schema.graphql', + resolvers, + context: req => ({ + ...req, + db: new Prisma({ + typeDefs: 'src/generated/prisma.graphql', + endpoint: '`http://localhost:4466/my-app/dev`', + secret: 'mysecret123', + }), + }), +}) +``` + +You're now set to start the server! 🚀 + +## Step 4: Start the server + + + +Execute the `start` script that's define in `server/package.json`: + +```bash(path="server") +yarn start +``` + + + +The server is now running on [http://localhost:4000](http://localhost:4000). + +## Step 5: Open a GraphQL playground to send queries and mutations + +Now that the server is running, you can use a [GraphQL Playground](https://github.com/graphcool/graphql-playground) to interact with it. + + + +Open a GraphQL Playground by executing the following command: + +```bash(path="server") +prisma playground +``` + + + +Note that the Playground let's you interact with two GraphQL APIs side-by-side: + +- `app`: The web server's GraphQL API defined in the **application schema** (from `./server/src/schema.graphql`) +- `database`: The CRUD GraphQL API of the Prisma database service defined in the **database schema** (from `./server/src/generated/prisma.graphql`) + +![](https://imgur.com/z7MWZA8.png) + +> Note that each Playground comes with auto-generated documentation which displays all GraphQL operations (i.e. queries, mutations as well as subscriptions) you can send to its API. The documentation is located on the rightmost edge of the Playground. + +Once the Playground opened, you can send queries and mutations. + + + +Paste the following mutation into the left pane of the `app` Playground and hit the _Play_-button (or use the keyboard shortcut `CMD+Enter`): + +```grahpql +mutation { + createPost( + description: "A rare look into the Prisma office" + imageUrl: "https://media2.giphy.com/media/xGWD6oKGmkp6E/200_s.gif" + ) { + id + } +} +``` + + + + + +To retrieve the `Post` node that was just created, you can send the following query in the `app` Playground: + +```graphql +{ + feed { + description + imageUrl + } +} +``` + + + + + +## Step 6: Launch the React application + +The last thing to do is actually launching the application 🚀 + + + +Install dependencies and run the app: + +```sh(path="server") +cd .. +yarn install +yarn start # open http://localhost:3000 in your browser +``` + + diff --git a/docs/1.1/01-Quickstart/03-Frontend/01-React/01-Apollo.md b/docs/1.1/01-Quickstart/03-Frontend/01-React/01-Apollo.md new file mode 100644 index 0000000000..b00f17eade --- /dev/null +++ b/docs/1.1/01-Quickstart/03-Frontend/01-React/01-Apollo.md @@ -0,0 +1,125 @@ +--- +alias: shaek6eina +description: Get started in 5 min with [React](https://facebook.github.io/react/), [Apollo Client](https://github.com/apollographql/apollo-client) and [GraphQL](https://www.graphql.org) and learn how to build a simple Instagram clone. +github: https://github.com/graphcool/frontend-examples/tree/master/react +--- + +# React & Apollo Quickstart + +In this quickstart tutorial, you'll learn how to connect your React app directly to a Prisma service. Note that this approach will only allow to perform CRUD operations on your data model. You won't be able to implement any custom business logic or other common features like authentication - if you need these features, see the corresponding [fullstack tutorial](!alias-tijghei9go). + +> The code for this project can be found on [GitHub](https://github.com/graphcool/frontend-examples/tree/master/react). + + + +Clone the example repository that contains the React application: + +```sh +git clone https://github.com/graphcool/frontend-examples.git +cd frontend-examples/react +``` + + + +Feel free to get familiar with the code. The app contains the following React [`components`](https://github.com/graphcool/frontend-examples/tree/master/react/src/components): + +- `Post`: Renders a single post item +- `ListPage`: Renders a list of post items +- `CreatePage`: Allows to create a new post item +- `DetailPage`: Renders the details of a post item and allows to update and delete it + +Prisma services are managed with the [Prisma CLI](https://github.com/graphcool/prisma/tree/master/cli). So before moving on, you first need to install it. + + + +Install the Prisma CLI: + +```sh +npm install -g prisma +``` + + + + + +Navigate to the `database` directory and deploy your service: + +```sh(path="") +cd database +prisma deploy +``` + + + + + +When prompted which cluster you want to deploy to, choose any of the _public cluster_ options (`prisma-eu1` or `prisma-us1`). + + + +> **Note**: If you haven't authenticated with the Prisma CLI before, this command is going to open up a browser window and ask you to login. + +You service is now deployed and available via the HTTP endpoint that was printed in the output of the command! The `Post` type is added to your data model and the corresponding CRUD operations are generated and exposed by the GraphQL API. + + + +Save the HTTP endpoint for the GraphQL API from the output of the `prisma deploy` command, you'll need it later! + + + +> **Note**: If you ever lose the endpoint for your GraphQL API, you can simply get access to it again by using the `prisma info` command. When using Apollo, you need to use the endpoint for the GraphQL API. + +You can test the API inside a [GraphQL Playground](https://github.com/graphcool/graphql-playground) which you can open with the `prisma playground` command. Feel free to try out the following query and mutation. + +**Fetching all posts:** + +```graphql +query { + allPosts { + id + description + imageUrl + } +} +``` + +**Creating a new post:** + +```graphql +mutation { + createPost( + description: "A rare look into the Prisma office" + imageUrl: "https://media2.giphy.com/media/xGWD6oKGmkp6E/200_s.gif" + ) { + id + } +} +``` + +![](https://imgur.com/w95UEi9.gif) + +The next step is to connect the React application with the GraphQL API from your Prisma service. + + + +Paste the HTTP endpoint for the GraphQL API that you saved after running `prisma deploy` into `./src/index.js` as the `uri` argument in the `HttpLink` constructor call: + +```js(path="src/index.js") +// replace `__API_ENDPOINT__` with the endpoint from the previous step +const httpLink = new HttpLink({ uri: '__API_ENDPOINT__' }) +``` + + + +That's it. The last thing to do is actually launching the application 🚀 + + + +Install dependencies and run the app: + +```sh(path="") +yarn install +yarn start # open http://localhost:3000 in your browser +``` + + diff --git a/docs/1.1/03-Tutorials/01-Prisma-Basics/01-Getting-Started.md b/docs/1.1/03-Tutorials/01-Prisma-Basics/01-Getting-Started.md new file mode 100644 index 0000000000..bbab13ba27 --- /dev/null +++ b/docs/1.1/03-Tutorials/01-Prisma-Basics/01-Getting-Started.md @@ -0,0 +1,259 @@ +--- +alias: ouzia3ahqu +description: Learn how to generate a GraphQL API for your database with Prisma. +--- + +# Getting started with Prisma + +In this tutorial, you'll learn how to get started with Prisma to generate a GraphQL API for your database. + +Here are the steps you're going to perform: + +- Install the Prisma CLI +- Bootstraping a Prisma service with `prisma init` +- Explore the API in a GraphQL Playground and send queries & mutations + +> To ensure you're not accidentally skipping an instruction in the tutorial, all required actions on your end are highlighted with a little counter on the left. +> +> **Pro tip**: If you're only keen on getting started but don't care so much about the explanations of what's going on, you can simply jump from instruction to instruction. + +## Installing the Prisma CLI + +Prisma services are managed with the [Prisma CLI](!alias-ieshoo5ohm). You can install it using `npm` (or `yarn`). + + + +Open your terminal and run the following command to install the Prisma CLI: + +``` +npm install -g prisma +# or +# yarn global add prisma +``` + + + +## Bootstraping a Prisma service + + + +Open a terminal and navigate to a folder of your choice. Then bootstrap your Prisma service with the following command: + +```sh +prisma init hello-world +``` + + + +This will create a new directory called `hello-world` as well as the two files which provide a minimal setup for your service: + +- [`prisma.yml`](!alias-foatho8aip): The root configuration file for your service. It contains information about your service, like the name (which is used to generate the service's HTTP endpoint), a secret to secure the access to the endpoint and about where it should be deployed. +- `datamodel.graphql` (can also be called differently, e.g. `types.graphql`): This file contains the definition of your [data model](!alias-eiroozae8u), written in [GraphQL SDL](https://blog.graph.cool/graphql-sdl-schema-definition-language-6755bcb9ce51). + +> **Note**: The `hello-world` directory actually contains a third file as well: `.graphqlconfig.yml`. This file follows the industry standard for configuring and structuring GraphQL projects (based on [`graphql-config`](https://github.com/graphcool/graphql-config)). If present, it is used by GraphQL tooling (such as the GraphQL Playground, the [`graphql-cli`](https://github.com/graphql-cli/graphql-cli/), text editors, build tools and others) to improve your local developer workflows. + +Let's take a look at the contents of the generated files: + +**`prisma.yml`** + +```yml +service: hello-world +stage: dev + +datamodel: datamodel.graphql + +# to enable auth, provide +# secret: my-secret +disableAuth: true +``` + +Here's an overview of the properties in the generated `prisma.yml`: + +- `service`: Defines the service name which will be part of the service's HTTP endpoint +- `stage`: A service can be deployed to multiple stages (e.g. a _development_ and a _production_ environment) +- `datamodel`: The path to the file which contains your data model +- `disableAuth`: If set to true, everyone who knows the endpoint of your Prisma service has full read and write access. If set to `false`, you need to specify a `secret` in `prisma.yml` which is used to generate JWT authentication tokens. These tokens need to be attached to the `Authorization` header of the requests sent to the API of your service. The easiest way to obtain such a token is the `prisma token` command from the Prisma CLI. + +> **Note**: We'll keep `disableAuth` set to `true` for this tutorial. In production applications, you'll always want to require authentication for your service! You can read more about this topic [here](!alias-pua7soog4v). + +**`datamodel.graphql`** + +```graphql +type User { + id: ID! @unique + name: String! +} +``` + +The data model contains type definitions for the entities in your application domain. In this case, you're starting out with a very simple `User` type with an `id` and a `name`. + +The `@unique` directive here expresses that no two users in the database can have the same `id`, Prisma will ensure this requirement is met at all times. + +## Deploying your Prisma service + +`prisma.yml` and `datamodel.graphql` are your abstract _service definition_. To actually create an instance of this service that can be invoked via HTTP, you need to _deploy_ it. + + + +Inside the `hello-world` directory in your terminal, run the following command: + +```sh +prisma deploy +``` + + + + + +Since `prisma.yml` doesn't yet contain the information about _where_ (meaning to which `cluster`) your service should be deployed, the CLI triggers a prompt for you to provide this information. At this point, you can choose to either deploy it locally with [Docker](https://www.docker.com) (which of course requires you to have Docker installed on your machine) or to a public Prisma cluster. You'll use a public cluster for the purpose of this tutorial. + + + +When prompted where (i.e. to which _cluster_) to deploy your Prisma service, choose one of the _public cluster_ options: `prisma-eu1` or `prisma-us1`. + + + +Your Prisma service is now deployed and ready to accept your queries and mutations 🎉 + +## Exploring your service in a GraphQL Playground + +So your service is deployed - but how do you know how to interact with it? What does its API actually look like? + +In general, the generated API allows to perform CRUD operations on the types in your data model. It also exposes GraphQL subscriptions which allow clients to _subscribe_ to certain _events_ and receive updates in realtime. + +It is important to understand that the data model is the foundation for your API. Every time you make changes to your data model, the GraphQL API gets updated accordingly. + +Because your datamodel contains the `User` type, the Prisma API now allows for its clients to create, read, update and delete instances, also called _nodes_, of that type. In particular, the following GraphQL operations are now generated based on the `User` type: + +- `user`: Query to retrieve a single `User` node by its `id` (or another `@unique` field). +- `users`: Query to retrieve a list of `User` nodes. +- `createUser`: Mutation to create a new `User` node. +- `updateUser`: Mutation to update an existing `User` node. +- `deleteUser`: Mutation to delete an existing `User` node. + +> **Note**: This list of generated operations is not complete. The Prisma API exposes a couple of more convenience operations that, for example, allow to batch update/delete many nodes. However, all operations either create, read, update or delete nodes of the types defined in the data model. + +To actually use these operations, you need a way to [send requests to your service's API](ohm2ouceuj). Since that API is exposed via HTTP, you could use tools like [`curl`](https://en.wikipedia.org/wiki/CURL) or [Postman](https://www.getpostman.com/) to interact with it. However, GraphQL actually comes with much nicer tooling for that purpose: [GraphQL Playground](https://github.com/graphcool/graphql-playground), an interactive GraphQL IDE. + + + +To open a GraphQL Playground, you can use the Prisma CLI again. Simply run the following command inside the `hello-world` directory: + +```sh +prisma playground +``` + + + +This will open a Playground looking as follows: + +![](https://imgur.com/HuJfglj.png) + +> **Note**: The Playground can be installed on your machine as a [standalone desktop application](https://github.com/graphcool/graphql-playground/releases). If you don't have the Playground installed, the command automatically opens a Playground in your default browser. + +One really cool property of GraphQL APIs is that they're effectively _self-documenting_. The [GraphQL schema](https://blog.graph.cool/graphql-server-basics-the-schema-ac5e2950214e) defines all the operations of an API, including input arguments and return types. This allows for tooling like the GraphQL Playground to auto-generate API documentation. + + + +To see the documentation for your service's API, click the green **SCHEMA**-button on the right edge of the Playground window. + + + +This brings up the Playground's documentation pane. The left-most column is a list of all the operations the API accepts. You can then drill down to learn the details about the input arguments or return types that are involved with each operation. + +![](https://imgur.com/l82HjFR.png) + +## Sending queries and mutations + +All right! With everything you learned so far, you're ready to fire off some queries and mutations against your API. Let's start with the `users` query to retrieve all the `User` nodes currently stored in the database. + + + +Enter the following query into the left Playground pane and click the **Play**-button (or use the hotkey **CMD+Enter**): + +```graphql +query { + users { + name + } +} +``` + + + +At this point, the server only returns an empty list. This is no surprise as we haven't actually created any `User` nodes so far. So, let's change that and use the `createUser` mutation to store a first `User` node in the database. + + + +Open a new tab in the Playground, enter the following mutation into the left Playground pane and send it: + +```graphql +mutation { + createUser(data: { + name: "Sarah" + }) { + id + } +} +``` + + + +This time, the response from the server actually contains some data (note that the `id` will of course vary as the server generates a globally unique ID for every new node upon creation): + +```json +{ + "data": { + "createUser": { + "id": "cjc69nckk31jx01505vgwmgch" + } + } +} +``` + + + +You can now go back to the previous tab with the `users` query and send that one again. + + + +This time, the `User` node that was just created is returned in the server response: + +![](https://imgur.com/LfXtmbc.png) + +Note that the API also offers powerful filtering, ordering and pagination capabilities. Here are examples for queries that provide the corresponding input arguments to the `users` query. + +**Retrieve all `User` nodes where the `name` contains the string `"ra"`** + +```graphql +query { + users(where: { + name_contains: "ra" + }) { + id + name + } +} +``` + +**Retrieve all `User` nodes sorted descending by their names** + +```graphql +query { + users(orderBy: name_DESC) { + id + name + } +} +``` + +**Retrieve a chunk of `User` nodes (position 20-29 in the list)** + +```graphql +query { + users(skip: 20, first: 10) { + id + name + } +} +``` diff --git a/docs/1.1/03-Tutorials/01-Prisma-Basics/02-Changing-the-Data-Model.md b/docs/1.1/03-Tutorials/01-Prisma-Basics/02-Changing-the-Data-Model.md new file mode 100644 index 0000000000..41abf059b2 --- /dev/null +++ b/docs/1.1/03-Tutorials/01-Prisma-Basics/02-Changing-the-Data-Model.md @@ -0,0 +1,184 @@ +--- +alias: va4ga2phie +description: Learn the fundamentals of using Prisma. +--- + +# Changing the data model and updating the API + +You now learned how to deploy a Prisma service, how to explore its API and how to interact with it by sending queries and mutations. + +In this tutorial, you'll learn the following: + +- Make changes to the data model +- Deploy the changes to update the service's API + +> To ensure you're not accidentally skipping an instruction in the tutorial, all required actions on your end are highlighted with a little counter on the left. +> +> **Pro tip**: If you're only keen on trying the practical parts but don't care so much about the explanations of what's going on, you can simply jump from instruction to instruction. + +## Changing the data model + +The last thing we want to cover in this tutorial is how you can update the API by making changes to the data model. + +We want to make the following changes to the data model: + +- Add an `age` field to the `User` type. +- Track the exact time when a `User` was _initially created_ or _last updated_. +- Add a new `Post` type with a `title` field. +- Create a one-to-many relation between `User` and `Post` to express that one `User` can create many `Post` nodes. + + + +Start by adding the required fields to the `User` type: + +```graphql +type User { + id: ID! @unique + createdAt: DateTime! + updatedAt: DateTime! + name: String! + age: Int +} +``` + + + +The `age` field is of type `Int` and not required on the `User` type. This means you can store `User` nodes where `age` will be null (in fact, this is the case for the `User` named `Sarah` you created before). + +`createdAt` and `updatedAt` on the other hand are actually special fields that are managed by Prisma. Under the hood, Prisma always maintains these fields - but they're only exposed in your API once you add them to the type definition in the data model (the same is true for the `id` field by the way). + +> **Note**: Right now, the values for these fields are read-only. In the future, it will be possible to set the values for these fields via regular mutations as well. To learn more about this feature and timeline, check out this [GitHub issue](https://github.com/graphcool/prisma/issues/1278). + +So far, the changes you made are only local. So, you won't be able to access the new fields in a GraphQL Playground if you open it right now. + +## Deploying your changes & updating the API + + + +To make your changes take effect, you need to to deploy the service again. In the `hello-world` directory, run the following command: + +```sh +prisma deploy +``` + + + +You can now either open up a new GraphQL Playground or _reload the schema_ in one that's already open (the button for reloading the schema is the **Refresh**-button right next to the URL of your GraphQL API). + +Once you did that, you can access the new fields on the `User` type. + + + +Try this mutation to create a new `User` node and set its `age` field: + +```graphql +mutation { + createUser(data: { + name: "John" + age: 42 + }) { + id + createdAt + updatedAt + } +} +``` + + + +Lastly in this tutorial, we want to add another type, called `Post`, to the data model and create a relation to the existing `User` type. + +Creating a relation between types comes very natural: All you need to do is add a new field of the related type to represent one end of the relation. Relations can - but don't have to - go in both directions. + +Go ahead and start by defining the new `Post` type with its end of the relation. + + + +Open `datamodel.graphql` and add the following type definition to it: + +```graphql +type Post { + id: ID! @unique + title: String! + author: User! +} +``` + + + + + +To apply these changes, you need to run `prisma deploy` inside the `hello-world` directory again. + + + +Every `Post` now requires a `User` node as its `author`. The way how this works is by using the `connect` argument for _nested_ mutations. + + + +You can for example send the following mutation to connect a new `Post` node with an existing `User` node (you'll of course have to replace the `__USER_ID__` placeholder with the actual `id` of a `User`): + +```graphql +mutation { + createPost(data: { + title: "GraphQL is awesome" + author: { + connect: { + id: "__USER_ID__" + } + } + }) { + id + } +} +``` + + + +Let's also add the other end of the relation, so we have a proper one-to-many relationship between the `User` and the `Post` types. + + + +Open `datamodel.graphql` and add a new field, called `posts`, to the `User` type so it looks as follows: + +```graphql +type User { + id: ID! @unique + createdAt: DateTime! + updatedAt: DateTime! + name: String! + age: Int + posts: [Post!]! +} +``` + + + +That's it! The new `posts` field represents a list of `Post` nodes which were created by that `User`. + + + +Of course, this now also allows you to send nested queries where you're asking for all `User` nodes, as well as all the `Post` nodes for these users as well: + +```graphql +{ + users { + name + posts { + title + } + } +} +``` + + + +## Next steps + +In this tutorial, we covered the very basics of using Prisma - but there's a lot more to explore! + +Here's a few pointers for where you can go next: + +- **Quickstart Tutorials (Backend & Frontend)**: The remaining quickstart tutorials explain how to use Prisma together with conrete languages and frameworks, like [React](!alias-tijghei9go), [Node.js](!alias-phe8vai1oo) or [TypeScript](!alias-rohd6ipoo4). +- [**Examples**](https://github.com/graphcool/Prisma/tree/master/examples): We're maintaing a list of practical examples showcasing certain use cases and scenarios with Prisma, such as authentication & permissions, file handling, wrapping REST APIs or using GraphQL subscriptions. +- [**Deployment Docs**](!alias-eu2ood0she): To learn more about different deployment options, you can check out the cluster documentation. diff --git a/docs/1.1/03-Tutorials/01-Prisma-Basics/index.md b/docs/1.1/03-Tutorials/01-Prisma-Basics/index.md new file mode 100644 index 0000000000..cf1666bc68 --- /dev/null +++ b/docs/1.1/03-Tutorials/01-Prisma-Basics/index.md @@ -0,0 +1,6 @@ +--- +alias: hoof1hees2 +subtitle: A practical introduction to using Prisma. +imageUrl: "http://imgur.com/a/dvsep" +description: "Learn how to generate a GraphQL API for your database with Prisma. This tutorial series includes the very first steps of installing the Prisma CLI, defining and updating your data model as well as working with the API." +--- diff --git a/docs/1.1/03-Tutorials/02-GraphQL-Server-Development/01-Deployment-with-Now.md b/docs/1.1/03-Tutorials/02-GraphQL-Server-Development/01-Deployment-with-Now.md new file mode 100644 index 0000000000..ed518418fa --- /dev/null +++ b/docs/1.1/03-Tutorials/02-GraphQL-Server-Development/01-Deployment-with-Now.md @@ -0,0 +1,126 @@ +--- +alias: ahs1jahkee +description: Learn how to deploy your GraphQL server with now. +--- + +# Deploy a GraphQL server with Now + +Once you're done implementing your GraphQL server and have tested it enough locally to make it available to the general public, you need to _deploy_ it to the web. + +In this tutorial, you're going to learn how you can use [Now](https://zeit.co/now) - an amazing one-click deployment tool from the [Zeit](https://zeit.co/) team - to deploy your GraphQL server. + +The tutorial has two parts: + +1. **Basic**: Learn how to do a simple and straightforward deployment with `now` based on the [`node-basic`](https://github.com/graphql-boilerplates/node-graphql-server/tree/master/basic) GraphQL boilerplate project +2. **Advanced**: Learn how to deploy with `now` with environment variables based on the [`node-advanced`](https://github.com/graphql-boilerplates/node-graphql-server/tree/master/advanced) GraphQL boilerplate project + +## Install Now Desktop + +The first thing you need to do is download the Now Desktop and login. + + + +Open [`https://zeit.co/download`](https://zeit.co/download) in your browser and hit the **DOWNLOAD**-button. + + + +> **Note**: Now Desktop includes the `now` CLI. + +![](https://imgur.com/UpRzQsY.png) + +## Basic + +### Bootstrap the GraphQL server + +In this tutorial, you'll use the [`node-basic`](https://github.com/graphql-boilerplates/node-graphql-server/tree/master/basic) GraphQL boilerplate project as a sample server to be deployed. The easiest way to get access to this boilerplate is by using the `graphql create` command from the [GraphQL CLI](https://github.com/graphql-cli/graphql-cli/). + +The boilerplate project is based on [`graphql-yoga`](https://github.com/graphcool/graphql-yoga/), a lightweight GraphQL server based on Express.js, `apollo-server` and `graphql-tools`. + + + +If you haven't already, go ahead and install the GraphQL CLI. Then, bootstrap your GraphQL server with `graphql create`: + +``` +npm install -g graphql-cli +graphql create hello-basic --boilerplate node-basic +``` + + + + + +When prompted where (i.e. to which _cluster_) to deploy your Prisma service, choose one of the _public cluster_ options: `prisma-eu1` or `prisma-us1`. + + + +The above `graphql create` command creates a new directory called `hello-basic` where it places the source files for your GraphQL server as well as the configuration for the belonging Prisma service. + +### Deploy the server with `now` + +The `now` command uploads your source files and invokes the `start` script defined in your `package.json` to started the remote server. + +You now have a proper foundation to deploy your GraphQL server. + + + +All you need to is navigate into the `hello-basic` directory and invoke `now`: + +``` +cd hello-basic +now +``` + + + +> **Note**: If this is the first time you're using `now`, it will ask you to authenticate with their service. + +That's it, your GraphQL server is now deployed and available under the URL printed by the CLI 🎉 The URL looks similar to `https://hello-basic-__ID__.now.sh` (where `__ID__` is a random ID for your service generated by `now`). + +## Advanced: Using environment variables + +### Bootstrap the GraphQL server + + + +In your terminal, navigate into a new directory and download the `node-advanced` boilerplate as follows: + +```sh +graphql create hello-advanced --boilerplate node-advanced +``` + + + + + +Like before, when prompted where to deploy the service, choose either `prisma-eu1` or `prisma-us1`. + + + +The service is now deployed to a public cluster. + +### Deploy the server with `now` + +This time, your service requires certain environment variables to be set. If you just ran `now` like in the previous section, the deployment would not succeed - or rather the Playground that would be deployed wouldn't work correctly because it doesn't know against which Prisma service it should be running. Because this information is now provided in terms of environment variables. + +That's what you can use the `--dotenv` option of the `now` command for! It takes as an argument a `.env` file where environment variables are specifed. + +> `.env` files are a convention / best practice for specifying environment variables. Many tools (such as Docker or other deployment tooling) "understand" `.env` files - and so does `now` when using the [`--dotenv`](https://zeit.co/docs/features/env-and-secrets#--dotenv-option) flag. + + + +All you need to is navigate into the `hello-advanced` directory and invoke `now` with that argument: + +``` +cd hello-advanced +now --dotenv .env +``` + + + +If you deployed your Prisma service locally with Docker, your `.env` file will contain local references for the environment variables `PRISMA_ENDPOINT` and `PRISMA_CLUSTER` (such as `http://localhost:60000/hello-advanced/dev`). In that case you can create another `.env` file (e.g. called `.env.prod`) and make the `PRISMA_ENDPOINT` and `PRISMA_CLUSTER` are set to proper remote URLs (of course that requires that you properly deploy the Prisma service to some public cluster on the web before) and then refer to that one during deployment: + +```sh +now --dotenv .env +``` + +You can find some documentation about how to handle environment variables and secrets when using `now` [here](https://zeit.co/docs/features/env-and-secrets). diff --git a/docs/1.1/03-Tutorials/02-GraphQL-Server-Development/02-Resolver-Patterns.md b/docs/1.1/03-Tutorials/02-GraphQL-Server-Development/02-Resolver-Patterns.md new file mode 100644 index 0000000000..33506ba256 --- /dev/null +++ b/docs/1.1/03-Tutorials/02-GraphQL-Server-Development/02-Resolver-Patterns.md @@ -0,0 +1,97 @@ +--- +alias: eifeecahx4 +description: Learn about common resolver patterns +--- + +# Common Resolver Patterns + +This tutorial gives an overview about common scenarios you might encounter when implementing your GraphQL server with `graphql-yoga` and Prisma. + +Note that all scenarios in this tutorial are based on the [`typescript-basic`](https://github.com/graphql-boilerplates/typescript-graphql-server/tree/master/basic) GraphQL boilerplate project. + +### Scenario: Add a new field to the data model and expose it in the API + +Adding a new address field to the `User` type in the database, with the purpose of exposing it in the application API as well. + +### Instructions + +#### 1. Adding the field to the data model + +in `database/datamodel.graphql`: + +```graphql +type User { + id: ID! @unique + email: String! @unique + password: String! + name: String! + posts: [Post!]! ++ address: String +} +``` + +#### 2. Deploying the updated data model + +```sh +prisma deploy +``` + +This will... + +* ... deploy the new database structure to the local service +* ... download the new GraphQL schema for the database to `database/schema.graphql` + +#### 3. Adding the field to the application schema + +In `src/schema.graphql`: + +```graphql +type User { + id: ID! + email: String! + name: String! + posts: [Post!]! ++ address: String +} +``` + +### Scenario: Adding a new resolver + +Suppose we want to add a custom resolver to delete a `Post`. + +### Instructions + +Add a new `delete` field to the Mutation type in `src/schema.graphql` + +```graphql +type Mutation { + createDraft(title: String!, text: String): Post + publish(id: ID!): Post ++ delete(id: ID!): Post +} +``` + +Add a `delete` resolver to Mutation part of `src/index.js` + +```js +delete(parent, { id }, ctx, info) { + return ctx.db.mutation.deletePost( + { + where: { id } + }, + info + ); +} +``` + +Run `yarn start`. + +Then you can run the following mutation to delete a post: + +```graphql +mutation { + delete(id: "__POST_ID__") { + id + } +} +``` diff --git a/docs/1.1/03-Tutorials/02-GraphQL-Server-Development/03-Permissions.md b/docs/1.1/03-Tutorials/02-GraphQL-Server-Development/03-Permissions.md new file mode 100644 index 0000000000..84b9aff107 --- /dev/null +++ b/docs/1.1/03-Tutorials/02-GraphQL-Server-Development/03-Permissions.md @@ -0,0 +1,389 @@ +--- +alias: thohp1zaih +description: Learn how to implement permissions and access rights with Prisma and graphql-yoga +--- + +# Permissions + +In this tutorial, you'll learn how to implement permissions rules when building a GraphQL server with Prisma and `graphql-yoga`. + +For the purpose of this tutorial, you'll use the [`node-advanced`](https://github.com/graphql-boilerplates/node-graphql-server/tree/master/advanced) GraphQL boilerplate project (which already comes with out-of-the-box authentication) to get started. You'll then gradually adjust the existing resolvers to account for the permission requirements of the API. Let's jump right in! + +## Bootstrapping the GraphQL server + +Before you can bootstrap the GraphQL server with `graphql create`, you need to install the [GraphQL CLI](https://github.com/graphql-cli/graphql-cli/). + + + +Open your terminal and install the GraphQL CLI with the following command: + +```sh +npm install -g graphql-cli +``` + + + + > **Note**: For the purpose of this tutorial you don't explicitly have to install the Prisma CLI because `prisma` is listed as a _development dependency_ in the `node-advanced` boilerplate, which allows to run its commands by prefixing it with `yarn`, e.g. `yarn prisma deploy` or `yarn prisma playground`. + > If you have `prisma` installed globally on your machine (which you can do with `npm install -g prisma`), you don't need to use the `yarn` prefix throughout this tutorial. + +Once the CLI is installed, you can create your GraphQL server. + + + +In your terminal, navigate to a directory of your choice and run the following command: + +```sh +graphql create permissions-example --boilerplate node-advanced +``` + + + + + +When prompted where (i.e. to which _cluster_) to deploy your Prisma service, choose one of the _public cluster_ options: `prisma-eu1` or `prisma-us1`. + + + +> **Note**: You can also deploy the Prisma service locally, this however requires you to have [Docker](https://www.docker.com) installed on your machine. For the purpose of this tutorial, we'll go with a public demo cluster to keep things simple and straightforward . + +This will create a new directory called `permissions-example` where it places the source files for the GraphQL server (based on `graphql-yoga`) and the required configuration for the belonging Prisma database service. + +The GraphQL server is based on the following data model: + +```graphql +type Post { + id: ID! @unique + createdAt: DateTime! + updatedAt: DateTime! + isPublished: Boolean! @default(value: "false") + title: String! + text: String! + author: User! +} + +type User { + id: ID! @unique + email: String! @unique + password: String! + name: String! + posts: [Post!]! +} +``` + +## Adding an `ADMIN` role to the app + +In this tutorial, a `User` can be either an admin (with special access rights) or a simple customer. To distinguish these types of users, you need to make a modification to the data model and add an enum that defines these roles. + + + +Open `database/datamodel.graphql` and update the `User` type in the data model to look as follows, note that you also need to add the `Role` enum: + +```graphql +type User { + id: ID! @unique + email: String! @unique + password: String! + name: String! + posts: [Post!]! + role: Role! @default(value: "CUSTOMER") +} + +enum Role { + ADMIN + CUSTOMER +} +``` + + + +Note that the `role` field is not exposed through the API of your GraphQL server (just like the `password` field) because the `User` type defined in the application schema does not have it. The application schema ultimately defines what data will be exposed to your client applications. + +To apply the changes, you need to deploy the database. + + + +In the `permissions-example` directory, run the following command: + +```sh +yarn prisma deploy +``` + + + +Now your data model and the Prisma API are updated and include the `role` field for the `User` type. + +## Defining permission requirements + +The **application schema** defined in `src/schema.graphql` exposes the following queries and mutations: + +```graphql +type Query { + feed: [Post!]! + drafts: [Post!]! + post(id: ID!): Post! + me: User +} + +type Mutation { + signup(email: String!, password: String!, name: String!): AuthPayload! + login(email: String!, password: String!): AuthPayload! + createDraft(title: String!, text: String!): Post! + publish(id: ID!): Post! + deletePost(id: ID!): Post! +} +``` + +At the moment, we're only interested in the resolvers that relate to the `Post` type. Here is an overview of the permission requirements we have for them: + +- `feed`: No permissions requirements. Everyone (not only authenticated users) should be able to access the `feed` of published `Post` nodes. +- `drafts`: Every user should only be able to access their own drafts (i.e. where they're set as the `author` of the `Post`). +- `post`: Only the `author` of a `Post` or an `ADMIN` user should be able to access `Post` nodes using the `post` query. +- `publish`: Only the `author` of a `Post` should be able to publish it. +- `deletePost`: Only the `author` of a `Post` node or an `ADMIN` user should be able to delete it. + +## Implementing permissions rules with `graphql-yoga` and Prisma + +When implementing permission rules with Prisma and `graphql-yoga`, the basic idea is to implement a "data access check" in each resolver. Only if that check succeeds, the operation (query, mutation or subscription) is forwarded to the Prisma service using the available `prisma-binding`. + +You're now going to gradually add these checks to the existing resolvers. + +### `feed` + +Since everyone is able to access the `feed` query, no check needs to be implemented here. + +### `drafts` + +For the `drafts` query, we have the following requirement: + +> Every user should only be able to access their own drafts (i.e. where they're set as the `author` of the `Post` + +Currently, the `drafts` resolver is implemented as follows: + +```js +drafts(parent, args, ctx, info) { + const id = getUserId(ctx) + + const where = { + isPublished: false, + author: { + id + } + } + + return ctx.db.query.posts({ where }, info) +}, +``` + +In fact, this already accounts for the requirement because it filters the `posts` and only retrieves the one for the authenticated `User`. So, there's nothing to do for you here. + +### `post` + +For the `post` query, we have the following requirement: + +> Only the `author` of a `Post` or an `ADMIN` user should be able to access `Post` nodes using the `post` query. + +Here is how the `post` resolver is currently implemented: + +```js +post(parent, { id }, ctx, info) { + return ctx.db.query.post({ where: { id } }, info) +} +``` + +It's very simple and straightforward! But now, you need to make sure that it only returns a `Post` if the `User` that sent the request is either the `author` of it _or_ and `ADMIN` user. + +You'll use the `exists` function of the `prisma-binding` package for that. + + + +Update the implementation of the resolver in `src/resolvers/Query.js` as follows: + +```js +async post(parent, { id }, ctx, info) { + + const requestingUserIsAuthor = await ctx.db.exists.Post({ + id, + author: { + id: userId, + }, + }) + const requestingUserIsAdmin = await ctx.db.exists.User({ + id: userId, + role: 'ADMIN', + }) + + if (requestingUserIsAdmin || requestingUserIsAuthor) { + return ctx.db.query.post({ where: { id } }, info) + } + throw new Error( + 'Invalid permissions, you must be an admin or the author of this post to retrieve it.', + ) + +} +``` + + + +With the two `exists` invocations, you gather information as to whether: + +- the `User` who sent the request is in fact the `author` of the `Post` that was requested +- the `User` who sent the request is an `ADMIN` + +If either of these conditions is true, you simply return the `Post`, otherwise you return an insufficient permissions error. + +### `publish` + +The `publish` mutation has the following requirement: + +> Only the `author` of a `Post` should be able to publish it. + +The `publish` resolver is implemented in `src/resolvers/Mutation/post.js` and currently looks as follows: + +```js +async publish(parent, { id }, ctx, info) { + const userId = getUserId(ctx) + const postExists = await ctx.db.exists.Post({ + id, + author: { id: userId }, + }) + if (!postExists) { + throw new Error(`Post not found or you're not the author`) + } + + return ctx.db.mutation.updatePost( + { + where: { id }, + data: { isPublished: true }, + }, + info, + ) +}, +``` + +The current `exists` invocation already ensures that the `User` who send the request is set as the `author` of the `Post` to be published. So again, you don't actually have to make any changes and the requirement is already taken care of. + +### `deletePost` + +The `deletePost` mutation has the following requirement: + +> Only the `author` of a `Post` node or an `ADMIN` user should be able to delete it. + +The current resolver is implemented in `src/resolvers/Mutation/post.js` and looks as follows: + +```js +async deletePost(parent, { id }, ctx, info) { + const userId = getUserId(ctx) + const postExists = await ctx.db.exists.Post({ + id, + author: { id: userId }, + }) + if (!postExists) { + throw new Error(`Post not found or you're not the author`) + } + + return ctx.db.mutation.deletePost({ where: { id } }) +}, +``` + +Again, the `exists` invocation already ensures that the requesting `User` is the `author` of the `Post` to be deleted. However, if that `User` is an `ADMIN`, the `Post` should still be deleted. + + + +Adjust the `deletePost` resolver in `src/resolvers/Mutation/post.js` to look as follows: + +```js +async deletePost(parent, { id }, ctx, info) { + const userId = getUserId(ctx) + const postExists = await ctx.db.exists.Post({ + id, + author: { id: userId }, + }) + + const requestingUserIsAdmin = await ctx.db.exists.User({ + id: userId, + role: 'ADMIN', + }) + + if (!postExists && !requestingUserIsAdmin) { + throw new Error(`Post not found or you don't have access rights to delete it.`) + } + + return ctx.db.mutation.deletePost({ where: { id } }) +}, +``` + + + +## Testing permissions + +You can the permissions inside a GraphQL Playground. Here's the general flow: + +- In the Playground, create a new `User` with the `signup` mutation and specify the `token` in the selection set so it's returned by the server (if you already created a `User` before, you can of course also use the `login` mutation) +- Save the `token` from the server's response and set it as the `Authorization` header in the Playground (you'll learn how to do this in a bit) +- All subsequent requests are now sent _on behalf_ of that `User` + +### 1. Creating a new `User` + +You first need to open a GraphQL Playground, but before you can do that you need to start the server! + + + +In the `permissions-example` directory, run the following command in your terminal: + +```sh +yarn start +``` + + + +The server is now running on [`http://localhost:4000`](http://localhost:4000). + + + +Open [`http://localhost:4000`](http://localhost:4000) in your browser. + + + + + +In the **default** Playground in the **app** section, send the following mutation: + +```graphql +mutation { + signup( + email: "sarah@graph.cool" + password: "graphql" + name: "Sarah" + ) { + token + } +} +``` + + + +![](https://imgur.com/gbnUlkr.png) + + + +Copy the `token` and set it as the `Authorization` header in the bottom-left corner of the Playground. You need to set the header as JSON as follows (note that you need to replace the `__TOKEN__` placeholder with the authentication `token` that was returned from the `signup` mutation): + +```json +{ + "Authorization": "__TOKEN__" +} +``` + + + +From now on, all requests sent through the Playground are sent _on behalf_ of the `User` you just created. + +Equipped with that knowledge, you can now play around with the available queries and mutations nd verify if the permission rules work. + +For example, you can go through the following flow: + +1. Create a new _draft_ with the `createDraft` mutation on behalf `Sarah` (the `User` you just created). +1. Create another `User` with the `signup` mutation and ask for a `token` for them. +1. Use the new authentication token to try and publish Sarah's draft. This should return the following error: `Post not found or you're not the author`. + +![](https://imgur.com/hZSC1gy.png) diff --git a/docs/1.1/03-Tutorials/02-GraphQL-Server-Development/index.md b/docs/1.1/03-Tutorials/02-GraphQL-Server-Development/index.md new file mode 100644 index 0000000000..50172d5fbc --- /dev/null +++ b/docs/1.1/03-Tutorials/02-GraphQL-Server-Development/index.md @@ -0,0 +1,6 @@ +--- +alias: kut8kohzoo +subtitle: Practical guides for building and deploying GraphQL servers. +imageUrl: "http://imgur.com/a/dvsep" +description: "Prisma is used as the foundation for building GraphQL servers. Learn everything you need to know about building and deploying GraphQL server with Prisma in this tutorial series." +--- diff --git a/docs/1.1/03-Tutorials/03-Database/01-Data-Export-&-Import.md b/docs/1.1/03-Tutorials/03-Database/01-Data-Export-&-Import.md new file mode 100644 index 0000000000..8ba2c52cf4 --- /dev/null +++ b/docs/1.1/03-Tutorials/03-Database/01-Data-Export-&-Import.md @@ -0,0 +1,240 @@ +--- +alias: caith9teiy +description: Learn how to export and import data with Prisma. +--- + +# Export & Import + +Prisma uses a dedicated, intermediate format for importing and exporting data: The [Normalized Data Format](!alias-teroo5uxih) (NDF). + +``` ++--------------+ +----------------+ +------------+ +| +--------------+ | | | | +| | | | | | | | +| | SQL | | (1) transform | NDF | (2) chunked upload | prisma | +| | MongoDB | | +--------------> | | +-------------------> | | +| | JSON | | | | | | +| | | | | | | | ++--------------+ | +----------------+ +------------+ + +--------------+ +``` + +In this tutorial, you'll perform the following steps: + +1. Create a Prisma service +1. Seed some initial data for the service +1. Export the data in NDF +1. Deploy the service to a new stage +1. Import the data in NDF + +## Create a Prisma service + + + +In your terminal, navigate to a folder of your choice and run the following command: + +```sh +prisma init import-example +``` + + + + + +When prompted what kind of template to use, choose the `Minimal setup: database-only` one. + + + +This created a new directory called `import-example` with the root configuration file `prisma.yml` as well as the definition of the service's data model in `datamodel.graphql`. + +Next, you'll update the data model to also include a relation. + + + +Open `datamodel.graphql` and change the contents to looks as follows: + +```graphql +type User { + id: ID! @unique + name: String! + posts: [Post!]! +} + +type Post { + id: ID! @unique + title: String! + author: User! +} +``` + +## Seed initial data + +Next, you're going to seed some initial data for the service. + + + +Create a new file called `seed.graphql` inside the `import-example` directory and add the following mutation to it: + +```graphql +mutation { + createUser(data: { + name: "Sarah", + posts: { + create: [ + { title: "GraphQL is awesome" }, + { title: "It really is" }, + { title: "How to GraphQL is the best GraphQL tutorial" } + ] + } + }) { + id + } +} +``` + + + +Now you need to tell the CLI that you created this file. You can do so by setting the `seed` property in `prisma.yml`. + + + +Open `prisma.yml` and update its contents to look as follows: + +```yml +service: import-example +stage: dev + +datamodel: datamodel.graphql + +# to enable auth, provide +# secret: my-secret +disableAuth: true + +seed: + import: seed.graphql +``` + + + +When deploying the service, the CLI will now send the mutation defined in `seed.graphql` to your service's API. + + + +Deploy the Prisma service by running the following command: + +```sh +prisma deploy +``` + + + + + +When prompted where (i.e. to which _cluster_) to deploy your Prisma service, choose one of the _public cluster_ options: `prisma-eu1` or `prisma-us1`. (Note that seeding also works when deploying with Docker) + + + +The CLI now deploys the service and executes the mutation in `seed.graphql`. To convince yourself the seeding actually worked, you can open up a GraphQL Playground and send the following query: + +```graphql +{ + users { + name + posts { + title + } + } +} +``` + +The Prisma API will respond with the following data: + +```json + + +{ + "data": { + "users": [ + { + "name": "Sarah", + "posts": [ + { + "title": "GraphQL is awesome" + }, + { + "title": "It really is" + }, + { + "title": "How to GraphQL is the best GraphQL tutorial" + } + ] + } + ] + } +} +``` + +## Export the data in NDF + +It's time to export the in the Normalized Data Format. + + + +In the `import-example` in your terminal, execute the following command: + +```sh +prisma export +``` + + + +This creates a new file called `export-__TIMESTAMP__.zip` where `__TIMESTAMP__` represents the exact time of the export. The files in the zip directory are in NDF. To learn more about the structure, check out the [reference documentation for the NDF](!alias-teroo5uxih). + +## Deploy the service to a new stage + +Next, you'll create "clone" of the service by deploying it to a new stage. + + + +Open `prisma.yml` and set the `stage` property to a new value. Also remove the `seed` and `cluster` properties! + +```yml +service: import-example +stage: test + +datamodel: datamodel.graphql + +# to enable auth, provide +# secret: my-secret +disableAuth: true +``` + + + + + +Run `prisma deploy` again to deploy the service the new `test` stage. + + + + + +Like before, when prompted where to deploy your Prisma service, either choose `prisma-eu1` or `prisma-us1`. + + + +## Import the data in NDF + +Now that the service is running, you can import the data from the zip directory! + + + +Run the following command in your terminal. Note that you need to replace the `__DATA__` placeholder with the path to the exported zip directory (e.g. `export-2018-01-13T19:28:25.921Z.zip`): + +```sh +prisma import --data __DATA__ +``` + + + +That's it! To convince yourself the import actually worked, you can open up a GraphQL Playground for the current `test` stage and send the above query again. diff --git a/docs/1.1/03-Tutorials/03-Database/02-Database-Access-(SQL).md b/docs/1.1/03-Tutorials/03-Database/02-Database-Access-(SQL).md new file mode 100644 index 0000000000..b1f2ed643a --- /dev/null +++ b/docs/1.1/03-Tutorials/03-Database/02-Database-Access-(SQL).md @@ -0,0 +1,107 @@ +--- +alias: eechaeth3l +description: Learn how to diredctly access your database with SQL. +--- + +# Database Access (SQL) + +Follow this guide to connect directly to the MySQL database powering your local Prisma cluster. + +If you used `prisma local start` to start your local Prisma cluster, you will have two containers running: + +`prisma` is running the main Prisma service +`prisma-db` is running the MySQL server that stores your data + +This guide explains how to connect to your local MySQL server in order to query and update data directly. + +> In the following, we assume that you have a local Prisma service running. + +#### 1. Get the name of the Docker container that runs the MySQL database + +list your running Prisma Docker containers: + +```sh +docker ps --filter name=prisma +``` + +Verify that there is a container with the name `prisma-db` image `mysql:5.7`. + +#### 2. Open MySQL client + +To open the MySQL client in your terminal, run the following command. Note that prisma-db is the container name from the list above: + +```sh + docker exec -it prisma-db mysql -u root --host 127.0.0.1 --port 3306 --password=prisma +``` + +#### 3. Send SQL queries to the database + +Once the MySQL client is open, you can ask for the currently available databases: + +```mysql +show databases; +``` + +This will print the following output: + +``` ++---------------------------+ +| Database | ++---------------------------+ +| information_schema | +| prisma | +| logs | +| mysql | +| performance_schema | +| sys | +| | ++---------------------------+ +``` + +From the available databases, the following three are relevant for you: + +* ``: The name of this database is a combination of the name and stage of your service. It looks like this: `service@stage`. It contains meta information about your service used to generate the GraphQL schema. +* `prisma`: This database contains meta-information about the Prisma service definition. + +You can now select one of these databases with the `use` command, for example if your `` is `my-service@dev`, then run: + +```mysql +use my-service@dev; +``` + +You can list tables like this: + +```sh +show tables; +``` + +``` ++----------------------+ +| Tables_in_my-app@dev | ++----------------------+ +| Post | +| _RelayId | ++----------------------+ +``` + +Now you can start writing queries: + +```sh +SELECT * FROM Post; +``` + +``` ++---------------------------+---------------------+---------------------+-------------+----------------------+-------------------------------------------------+ +| id | createdAt | updatedAt | isPublished | title | text | ++---------------------------+---------------------+---------------------+-------------+----------------------+-------------------------------------------------+ +| cjc82o6cg000b0135wpxgybf6 | 2018-01-09 20:12:02 | 2018-01-09 20:12:02 | 1 | Hello World | This is my first blog post ever! | +| cjc82o6mo000d013599yzlwls | 2018-01-09 20:12:02 | 2018-01-09 20:12:02 | 1 | My Second Post | My first post was good, but this one is better! | +| cjc82o6n4000f01350jortmv2 | 2018-01-09 20:12:02 | 2018-01-09 20:12:02 | 0 | Solving World Hunger | This is a draft... | ++---------------------------+---------------------+---------------------+-------------+----------------------+-------------------------------------------------+ +``` + +You can quit MySQL like this: + +```sh +exit; +``` diff --git a/docs/1.1/03-Tutorials/03-Database/index.md b/docs/1.1/03-Tutorials/03-Database/index.md new file mode 100644 index 0000000000..8aa98b0660 --- /dev/null +++ b/docs/1.1/03-Tutorials/03-Database/index.md @@ -0,0 +1,6 @@ +--- +alias: toh0uphaet +subtitle: Learn how to import and export data with Prisma. +imageUrl: "http://imgur.com/a/dvsep" +description: "It is a common use case that developers need to import data from an existing data source into a Prisma service. This tutorial series provides practical guidance for how this can be done." +--- diff --git a/docs/1.1/03-Tutorials/04-Cluster-Deployment/01-Local-(Docker).md b/docs/1.1/03-Tutorials/04-Cluster-Deployment/01-Local-(Docker).md new file mode 100644 index 0000000000..faa126422c --- /dev/null +++ b/docs/1.1/03-Tutorials/04-Cluster-Deployment/01-Local-(Docker).md @@ -0,0 +1,64 @@ +--- +alias: meemaesh3k +description: Learn how to deploy your Prisma database service to a local cluster. +--- + +# Local Cluster (Docker) + +This guide describes advanced topics for the local Prisma cluster. + +If you want to develop without internet access or simply prefer having everything locally, you can use `prisma local` to set up a local Prisma cluster with Docker. + +### Installing Docker + +You need an up-to-date version of Docker to run Prisma locally. You can find installation instructions for the free Docker Community Edition (CE) on https://www.docker.com/community-edition + +### Set up local cluster + +Getting started is as simple as running: + +```sh +prisma local start +``` + +This will download the open source Docker images for Prisma and start two Docker containers for Prisma and MySQL. It can take a while, depending on your internet connection. + +Now you can deploy a service to the local cluster: + +``` +❯ prisma deploy + +? Please choose the cluster you want to deploy "demo@dev" to (Use arrow keys) + + prisma-eu1 Free development cluster (hosted on Prisma Cloud) + prisma-us1 Free development cluster (hosted on Prisma Cloud) +❯ local Local cluster (requires Docker) +``` + +This will add a `cluster` entry to the `prisma.yml` with the cluster you chose. + +### Upgrading local cluster + +To upgrade the local cluster, you can run: + +```sh +prisma local upgrade +``` + +> Note: It is recommended to export your data before upgrading, using the `prisma export` command. + +If you run into issues during or after upgrading, you can [nuke the local cluster](!alias-si4aef8hee), wiping all data in the process. + +### Cluster Information + +You can view the current version of Prisma you are running by listing all available clusters: + +``` +> prisma cluster list + +name version endpoint +────────────── ───────────── ────────────────────────────────── +local 1.0.0-beta4.2 http://localhost:4466/cluster +``` + +> To learn how you can directly your MySQL database, follow [this](!alias-eechaeth3l) tutorial. \ No newline at end of file diff --git a/docs/1.1/03-Tutorials/04-Cluster-Deployment/02-Digital-Ocean-(Docker-Machine).md b/docs/1.1/03-Tutorials/04-Cluster-Deployment/02-Digital-Ocean-(Docker-Machine).md new file mode 100644 index 0000000000..6adee23466 --- /dev/null +++ b/docs/1.1/03-Tutorials/04-Cluster-Deployment/02-Digital-Ocean-(Docker-Machine).md @@ -0,0 +1,246 @@ +--- +alias: texoo9aemu +description: Learn how to deploy your Prisma database service to Digital Ocean using Docker Machine. +--- + +# Digital Ocean - Docker Machine + +This section describes how to set up a fully functioning Prisma server on Digital Ocean in less than 20 minutes. We will use Docker Machine to automate the entire installation process. + +Digital Ocean is an easy to use provider of virtual servers. They offer different compute sizes called droplets. The 10$ droplet is a good starting point for a Prisma server. + +> The setup described in this section does not include features you would normally expect from production ready servers, such as backup and active failover. We will add more guides in the future describing a more complete setup suitable for production use. + +## Install Docker + +You need Docker and Docker Machine. + +Follow the instructions at https://docs.docker.com/machine/install-machine/#install-machine-directly + +When done, you should be able to run the following command: + +``` +❯ docker-machine -v +docker-machine version 0.13.0, build 9ba6da9 +``` + +## Connect to Digital Ocean + +If you are new to Digital Ocean you should start by creating an account at https://www.digitalocean.com/ + +Then follow step 1 through 2 on https://docs.docker.com/machine/examples/ocean/ + +You can now start a droplet with the name prisma like this: + +> Note that this starts a droplet with 1GB memory in the Amsterdam region. You can pick a different size and region by tweaking the parameters as described in https://docs.docker.com/machine/drivers/digital-ocean/ + +```sh +docker-machine create --driver digitalocean --digitalocean-access-token xxxxxxxxx --digitalocean-region ams2 --digitalocean-size 1gb prisma +``` + +You will now have a running droplet that is controleld by `docker-machine`. List your droplets by running: + +``` +❯ docker-machine ls +NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS +prisma - digitalocean Running tcp://45.55.177.154:2376 v18.01.0-ce +``` + +## Install Prisma on your Droplet + +First step is to configure Docker to conenct to your droplet. Do this by running `docker-machine env prisma` and then run the command that is printed in the last line. + +The command varies based on your os and shell. On MacOS it might look like this: + +```sh +❯ docker-machine env prisma +set -gx DOCKER_TLS_VERIFY "1"; +set -gx DOCKER_HOST "tcp://188.226.158.30:2376"; +set -gx DOCKER_CERT_PATH "/Users/demo/.docker/machine/machines/prisma"; +set -gx DOCKER_MACHINE_NAME "prisma"; +# Run this command to configure your shell: +# eval (docker-machine env prisma-1gb) + +❯ eval (docker-machine env prisma-1gb) +``` + +You can read more about this in the Docker docs https://docs.docker.com/machine/reference/env/ + +Now you need to copy the Configuration files for Prisma Cluster. In a new folder create the two files: + +> .env + +``` +PORT=4466 +SCHEMA_MANAGER_SECRET=SECRET_1 +SCHEMA_MANAGER_ENDPOINT=http://prisma-database:${PORT}/cluster/schema +CLUSTER_ADDRESS=http://prisma-database:${PORT} +CLUSTER_PUBLIC_KEY=PUBLIC_KEY + +SQL_CLIENT_HOST=prisma-db +SQL_CLIENT_PORT=3306 +SQL_CLIENT_USER=root +SQL_CLIENT_PASSWORD=SECRET_2 +SQL_CLIENT_CONNECTION_LIMIT=10 + +SQL_INTERNAL_HOST=prisma-db +SQL_INTERNAL_PORT=3306 +SQL_INTERNAL_USER=root +SQL_INTERNAL_PASSWORD=SECRET_2 +SQL_INTERNAL_DATABASE=graphcool +SQL_INTERNAL_CONNECTION_LIMIT=10 +``` + +> docker-compose.yml + +```yml +version: "3" +services: + prisma-db: + container_name: prisma-db + image: mysql:5.7 + networks: + - prisma + restart: always + command: mysqld --max-connections=1000 --sql-mode="ALLOW_INVALID_DATES,ANSI_QUOTES,ERROR_FOR_DIVISION_BY_ZERO,HIGH_NOT_PRECEDENCE,IGNORE_SPACE,NO_AUTO_CREATE_USER,NO_AUTO_VALUE_ON_ZERO,NO_BACKSLASH_ESCAPES,NO_DIR_IN_CREATE,NO_ENGINE_SUBSTITUTION,NO_FIELD_OPTIONS,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_UNSIGNED_SUBTRACTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,PIPES_AS_CONCAT,REAL_AS_FLOAT,STRICT_ALL_TABLES,STRICT_TRANS_TABLES,ANSI,DB2,MAXDB,MSSQL,MYSQL323,MYSQL40,ORACLE,POSTGRESQL,TRADITIONAL" + environment: + MYSQL_ROOT_PASSWORD: $SQL_INTERNAL_PASSWORD + MYSQL_DATABASE: $SQL_INTERNAL_DATABASE + ports: + - "3306:3306" # Temporary/debug mapping to the host + volumes: + - db-persistence:/var/lib/mysql + + prisma: + image: prismagraphql/prisma:1.0.0-beta4.2 + restart: always + ports: + - "0.0.0.0:${PORT}:${PORT}" + networks: + - prisma + environment: + PORT: $PORT + SCHEMA_MANAGER_SECRET: $SCHEMA_MANAGER_SECRET + SCHEMA_MANAGER_ENDPOINT: $SCHEMA_MANAGER_ENDPOINT + SQL_CLIENT_HOST_CLIENT1: $SQL_CLIENT_HOST + SQL_CLIENT_HOST_READONLY_CLIENT1: $SQL_CLIENT_HOST + SQL_CLIENT_HOST: $SQL_CLIENT_HOST + SQL_CLIENT_PORT: $SQL_CLIENT_PORT + SQL_CLIENT_USER: $SQL_CLIENT_USER + SQL_CLIENT_PASSWORD: $SQL_CLIENT_PASSWORD + SQL_CLIENT_CONNECTION_LIMIT: 10 + SQL_INTERNAL_HOST: $SQL_INTERNAL_HOST + SQL_INTERNAL_PORT: $SQL_INTERNAL_PORT + SQL_INTERNAL_USER: $SQL_INTERNAL_USER + SQL_INTERNAL_PASSWORD: $SQL_INTERNAL_PASSWORD + SQL_INTERNAL_DATABASE: $SQL_INTERNAL_DATABASE + CLUSTER_ADDRESS: $CLUSTER_ADDRESS + SQL_INTERNAL_CONNECTION_LIMIT: 10 + CLUSTER_PUBLIC_KEY: $CLUSTER_PUBLIC_KEY + BUGSNAG_API_KEY: "" + CLUSTER_VERSION: 1.0.0-beta4.2 + +networks: + prisma: + driver: bridge + +volumes: + db-persistence: +``` + +In `.env`, replace `SECRET_1` and `SECRET_2` (occurs twice) with a long and secure random string. + +Now you are ready to use `docker-compose` to start your Prisma cluster: + +```sh +docker-compose up -d +``` + +## Enable Cluster Security + +By default, anyone can connect to the new cluster using the Prisma CLI and deploy services. To lock down access, you need to configure a public/private keypair. + +``` +openssl genrsa -out private.pem 2048 +openssl rsa -in private.pem -outform PEM -pubout -out public.pem +``` + +This will generate two files `private.pem` and `public.pem` + +Copy the output of the following command to the `.env` file and replace `PUBLIC_KEY`: + +```sh +cat public.pem | sed -n -e 'H;${x;s/\n/\\\\r\\\\n/g;p;}' +``` + +open ~/.prisma/config.yml in your favourite editor. It is likely that you already have one or more clusters defined in this file. Add another cluster and give it a descriptive name. For example `do-cluster`: + +```yml +clusters: + local: + host: 'http://localhost:4466' + clusterSecret: "-----BEGIN RSA PRIVATE KEY----- [ long key omitted ] -----END RSA PRIVATE KEY-----\r\n" + do-cluster: + host: 'http://45.55.177.154:4466' + clusterSecret: "-----BEGIN RSA PRIVATE KEY----- [ long key omitted ] -----END RSA PRIVATE KEY-----\r\n" +``` + +Change the host to use the ip of your Digital Ocean droplet. + +Copy the output of the following command and replace the content of `clusterSecret` for the new cluster: + +```sh +cat private.pem | sed -n -e 'H;${x;s/\n/\\\\r\\\\n/g;p;}' +``` + +to restart the Prisma cluster: + +``` +docker-compose kill +docker-compose up -d +``` + +## Deploy a service + +On your local machine, verify that the cluster configuration is being picked up correctly: + +```sh +prisma cluster list +``` + +The output should include your newly added cluster. + +Now you can create a new service and deploy it to the cluster: + +``` +prisma init +prisma deploy +``` + +Pick the new cluster in the deployment option. You should see output similar to this: + +``` +Added cluster: do-cluster to prisma.yml +Creating stage dev for service demo ✔ +Deploying service `demo` to stage `dev` on cluster `do-cluster` 1.3s + +Changes: + + User (Type) + + Created type `User` + + Created field `id` of type `GraphQLID!` + + Created field `name` of type `String!` + + Created field `updatedAt` of type `DateTime!` + + Created field `createdAt` of type `DateTime!` + +Applying changes 1.8s + +Hooks: + +Running $ graphql prepare... + +Your GraphQL database endpoint is live: + + HTTP: http://45.55.177.154:4466/demo/dev + WS: ws://45.55.177.154:4466/demo/dev +``` diff --git a/docs/1.1/03-Tutorials/04-Cluster-Deployment/03-Digital-Ocean-(manual).md b/docs/1.1/03-Tutorials/04-Cluster-Deployment/03-Digital-Ocean-(manual).md new file mode 100644 index 0000000000..bf6dfad779 --- /dev/null +++ b/docs/1.1/03-Tutorials/04-Cluster-Deployment/03-Digital-Ocean-(manual).md @@ -0,0 +1,165 @@ +--- +alias: texoo6aemu +description: Learn how to deploy your Prisma database service to Digital Ocean manually. +--- + + +# Digital Ocean (manual) + +This section describes how to set up a fully functioning Prisma server on Digital Ocean in less than 20 minutes. + +In the following procedure you will connect to your droplet with ssh, and manually install all required dependencies. Most users should use the procedure described in [Digital Ocean (Docker Machine)](!alias-texoo9aemu) instead. + +Digital Ocean is an easy to use provider of virtual servers. They offer different compute sizes called droplets. The 10$ droplet is a good starting point for a Prisma server. + +> The setup described in this section does not include features you would normally expect from production ready servers, such as backup and active failover. We will add more guides in the future describing a more complete setup suitable for production use. + +## Creating a droplet + +If you are new to Digital Ocean you should start by creating an account at https://www.digitalocean.com/ + +After you log in, create a new Droplet: + +1. Pick the latest Ubuntu Distribution. As of this writing it is 17.10. +2. Pick a standard droplet. The 10$/mo droplet with 1 GB memory is a good starting point. +3. Pick a region that is close to your end user. If this Prisma will be used for development, you should pick the region closest to you. +4. Create an ssh key that you will use to connect to your droplet. Follow the guide provided by Digital Ocean. +5. Set a name for your droplet. For example `prisma` +6. Relax while your droplet is being created. This should take less than a minute. + +## Installing Prisma + +### Connect + +Digital Ocean will show you the ip address. If you are using MacOS or Linux you can now connect like this: + +```sh +ssh root@37.139.15.166 + +# You can optionally specify the path to your ssh key: +ssh root@37.139.15.166 -i /Users/demo/.ssh/id_rsa_do +``` + +### Install Docker & node & Prisma + +Digital Ocean has a detailed guide at https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-16-04 + +For the quick path, execute these commands on your droplet: + +```sh +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - +sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" +sudo apt-get update +sudo apt-get install -y docker-ce +sudo curl -L https://github.com/docker/compose/releases/download/1.18.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose +``` + +Install node: + +```sh +curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - +sudo apt-get install -y nodejs +``` + +Install Prisma: + +```sh +npm -g install prisma +prisma local start +``` + +Prisma is now installed and running. At this point you should verify that everything is running correctly. + +### Verify Prisma Installation + +Verify that the correct docker containers are running: + +```sh +> docker ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +e5d2e028eba9 prismagraphql/prisma:1.0.0 "/app/bin/single-ser…" 51 seconds ago Up 49 seconds 0.0.0.0:4466->4466/tcp prisma +42d9d5acd0e4 mysql:5.7 "docker-entrypoint.s…" 51 seconds ago Up 49 seconds 0.0.0.0:3306->3306/tcp prisma-db +``` + +Run `prisma cluster list` and verify that the local cluster is in the output. + +Finally, connect to the `/cluster` endpoint in a browser. If your droplet has the ip `37.139.15.166` open the following webpage: `http://37.139.15.166:4466/cluster` + +If a GraphQL Playground shows up, your Prisma cluster is set up correctly. + +### Connect and Deploy a Service + +Your Prisma cluster is secured by a public/private keypair. In order to connect with the `prisma` CLI on your local machine, you need to configure security settings. + +#### Copy cluster configuration from server + +On your digital ocean droplet, copy the clusterSecret for the `local` cluster: + +```sh +> cat ~/.prisma/config.yml +clusters: + local: + host: 'http://localhost:4466' + clusterSecret: "-----BEGIN RSA PRIVATE KEY----- [ long key omitted ] -----END RSA PRIVATE KEY-----\r\n" +``` + +#### Add new cluster in local configuration + +On your local development machine open `~/.prisma/config.yml` in your favourite editor. It is likely that you already have one or more clusters defined in this file. Add another cluster and give it a descriptive name. For example `do-cluster`: + +```yml +clusters: + local: + host: 'http://localhost:4466' + clusterSecret: "-----BEGIN RSA PRIVATE KEY----- [ long key omitted ] -----END RSA PRIVATE KEY-----\r\n" + do-cluster: + host: 'http://37.139.15.166:4466' + clusterSecret: "-----BEGIN RSA PRIVATE KEY----- [ long key omitted ] -----END RSA PRIVATE KEY-----\r\n" +``` + +Change the host to use the ip of your Digital Ocean droplet. + +#### Deploy a service + +On your local machine, verify that the cluster configuration is being picked up correctly: + +```sh +prisma cluster list +``` + +The output should include your newly added cluster. + +Now you can create a new service and deploy it to the cluster: + +```sh +prisma init +prisma deploy +``` + +Pick the new cluster in the deployment option. You should see output similar to this: + +```sh +Added cluster: do-cluster to prisma.yml +Creating stage dev for service demo ✔ +Deploying service `demo` to stage `dev` on cluster `do-cluster` 1.3s + +Changes: + + User (Type) + + Created type `User` + + Created field `id` of type `GraphQLID!` + + Created field `name` of type `String!` + + Created field `updatedAt` of type `DateTime!` + + Created field `createdAt` of type `DateTime!` + +Applying changes 1.8s + +Hooks: + +Running $ graphql prepare... + +Your GraphQL database endpoint is live: + + HTTP: http://37.139.15.166:4466/demo/dev + WS: ws://37.139.15.166:4466/demo/dev +``` diff --git a/docs/1.1/03-Tutorials/04-Cluster-Deployment/index.md b/docs/1.1/03-Tutorials/04-Cluster-Deployment/index.md new file mode 100644 index 0000000000..9aa47793f7 --- /dev/null +++ b/docs/1.1/03-Tutorials/04-Cluster-Deployment/index.md @@ -0,0 +1,6 @@ +--- +alias: ohh5haish7 +subtitle: Learn about different deployment options for your Prisma service. +imageUrl: "http://imgur.com/a/dvsep" +description: "There are a variety of options for deploying your Prisma service. This tutorial series contains practical guides for deploying to local clusters as well as using cloud providers such as Digital Ocean and more." +--- diff --git a/docs/1.1/04-Reference/01-Service-Configuration/01-Overview.md b/docs/1.1/04-Reference/01-Service-Configuration/01-Overview.md new file mode 100644 index 0000000000..cbef9b4588 --- /dev/null +++ b/docs/1.1/04-Reference/01-Service-Configuration/01-Overview.md @@ -0,0 +1,28 @@ +--- +alias: ieshoo5ohm +description: Learn how to use the Prisma command line +--- + +# Overview + +The Prisma command line interface (CLI) is the primary tool to manage your database services with Prisma. + +Generally, the configuration of a Prisma service is handled using the CLI and the service definition file [`prisma.yml`](!alias-foatho8aip). + +A central part of configuring a Prisma service is deploying a [data model](!alias-eiroozae8u). + +## Getting Started + +You can download the Prisma CLI from npm: + +``` +npm install -g prisma +``` + +To initialize a new service, use the `init` command: + +``` +prisma init +``` + +In the following sections you'll learn more about configuring Prisma services using the CLI. diff --git a/docs/1.1/04-Reference/01-Service-Configuration/02-prisma.yml/01-Overview-&-Example.md b/docs/1.1/04-Reference/01-Service-Configuration/02-prisma.yml/01-Overview-&-Example.md new file mode 100644 index 0000000000..d2f00a1cbc --- /dev/null +++ b/docs/1.1/04-Reference/01-Service-Configuration/02-prisma.yml/01-Overview-&-Example.md @@ -0,0 +1,92 @@ +--- +alias: foatho8aip +description: Overview +--- + +# Overview + +Every Prisma service consists of several components that developers can provide, such as the service name, the data model for the service, information about deployment and authentication or the configuration of event subscriptions functions. + +All of these components are set up in the configuration file for a service: `prisma.yml`. + +## Example + +Here is a simple example of a service definition file: + +```yml +# REQUIRED +# `my-demo-app` is the name of this Prisma service. +service: my-demo-app + +# REQUIRED +# This service is based on the type definitions in the two files +# `database/types.graphql` and `database/enums.graphql` +datamodel: + - database/types.graphql + - database/enums.graphql + +# OPTIONAL +# The service will be deployed to the `local` cluster. +# Note that if you leave out this option, you will be +# asked which cluster to deploy to, and your decision +# will be persisted here. +cluster: local + +# REQUIRED +# This service will be deployed to the `dev` stage. +stage: dev + +# OPTIONAL (default: false) +# Whether authentication is required for this service +# is based on the value of the `PRISMA_DISABLE_AUTH` +# environment variable. +disableAuth: ${env:PRISMA_DISABLE_AUTH} + +# OPTIONAL +# If your Prisma service requires authentication, this is the secret for creating JWT tokens. +secret: + +# OPTIONAL +# Path where the full GraphQL schema will be written to +# after deploying. Note that it is generated based on your +# data model. +schema: schemas/prisma.graphql + +# OPTIONAL +# This service has one event subscription configured. The corresponding +# subscription query is located in `database/subscriptions/welcomeEmail.graphql`. +# When the subscription fires, the specified `webhook` is invoked via HTTP. +subscriptions: + sendWelcomeEmail: + query: database/subscriptions/sendWelcomeEmail.graphql + webhook: + url: https://${self.custom:serverlessEndpoint}/sendWelcomeEmail + headers: + Authorization: ${env:MY_ENDPOINT_SECRET} + +# OPTIONAL +# Points to a `.graphql` file containing GraphQL operations that will be +# executed when initially deploying a service. +seed: + import: database/seed.graphql + +# OPTIONAL +# This service only defines one custom variable that's referenced in +# the `webhook` of the `subscription` +custom: + serverlessEndpoint: https://bcdeaxokbj.execute-api.eu-west-1.amazonaws.com/dev +``` + +This service definition expects the following file structure: + +``` +. +├── prisma.yml +├── database +│   ├── subscriptions +│   │   └── welcomeEmail.graphql +│   ├── types.graphql +│   └── enums.graphql +└── schemas +    └── prisma.graphql +``` diff --git a/docs/1.1/04-Reference/01-Service-Configuration/02-prisma.yml/02-YAML-Structure.md b/docs/1.1/04-Reference/01-Service-Configuration/02-prisma.yml/02-YAML-Structure.md new file mode 100644 index 0000000000..b62da6d2af --- /dev/null +++ b/docs/1.1/04-Reference/01-Service-Configuration/02-prisma.yml/02-YAML-Structure.md @@ -0,0 +1,304 @@ +--- +alias: ufeshusai8 +description: YAML Structure +--- + +# YAML Structure + +## Overview + +The service definition file `prisma.yml` has the following root properties: + +- `service` (required): Name of the Prisma service +- `datamodel` (required): Type definitions for database models, relations, enums and other types +- `stage` (required): The stage of the Prisma service to deploy to +- `cluster`: The cluster name to deploy to. Can be omitted to prompt interactive cluster selection. +- `disableAuth`: Disable authentication for the endpoint +- `secret`: Secret for securing the API endpoint +- `subscriptions`: Configuration of subscription functions +- `seed`: Instructions for data seeding +- `custom`: Use to provide variables which can be referenced from other fields + +> The exact structure of `prisma.yml` is defined with [JSON schema](http://json-schema.org/). You can find the corresponding schema definition [here](https://github.com/graphcool/graphcool-json-schema/blob/master/src/schema.json). + +## `service` (required) + +The service defines the service name which will also be reflected in the endpoint for your service once it's deployed. The service name must follow these requirements: + +- must contain only alphanumeric characters, hyphens and underscores +- must start with an uppercase or lowercase letter +- must be at most 64 characters long + +#### Type + +The `service` property expects a **string**. + +#### Examples + +Define a service called `hello-word`. + +```yml +service: hello-world +``` + +Define a service called `DEMO_APP123`. + +```yml +service: My-DEMO_APP123 +``` + +## `datamodel` (required) + +The `datamodel` points to one or more `.graphql`-files containing type definitions written in the [SDL](https://blog.graph.cool/graphql-sdl-schema-definition-language-6755bcb9ce51). If multiple files are provided, the CLI will simply concatenate their contents at deployment time. + +#### Type + +The `datamodel` property expects a **string** or a **list of strings**. + +#### Examples + +The data model is defined in a file called `types.graphql`. + +```yml +datamodel: types.graphql +``` + +The data model is defined in two files called `types.graphql` and `enums.graphl`. When deployed, the contents of both files will be concatenated by the CLI. + +```yml +datamodel: + - types.graphql + - enums.graphql +``` + +## `stage` (required) + +The `stage` property defines the deployment target name to which you can deploy your service. + +#### Type + +The `stage` property expects a **string** that denotes the name of the stage. + +#### Examples + +Define a `dev` stage: + +```yml +stage: dev +``` + +Read the stage from an environment variable: + +```yml +stage: ${env:MY_STAGE} +``` + +## `cluster` (optional) + +The cluster defines the cluster to which the service will be deployed to. It refers to clusters in the global registry, `~/.prismarc`. + +- must contain only alphanumeric characters, hyphens and underscores +- must start with an uppercase or lowercase letter +- must be at most 64 characters long + +If the `cluster` property is omitted, an interactive selection is prompted. + +#### Type + +The `cluster` property expects a **string**. + +#### Examples + +Refer to the `local` cluster. + +```yml +cluster: local +``` + +## `disableAuth` (optional) + +The `disableAuth` property indicates whether the Prisma service requires authentication. If set to `true`, anyone has full read/write-access to the database! + +Setting `disableAuth` is optional. If not set, the default is `false` (which means authentication is enabled by default). + +#### Type + +The `disableAuth` property expects a **boolean**. + +#### Examples + +Disable authentication in your Prisma service. + +```yml +disableAuth: true +``` + +Enable authentication in your Prisma service. + +```yml +disableAuth: false +``` + +## `secret` (optional) + +A secret is used to generate (or _sign_) authentication tokens ([JWT](https://jwt.io)). If your Prisma service requires authentication, one of these authentication tokens needs to be attached to the HTTP request (in the `Authorization` header field). A secret must follow these requirements: + +- must be [utf8](https://en.wikipedia.org/wiki/UTF-8) encoded +- must not contain spaces +- must be at most 256 characters long + +Note that it's possible to encode multiple secrets in this string, which allows smoothless secret rotation. + +Read more about Database [authentication here](!alias-utee3eiquo#authentication). + +#### Type + +The `secret` property expects a **string** (not a list of strings). If you want to specify multiple secrets, you need to provide them as a comma-separated list (spaces are ignored), but still as a single string value. + +#### Examples + +Define one secret with value `moo4ahn3ahb4phein1eingaep`. + +```yml +secret: moo4ahn3ahb4phein1eingaep +``` + +Define three secrets with values `myFirstSecret`, `SECRET_NUMBER_2` and `3rd-secret`. Note that the spaces before the second secret are ignored. + +```yml +secret: myFirstSecret, SECRET_NUMBER_2,3rd-secret +``` + +Use the value of the `MY_SECRET` environment variable as the secret(s). + +```yml +secret: ${env:MY_SECRET} +``` + +## `schema` (optional) + +Upon every deploy of your service, the CLI will generate the service's _database schema_ (typically called `database.graphql`). This file contains the definitions of all CRUD operations for the types defined in your data model. + +The `schema` property specifies the file path indicating where the CLI should store the generated file. + +Specifying `schema` is optional. If not set, the CLI will not generate and store the database schema! + +#### Type + +The `schema` property expects a **string**. + +#### Example + +Store the database schema in the root directory of the service and call it `database.graphql`. + +```yml +schema: database.graphql +``` + +Store the database schema in the `src/schemas` directory of the service and call it `database.graphql`. + +```yml +schema: src/schemas/database.graphql +``` + +## `subscriptions` (optional) + +The `subscriptions` property is used to define all the event subscription functions for your Prisma service. Event subscriptions need (at least) two pieces of information: + +- a _subscription query_ that defines upon which event a function should be invoked and what the payload looks like +- the URL of a _webhook_ which is invoked via HTTP once the event happens +- (optionally) a number of HTTP headers to be attached to the request that's sent to the URL + +#### Type + +The `subscriptions` property expects an **object** with the following properties: + +- `query` (required): The file path to the _subscription query_. +- `webhook` (required): Information (URL and optionally HTTP headers) about the webhook to be invoked. If there are no headers, you can provide the URL to this property directly (see first example below). Otherwise, `webhook` takes another object with properties `url` and `headers` (see second example below). + +#### Examples + +Specify one event subscription without HTTP headers. + +```yml +subscriptions: + sendWelcomeEmail: + query: database/subscriptions/sendWelcomeEmail.graphql + webhook: https://bcdeaxokbj.execute-api.eu-west-1.amazonaws.com/dev/sendWelcomeEmail +``` + +Specify one event subscription with two HTTP headers. + +```yml +subscriptions: + sendWelcomeEmail: + query: database/subscriptions/sendWelcomeEmail.graphql + webhook: + url: https://bcdeaxokbj.execute-api.eu-west-1.amazonaws.com/dev/sendWelcomeEmail + headers: + Authorization: ${env:MY_ENDPOINT_SECRET} + Content-Type: application/json +``` + +## `seed` (optional) + +Database seeding is a standardised way to populate a service with test data. + +#### Type + +The `seed` property expects an **object**, with either one of two sub-properties: + +* `import`: instructions to import data when seeding a service. You can refer to two kinds of files: + * either a path to a `.graphql` file with GraphQL operations + * or a path to a `.zip` file that contains a data set in [Normalized Data Format (NDF)](!alias-teroo5uxih) +* `run`: shell command that will be executed when seeding a service. This is meant for more complex seed setups that are not covered by `import`. + +> Note: `run` is currently not supported. Follow [the proposal](https://github.com/graphcool/framework/issues/1181) to stay informed. + +Seeds are implicitely executed when deploying a service for the first time (unless explicitely disabled using the `--no-seed` flag). Track [this feature request for additional seeding workflows](https://github.com/graphcool/prisma/issues/1536). + +#### Examples + +Refer to a `.graphql` file containing seeding mutations: + +```yml +seed: + import: database/seed.graphql +``` + +Refer to a `.zip` file with a data set in NDF: + +```yml +seed: + import: database/backup.zip +``` + +Run a Node script when seeding: + +```yml +seed: + run: node script.js +``` + +## `custom` (optional) + +The `custom` property lets you specify any sorts of values you want to resuse elsewhere in your `prisma.yml`. It thus doesn't have a predefined structure. You can reference the values using variables with the `self` variable source, e.g.: `${self.custom.myVariable}`. + +#### Type + +The `custom` property expects an **object**. There are no assumptions about the shape of the object. + +#### Examples + +Define two custom values and reuse them in the definition of the event subscription. + +```yml +custom: + serverlessEndpoint: https://bcdeaxokbj.execute-api.eu-west-1.amazonaws.com/dev + subscriptionQueries: database/subscriptions/ + +subscriptions: + sendWelcomeEmail: + query: ${self.custom:subscriptionQueries}/sendWelcomeEmail.graphql + webhook: https://${self.custom:serverlessEndpoint}/sendWelcomeEmail +``` diff --git a/docs/1.1/04-Reference/01-Service-Configuration/02-prisma.yml/03-Using-Variables.md b/docs/1.1/04-Reference/01-Service-Configuration/02-prisma.yml/03-Using-Variables.md new file mode 100644 index 0000000000..1f4550784d --- /dev/null +++ b/docs/1.1/04-Reference/01-Service-Configuration/02-prisma.yml/03-Using-Variables.md @@ -0,0 +1,91 @@ +--- +alias: nu5oith4da +description: Variables +--- + +# Using Variables + +Variables allow you to dynamically replace configuration values in your service definition file `prisma.yml`. + +To use variables inside `prisma.yml`, you need to reference the values enclosed in `${}` brackets. Inside the brackes, you first need to specify the _variable source_ and the _variable name_, separated by a colon. + +```yml +# prisma.yml file +yamlKeyXYZ: ${src:myVariable} # see list of current variable sources below +# this is an example of providing a default value as the second parameter +otherYamlKey: ${src:myVariable, defaultValue} +``` + +A _variable source_ can be either of the following three options: + +- An _environment variable_ +- A _self-reference_ to another value inside the same service +- An _option from the command line_ + +> Note that you can only use variables in property **values** - not in property keys. + +### Environment variables + +You can reference environment variables inside the service definition file. + +When using an environment variable, the value that you put into the bracket is composed of: + +- the _prefix_ `env:` +- the _name_ of the environment variable + +In the following example, environment variables are used to declare the stage, the cluster and the secret the `example` service: + +```yml +service: example +stage: ${env:PRISMA_STAGE} +cluster: ${env:PRISMA_CLUSTER} +secret: ${env:PRISMA_SECRET} +datamodel: database/datamodel.graphql +``` + +Note that the CLI will load environment variables from 3 different locations and in the following order: + +1. The local environment +1. A file specified with the `--dotenv` parameter +1. if the `--dotenv`argument was omitted, a file called `.env` in the same directory + +### Self-references + +You can recursively reference other property values inside the same `prisma.yml` file. + +When using a recursive self-reference as a variable, the value that you put into the bracket is composed of: + +- the _prefix_ `self:` +- (optional) the _path_ to the referenced property + +> If no path is specified, the value of the variable will be the full YAML file. + +In the following example, the `createCRMEntry` function uses the same subscription query as the `sendWelcomeEmail` function: + +```yml +subscriptions: + sendWelcomeEmail: + query: database/subscriptions/createUserSubscription.graphql + webhook: + url: ${self.custom.severlessEndpoint}/sendWelcomeEmail + headers: ${self.custom.headers} + createCRMEntry: + query: ${self:functions.subscriptions.sendWelcomeEmail.query} + webhook: + url: ${self.custom.severlessEndpoint}/createCRMEntry + headers: ${self.custom.headers} + +custom: + serverlessEndpoint: 'https://bcdeaxokbj.execute-api.eu-west-1.amazonaws.com/dev' + headers: + Authorization: Bearer wohngaeveishuomeiphohph1ls +``` + +### CLI options + +You can reference CLI options that are passed when invoking a `prisma` command. + +When referencing a CLI option, the value that you put into the bracket is composed of: + +- the _prefix_ `opt:` +- the _name_ of the CLI option diff --git a/docs/1.1/04-Reference/01-Service-Configuration/02-prisma.yml/index.md b/docs/1.1/04-Reference/01-Service-Configuration/02-prisma.yml/index.md new file mode 100644 index 0000000000..061a98d1d3 --- /dev/null +++ b/docs/1.1/04-Reference/01-Service-Configuration/02-prisma.yml/index.md @@ -0,0 +1,3 @@ +--- +description: Learn about. +--- diff --git a/docs/1.1/04-Reference/01-Service-Configuration/03-Data-Modelling-(SDL).md b/docs/1.1/04-Reference/01-Service-Configuration/03-Data-Modelling-(SDL).md new file mode 100644 index 0000000000..2e1659d816 --- /dev/null +++ b/docs/1.1/04-Reference/01-Service-Configuration/03-Data-Modelling-(SDL).md @@ -0,0 +1,646 @@ +--- +alias: eiroozae8u +description: An overview of how to design data models with Prisma. +--- + +# Data Modelling + +## Overview + +Prisma uses the GraphQL [Schema Definition Language](https://blog.graph.cool/graphql-sdl-schema-definition-language-6755bcb9ce51) (SDL) for data modeling. Your data model is written in one or more `.graphql`-files and is the foundation for the actual database schema that Prisma generates under the hood. If you're using just a single file for your type definitions, this file is typically called `datamodel.graphql`. + +> To learn more about the SDL, you can check out the [official GraphQL documentation](http://graphql.org/learn/schema/#type-language). + +The `.graphql`-files containing the data model need to be specified in `prisma.yml` under the `datamodel` property. For example: + +```yml +datamodel: + - types.graphql + - enums.graphql +``` + +If there is only a single file that defines the data model, it can be specified as follows: + +```yml +datamodel: datamodel.graphql +``` + +The data model is the foundation for the GraphQL API of your Prisma service. Based on the data model, Prisma will generate a powerful [GraphQL schema](https://blog.graph.cool/graphql-server-basics-the-schema-ac5e2950214e) (called **Prisma database schema**) which defines CRUD operations for the types in the data model. + + + +A GraphQL schema defines the operations of a GraphQL API. It effectively is a collection of _types_ written in SDL (the SDL also supports primitives like interfaces, enums, union types and more, you can learn everything about GraphQL's type system [here](http://graphql.org/learn/schema/#type-system)). A GraphQL schema has three special _root types_: `Query`, `Mutation` and `Subscription`. These types define the _entry points_ for the API and define what operations the API will accept. To learn more about GraphQL schema, check out this [article](https://blog.graph.cool/graphql-server-basics-the-schema-ac5e2950214e). + + + +### Example + +A simple `datamodel.graphql` file: + +```graphql +type Tweet { + id: ID! @unique + createdAt: DateTime! + text: String! + owner: User! + location: Location! +} + +type User { + id: ID! @unique + createdAt: DateTime! + updatedAt: DateTime! + handle: String! @unique + name: String + tweets: [Tweet!]! +} + +type Location { + latitude: Float! + longitude: Float! +} +``` + +This example illustrates a few important concepts when working with your data model: + +* The three types `Tweet`, `User` and `Location` are mapped to tables in the database. +* There is a bidirectional relation between `User` and `Tweet` +* There is a unidirectional relation from `Tweet` to `Location` +* Except for the `name` field on `User`, all fields are required in the data model (as indicated by the `!` following the type). +* The `id`, `createdAt` and `updatedAt` fields are managed by Prisma and read-only in the exposed GraphQL API (meaning they can not be altered via mutations). + +Creating and updating your data model is as simple as writing a text file. Once you're happy with your data model, you can apply the changes to your Prisma service by running `prisma deploy`: + +```sh +$ prisma deploy + +Changes: + + Tweet (Type) + + Created type `Tweet` + + Created field `id` of type `GraphQLID!` + + Created field `createdAt` of type `DateTime!` + + Created field `text` of type `String!` + + Created field `owner` of type `Relation!` + + Created field `location` of type `Relation!` + + Created field `updatedAt` of type `DateTime!` + + User (Type) + + Created type `User` + + Created field `id` of type `GraphQLID!` + + Created field `createdAt` of type `DateTime!` + + Created field `updatedAt` of type `DateTime!` + + Created field `handle` of type `String!` + + Created field `name` of type `String` + + Created field `tweets` of type `[Relation!]!` + + Location (Type) + + Created type `Location` + + Created field `latitude` of type `Float!` + + Created field `longitude` of type `Float!` + + Created field `id` of type `GraphQLID!` + + Created field `updatedAt` of type `DateTime!` + + Created field `createdAt` of type `DateTime!` + + TweetToUser (Relation) + + Created relation between Tweet and User + + LocationToTweet (Relation) + + Created relation between Location and Tweet + +Applying changes... (22/22) +Applying changes... 0.4s +``` + +### Building blocks of the data model + +There are several available building blocks to shape your data model. + +* [Types](#object-types) consist of multiple [fields](#fields) and are used to group similar entities together. Each type in your data model is mapped to the database and CRUD operations are added to the GraphQL schema. +* [Relations](#relations) describe _relationships_ between types. +* [Interfaces](http://graphql.org/learn/schema/#interfaces) are abstract types that include a certain set of fields which a type must include to _implement_ the interface. Currently, interfaces cannot be user-defined, but [there's a pending feature request](https://github.com/graphcool/framework/issues/83) for advanced interface support. +* Special [directives](#graphql-directives) covering different use cases such as type constraints or cascading delete behaviour. + +The rest of this page describes these building blocks in more detail. + +## Prisma database schema vs Data model + +When starting out with GraphQL and Prisma, the amount of `.graphql`-files you're working with can be confusing. Yet, it's crucial to understand what the role of each of them is. + +In general, a `.graphql`-file can contain either of the following: + +- GraphQL operations (i.e. _queries_, _mutations_ or _subscriptions_) +- GraphQL type definitions in SDL + +In the context of distinguishing the Prisma database schema from the data model, only the latter is relevant! + +Note that not every `.graphql`-file that falls into the latter category is per se a _valid_ GraphQL schema. As mentioned in the info box above, a GraphQL schema is characterised by the fact that it has three root types: `Query`, `Mutation` and `Subscription` in addition to any other types that are required for the API. + +Now, by that definition the **data model is not actually a GraphQL schema**, despite being a `.graphql`-file written in SDL. It lacks the root types and thus doesn't actually define API operations! Prisma simply uses the data model as a handy tool for you to express what the data model looks like. + +As mentioned above, Prisma will then generate an actual GraphQL schema that contains the `Query`, `Mutation` and `Subscription` root types. This schema is typically stored inside your project as `prisma.graphql` and called the **Prisma database schema**. Note that you should never make any manual changes to this file! + +As an example, consider the following very simple data model: + +**`datamodel.graphql`** + +```graphql +type User { + id: ID! @uniue + name: String! +} +``` + +If you're deploying this data model to your Prisma service, Prisma will generate the following Prisma database schema that defines the GraphQL API of your service: + +**`prisma.graphql`** + +```graphql +type Query { + users(where: UserWhereInput, orderBy: UserOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [User]! + user(where: UserWhereUniqueInput!): User +} + +type Mutation { + createUser(data: UserCreateInput!): User! + updateUser(data: UserUpdateInput!, where: UserWhereUniqueInput!): User + deleteUser(where: UserWhereUniqueInput!): User +} + +type Subscription { + user(where: UserSubscriptionWhereInput): UserSubscriptionPayload +} +``` + +Note that this is a simplified version of the generated schema, you can find the full schema [here](https://gist.github.com/gc-codesnippets/f302c104f2806f9e13f41d909e07d82d). + + + +If you've already looked into building your own GraphQL server based on Prisma, you might have come across another `.graphql`-file which is referred to as your **application schema**. This is another proper GraphQL schema (meaning it contains the `Query`, `Mutation` and `Subscription` root types) that defines the API exposed to your client applications. It uses the underlying Prisma GraphQL API as a "query engine" to actually run the queries, mutations and subscriptions against the database. + +A GraphQL server based on Prisma usually has two GraphQL APIs, think of them as two layers for your service: + +- **Application layer**: Defined by the application schema (here is where you implement business logic, authentication, integrate with 3rd-party services, etc) +- **Database layer**: Defined by the Prisma database service + + + +## Object types + +An _object type_ (or short _type_) defines the structure for one concrete part of your data model. It is used to represents _entities_ from your _application domain_. + + If you are familiar with SQL databases you can think of an object type as the schema for a _table_ in your relational database. A type has a _name_ and one or multiple _[fields](#fields)_. + +An instantiation of a type is called a _node_. This term refers to a node inside your _data graph_. +Every type you define in your data model will be available as an analogous type in the generated _Prisma database schema_. + +### Defining an object type + +A object type is defined in the data model with the keyword `type`: + +```graphql +type Article { + id: ID! @unique + text: String! + isPublished: Boolean @default(value: "false") +} +``` + +The type defined above has the following properties: + +* Name: `Article` +* Fields: `id`, `text` and `isPublished` (with the default value `false`) + +### Generated operations based on types + +The types in your data model affect the available operations in the [Prisma GraphQL API](!alias-abogasd0go). For every type, + +* [queries](!alias-ahwee4zaey) allow you to fetch one or many nodes of that type +* [mutations](!alias-ol0yuoz6go) allow you to create, update or delete nodes of that type +* [subscriptions](!alias-aey0vohche) allow you to get notified of changes to nodes of that type (i.e. new nodes are _created_ or existing nodes are _updated_ or _deleted_) + +## Fields + +_Fields_ are the building blocks of a [type](#object-types), giving a node its _shape_. Every field is referenced by its name and is either [scalar](#scalar-types) or a [relation](#relations) field. + +### Scalar types + +#### String + +A `String` holds text. This is the type you would use for a username, the content of a blog post or anything else that is best represented as text. + +Note: String values are currently limited to 256KB in size on the shared demo cluster. This limit can be increased on other clusters using [the cluster configuration](https://github.com/graphcool/framework/issues/748). + +In queries or mutations, String fields have to be specified using enclosing double quotes: `string: "some-string"`. + +#### Integer + +An `Int` is a number that cannot have decimals. Use this to store values such as the weight of an ingredient required for a recipe or the minimum age for an event. + +Note: `Int` values range from -2147483648 to 2147483647. + +In queries or mutations, `Int` fields have to be specified without any enclosing characters: `int: 42`. + +#### Float + +A `Float` is a number that can have decimals. Use this to store values such as the price of an item in a store or the result of complex calculations. + +In queries or mutations, `Float` fields have to be specified without any enclosing characters and an optional decimal point: `float: 42`, `float: 4.2`. + +#### Boolean + +A `Boolean` can have the value `true` or `false`. This is useful to keep track of settings such as whether the user wants to receive an email newsletter or if a recipe is appropriate for vegetarians. + +In queries or mutations, `Boolean` fields have to be specified without any enclosing characters: `boolean: true`, `boolean: false`. + +#### DateTime + +The `DateTime` type can be used to store date or time values. A good example might be a person's date of birth. + +In queries or mutations, `DateTime` fields have to be specified in [ISO 8601 format](https://en.wikipedia.org/wiki/ISO_8601) with enclosing double quotes: + +* `datatime: "2015"` +* `datatime: "2015-11"` +* `datatime: "2015-11-22"` +* `datetime: "2015-11-22T13:57:31.123Z"`. + +#### Enum + +Enums are defined on a service scope. + +Like a Boolean an Enum can have one of a predefined set of values. The difference is that you can define the possible values. For example you could specify how an article should be formatted by creating an Enum with the possible values `COMPACT`, `WIDE` and `COVER`. + +Note: Enum values can at most be 191 characters long. + +In queries or mutations, Enum fields have to be specified without any enclosing characters. You can only use values that you defined for the enum: `enum: COMPACT`, `enum: WIDE`. + +#### JSON + +Sometimes you need to store arbitrary JSON values for loosely structured data. The `JSON` type makes sure that it is actually valid Json and returns the value as a parsed Json object/array instead of a string. + +Note: Json values are currently limited to 256KB in size on the shared demo cluster. This limit can be increased on other clusters using [the cluster configuration](https://github.com/graphcool/framework/issues/748). + +In queries or mutations, Json fields have to be specified with enclosing double quotes. Special characters have to be escaped: `json: "{\"int\": 1, \"string\": \"value\"}"`. + +#### ID + +An ID value is a generated unique 25-character string based on [cuid](https://github.com/graphcool/cuid-java). Fields with ID values are system fields and just used internally, therefore it is not possible to create new fields with the ID type. + +### Type modifiers + +#### List + +Scalar fields can be marked with the list field type. A field of a relation that has the many multiplicity will also be marked as a list. + +In queries or mutations, list fields have to be enclosed by square brackets, while the separate entries of the list adhere to the same formatting rules as lined out above: `listString: ["a string", "another string"]`, `listInt: [12, 24]`. + +#### Required + +Fields can be marked as required (sometimes also referred to as "non-null"). When creating a new node, you need to supply a value for fields which are required and don't have a [default value](#default-value). + +Required fields are marked using a `!` after the field type: `name: String!`. + +### Field constraints + +Fields can be configured with certain field constraints to add further semantics to your data model. + +#### Unique + +Setting the _unique_ constraint makes sure that two nodes of the type in question cannot have the same value for a certain field. The only exception is the `null` value, meaning that multiple nodes can have the value `null` without violating the constraint. + +> A typical example would be an `email` field on the `User` type where the assumption is that every `User` should have a globally unique email address. + +Please note that only the first 191 characters in a String field are considered for uniqueness and the unique check is **case insensitive**. Storing two different strings is not possible if the first 191 characters are the same or if they only differ in casing. + +To mark a field as unique, simply append the `@unique` directive to it: + +```graphql +type User { + email: String! @unique + age: Int! +} +``` + +For every field that's annotated with `@unique`, you're able to query the corresponding node by providing a value for that field. + +For example, for the above data model, you can now retrieve a particular `User` node by its `email` address: + +```graphql +query { + user(where: { + email: "alice@graph.cool" + }) { + age + } +} +``` + +#### More constraints + +More database constraints will be added going forward according to this [feature request](https://github.com/graphcool/graphcool/issues/728). + +### Default value + +You can set a default value for scalar fields. The value will be taken for new nodes when no value was supplied during creation. + +To specify a default value for a field, you can use the `@default` directive: + +```graphql +type Story { + isPublished: Boolean @default(value: "false") +} +``` + +Notice that you need to always provide the value in double-quotes, even for non-string types such as `Boolean` or `Int`. + +### System fields + +The three fields `id`, `createdAt` and `updatedAt` have special meaning. They are optional in your data model, but will always be maintained in the underlying database. This way you can always add the field to your data model later, and the data will be available for existing nodes. + +> The values of these fields are currently read-only in the GraphQL API (except when [importing data](!alias-ol2eoh8xie)) but will be made configurable in the future. See [this proposal](https://github.com/graphcool/framework/issues/1278) for more information. + + + +Notice that you cannot have custom fields that are called `id`, `createdAt` and `updatedAt` since these field names are reserved for the system fields. Here are the only supported declarations for these three fields: + +* `id: ID! @unique` +* `createdAt: DateTime!` +* `updatedAt: DateTime!` + + + +#### System field: `id` + +A node will automatically get assigned a globally unique identifier when it's created, this identifier is stored in the `id` field. + +Whenever you add the `id` field to a type definition to expose it in the GraphQL API, you must annotate it with the `@unique` directive. + +The `id` has the following properties: + +* Consists of 25 alphanumeric characters (letters are always lowercase) +* Always starts with a (lowercase) letter `c` +* Follows [cuid](https://github.com/ericelliott/cuid) (_collision resistant unique identifiers_) scheme + +Notice that all your object types will implement the `Node` interface in the database schema. This is what the `Node` interface looks like: + +```graphql +interface Node { + id: ID! @unique +} +``` + +#### System fields: `createdAt` and `updatedAt` + +The data model further provides two special fields which you can add to your types: + +* `createdAt: DateTime!`: Stores the exact date and time for when a node of this object type was _created_. +* `updatedAt: DateTime!`: Stores the exact date and time for when a node of this object type was _last updated_. + +If you want your types to expose these fields, you can simply add them to the type definition, for example: + +```graphql +type User { + id: ID! @unique + createdAt: DateTime! + updatedAt: DateTime! +} +``` + +### Generated operations based on fields + +Fields in the data model affect the available [query arguments](!alias-ahwee4zaey#query-arguments). + +## Relations + +A _relation_ defines the semantics of a connection between two [types](#object-types). Two types in a relation are connected via a [relation field](#scalar-and-relation-fields). When a relation might be ambiguous, the relation field needs to be annotated with the [`@relation`](#relation-fields) directive to disambiguate it. + +A relation can also connect a type with itself. It is then referred to as a _self-relation_. + +### Required relations + +For a _to-one_ relation field, you can configure whether it is _required_ or _optional_. The required flag acts as a contract in GraphQL that this field can never be `null`. A field for the address of a user would therefore be of type `Address` or `Address!`. + +Nodes for a type that contains a required _to-one_ relation field can only be created using a [nested mutation](!alias-ol0yuoz6go#nested-mutations) to ensure the according field will not be `null`. + +> Note that a _to-many_ relation field is always set to required. For example, a field that contains many user addresses always uses the type `[Address!]!` and can never be of type `[Address!]`. The reason is that in case the field doesn't contain any nodes, `[]` will be returned, which is not `null`. + +### The `@relation` directive + +When defining relations between types, there is the `@relation` directive which provides meta-information about the relation. It can take two arguments: + +* `name`: An identifier for this relation (provided as a string). This argument is only required if relations are ambiguous. +* `onDelete` ([pending feature request](https://github.com/graphcool/framework/issues/1262)): Specifies the _deletion behaviour_. (In case a node with related nodes gets deleted, the deletion behaviour determines what should happen to the related node(s).) The input values for this argument are defined as an enum with the following possible values: + * `NO_ACTION` (default): Keep the related node + * `CASCADE`: Delete the related node + * `SET_NULL`: Set the related node to `null` + +#### Omitting the `@relation` directive + +In the simplest case, where a relation between two types is unambiguous and the default deletion behaviour (`NO_ACTION`) should be applied, the corresponding relation fields do not have to be annotated with the `@relation` directive: + +```graphql +type User { + id: ID! @unique + stories: [Story!]! +} + +type Story { + id: ID! @unique + text: String! + author: User! +} +``` + +Here we are defining a _one-to-many_ relation between the `User` and `Story` types. Since `onDelete` has not been provided, the default deletion behaviour is used: `NO_ACTION`. The semantics of this deletion behaviour are that stories and users can exists completely independently from another: When a `User` node is deleted, the nodes from its `stories` field will remain to exist. Likewise, when a `Story` node is deleted, the corresponding `author` node will remain to exist. + +#### Using the `name` argument of the `@relation` directive + +In certain cases, your data model may contain ambiguous relations. For example, consider you not only want a relation to express the "author-relationship" between `User` and `Story`, but you also want a relation to express which `Story` nodes have been _liked_ by a `User`. + +In that case, you end up with two different relations between `User` and `Story`! In order to disambiguate them, you need to give the relation a name: + +```graphql +type User { + id: ID! @unique + writtenStories: [Story!]! @relation(name: "WrittenStories") + likedStories: [Story!]! @relation(name: "LikedStories") +} + +type Story { + id: ID! @unique + text: String! + author: User! @relation(name: "WrittenStories") + likedBy: [User!]! @relation(name: "LikedStories") +} +``` + +If the `name` wasn't provided in this case, there would be no way to decide whether `writtenStories` should relate to the `author` or the `likedBy` field. + +#### Using the `onDelete` argument of the `@relation` directive + +As mentioned above, you can specify a dedicated deletion behaviour for the related nodes. That's what the `onDelete` argument of the `@relation` directive is for. + +Consider the following example: + +```graphql +type User { + id: ID! @unique + comments: [Comment!]! @relation(name: "CommentAuthor", onDelete: CASCADE) + blog: Blog @relation(name: "BlogOwner", onDelete: CASCADE) +} + +type Blog { + id: ID! @unique + comments: [Comment!]! @relation(name: "Comments", onDelete: CASCADE) + owner: User! @relation(name: "BlogOwner", onDelete: SET_NULL) +} + +type Comment { + id: ID! @unique + blog: Blog! @relation(name: "Comments", onDelete: NO_ACTION) + author: User @relation(name: "CommentAuthor", onDelete: NO_ACTION) +} +``` + +Let's investigate the deletion behaviour for the three types: + +* When a `User` node gets deleted: + * all related `Comment` nodes will be deleted + * the related `Blog` node will be deleted +* When a `Blog` node gets deleted: + * all related `Comment` nodes will be deleted + * the related `User` node will have its `blog` field set to `null` +* When a `Comment` node gets deleted: + * the related `Blog` node continues to exist + * the related `User` node continues to exist + +### Generated operations based on relations + +The relations that are included in your schema affect the available operations in the [GraphQL API](!alias-abogasd0go). For every relation, + +* [relation queries](!alias-ahwee4zaey#querying-data-across-relations) allow you to query data across types or aggregated for a relation (note that this is also possible using [Relay](https://facebook.github.io/relay/)'s [connection model](!alias-ahwee4zaey#connection-queries)) +* [nested mutations](!alias-ol0yuoz6go#nested-mutations) allow you to create, connect, update, upsert and delete nodes across types +* [relation subscriptions](!alias-aey0vohche#relation-subscriptions) allow you to get notified of changes to a relation + +## GraphQL directives + +Directives are used to provide additional information in your data model. They look like this: `@name(argument: "value")` or simply `@name` when there are no arguments + +### Data model directives + +Data model directives describe additional information about types or fields in the GraphQL schema. + +#### Unique scalar fields + +The `@unique` directive marks a scalar field as [unique](#unique). Unique fields will have a unique _index_ applied in the underlying database. + +```graphql +# the `User` type has a unique `email` field +type User { + email: String @unique +} +``` + +Find more info about the `@unique` directive [above](#unique). + +#### Relation fields + +The directive `@relation(name: String, onDelete: ON_DELETE! = NO_ACTION)` can be attached to a relation field. + +[See above](#the-relation-directive) for more information. + +#### Default value for scalar fields + +The directive `@default(value: String!)` sets [a default value](#default-value) for a scalar field. Note that the `value` argument is of type String for all scalar fields (even if the fields themselves are not strings): + +```graphql +# the `title`, `published` and `someNumber` fields have default values `New Post`, `false` and `42` +type Post { + title: String! @default(value: "New Post") + published: Boolean! @default(value: "false") + someNumber: Int! @default(value: "42") +} +``` + +### Temporary directives + +Temporary directives are used to perform one-time migration operations. After deploying a service that contain a temporary directive, it **needs to be manually removed from the type definitions file**. + +#### Renaming a type or field + +The temporary directive `@rename(oldName: String!)` is used to rename a type or field. + +```graphql +# renaming the `Post` type to `Story`, and its `text` field to `content` +type Story @rename(oldName: "Post") { + content: String @rename(oldName: "text") +} +``` + + + +If the rename directive is not used, Prisma would remove the old type and field before creating the new one, resulting in loss of data! + + + +#### Migrating the value of a scalar field + +The temporary directive `@migrationValue(value: String!)` is used to migrate the value of a scalar field. When changing an optional field to a requried field, it is necessary to also use this directive. + +## Naming conventions + +Different objects you encounter in a Prisma service like types or relations follow separate naming conventions to help you distinguish them. + +### Types + +The type name determines the name of derived queries and mutations as well as the argument names for nested mutations. Type names can only contain **alphanumeric characters** and need to start with an uppercase letter. They can contain **at most 64 characters**. + +_It's recommended to choose type names in the singular form._ + +_Type names are unique on a service level._ + +##### Examples + +* `Post` +* `PostCategory` + +### Scalar and relation fields + +The name of a scalar field is used in queries and in query arguments of mutations. Field names can only contain **alphanumeric characters** and need to start with a lowercase letter. They can contain **at most 64 characters**. + +The name of relation fields follows the same conventions and determines the argument names for relation mutations. + +_It's recommended to only choose plural names for list fields_. + +_Field names are unique on a type level._ + +##### Examples + +* `name` +* `email` +* `categoryTags` + +### Relations + +Relation names can only contain **alphanumeric characters** and need to start with an uppercase letter. They can contain **at most 64 characters**. + +_Relation names are unique on a service level._ + +##### Examples + +* `UserOnPost`, `UserPosts` or `PostAuthor`, with field names `user` and `posts` +* `Appointments`, `EmployeeOnAppointment` or `AppointmentEmployee`, with field names `employee` and `appointments` + +### Enums + +Enum values can only contain **alphanumeric characters and underscores** and need to start with an uppercase letter. The name of an enum value can be used in query filters and mutations. They can contain **at most 191 characters**. + +_Enum names are unique on a service level._ + +_Enum value names are unique on an enum level._ + +##### Examples + +* `A` +* `ROLE_TAG` +* `RoleTag` diff --git a/docs/1.1/04-Reference/01-Service-Configuration/index.md b/docs/1.1/04-Reference/01-Service-Configuration/index.md new file mode 100644 index 0000000000..c958c2aaab --- /dev/null +++ b/docs/1.1/04-Reference/01-Service-Configuration/index.md @@ -0,0 +1,3 @@ +--- +description: Prisma Services turn your database into a GraphQL API. They are configured using the Prisma CLI. +--- diff --git a/docs/1.1/04-Reference/02-Prisma-API/01-Overview.md b/docs/1.1/04-Reference/02-Prisma-API/01-Overview.md new file mode 100644 index 0000000000..409316adfb --- /dev/null +++ b/docs/1.1/04-Reference/02-Prisma-API/01-Overview.md @@ -0,0 +1,22 @@ +--- +alias: ohm2ouceuj +description: How to use the API +--- + +# Overview + +## What is the Prisma API? + +A Prisma service exposes a GraphQL API that is automatically generated based on the deployed [data model](!alias-eiroozae8u). It is also referred to as the **Prisma API**. The Prisma API defines CRUD operations for the types in the data model and allows to get realtime updates when events are happening in the database (e.g. new nodes are _created_ or existing ones _updated_ or _deleted_). + + + +The Prisma API is defined by a corresponding [GraphQL schema](https://blog.graph.cool/graphql-server-basics-the-schema-ac5e2950214e), called [**Prisma database schema**](!alias-eiroozae8u#prisma-database-schema-vs-data-model). + + + +## Exploring the Prisma API + +The [GraphQL Playground](https://github.com/graphcool/graphql-playground) is the best tool to explore the Prisma API and get to know it better. You can use it to run GraphQL mutations, queries and subscriptions. + +To open up a Playground for your database service, simply run the `prisma playground` command in the working directory of your service or paste your service's HTTP endpoint into the address bar of your browser. diff --git a/docs/1.1/04-Reference/02-Prisma-API/02-Concepts.md b/docs/1.1/04-Reference/02-Prisma-API/02-Concepts.md new file mode 100644 index 0000000000..4a0ce5e46a --- /dev/null +++ b/docs/1.1/04-Reference/02-Prisma-API/02-Concepts.md @@ -0,0 +1,253 @@ +--- +alias: utee3eiquo +description: Concepts +--- + +# Concepts + +## Data model and Prisma database schema + +The Prisma API of a Prisma service is fully centered around its data model. + +The API is automatically generated based on the [data model](!alias-eiroozae8u) that's associated with your Prisma service. + +Every operation exposed in the Prisma API is associated with a model or relation from your data model: + +* [Queries](!alias-ahwee4zaey) + * query one or more nodes of a certain model + * query nodes across relations + * query data aggregated across relations +* [Mutations](!alias-ol0yuoz6go) + * create, update, upsert and delete nodes of a certain model + * create, connect, disconnect, update and upsert nodes across relations + * batch update or delete nodes of a certain model +* [Subscriptions](!alias-aey0vohche) + * get notified about created, updated and deleted nodes + +The actual [GraphQL schema](https://blog.graph.cool/graphql-server-basics-the-schema-ac5e2950214e) defining the available GraphQL operations in the Prisma API is also referred to as **Prisma database schema**. + +> You can learn more about the differences between the data model and the prisma database in the [data modelling](!alias-eiroozae8u#prisma-database-schema-vs-data-model) chapter. + +## Advanced API concepts + +### Node selection + +Many operations in the Prisma API only affect a subset of the existing nodes in the database, oftentimes even only a single node. + +In these case, you need a way to ask for specific nodes in the API - most of the time this is done via a `where` argument. + +Nodes can be selected via any field that's annotated with the [`@unique`](!alias-eiroozae8u#unique) directive. + +For the following examples, consider the following simple data model: + +```graphql +type Post { + id: ID! @unique + title: String! + published: Boolean @default(value: "false") +} +``` + +Here are a few scenarios where node selection is required. + +**Retrieve a single node by its `email`**: + +```graphql +query { + post(where: { + id: "ohco0iewee6eizidohwigheif" + }) { + id + } +} +``` + +**Update the `title` of a single node**: + +```graphql +mutation { + updatePost( + where: { + id: "ohco0iewee6eizidohwigheif" + } + data: { + title: "GraphQL is awesome" + } + ) { + id + } +} +``` + +**Update `published` of a many nodes at once** (also see [Batch operations](#batch-operations)): + +```graphql +mutation { + updatePost( + where: { + id_in: ["ohco0iewee6eizidohwigheif", "phah4ooqueengij0kan4sahlo", "chae8keizohmiothuewuvahpa"] + } + data: { + published: true + } + ) { + count + } +} +``` + +### Batch operations + +One application of the node selection concept is the exposed [batch operations](!alias-utee3eiquo#batch-operations). Batch updating or deleting is optimized for making changes to a large number of nodes. As such, these mutations only return _how many_ nodes have been affected, rather than full information on specific nodes. + +For example, the mutations `updateManyPosts` and `deleteManyPosts` provide a `where` argument to select specific nodes, and return a `count` field with the number of affected nodes (see the example above). + +### Connections + +In contrast to the simpler object queries that directly return a list of nodes, connection queries are based on the [Relay Connection](https://facebook.github.io/relay/graphql/connections.htm) model. In addition to pagination information, connections also offer advanced features like aggregation. + +For example, while the `posts` query allows you to select specific `Post` nodes, sort them by some field and paginate over the result, the `postsConnection` query additionally allows you to _count_ all unpublished posts: + +```graphql +query { + postsConnection { + # `aggregate` allows to perform common aggregation operations + aggregate { + count + } + edges { + # each `node` refers to a single `Post` element + node { + title + } + } + } +} +``` + +### Transactional mutations + +Single mutations in the Prisma API that are not batch operations are always executed _transactionally_, even if they consist of many actions that potentially spread across relations. This is especially useful for [nested mutations](!alias-ol0yuoz6go#nested-mutations) that perform several database writes on multiple types. + +An example is creating a `User` node and two `Post` nodes that will be connected, while also connecting the `User` node to two other, already existing `Post` nodes, all in a single mutation. If any of the mentioned actions fail (for example because of a violated `@unique` field constraint), the entire mutation is rolled back! + +Mutations are _transactional_, meaning they are [_atomic_](https://en.wikipedia.org/wiki/Atomicity_(database_systems)) and [_isolated_](https://en.wikipedia.org/wiki/Isolation_(database_systems)). This means that between two separate actions of the same nested mutation, no other mutations can alter the data. Also the result of a single action cannot be observed until the complete mutation has been processed. + +## Authentication + +The GraphQL API of a Prisma service is typically protected by a [`secret`](!alias-ufeshusai8#secret-optional) which you specify in [`prisma.yml`](!alias-foatho8aip). + +The `secret` is used to sign a [JWT](https://jwt.io/) which can then be used in the `Authorization` field of the HTTP header: + +``` +Authorization: Bearer __TOKEN__ +``` + +This is a sample payload for a JWT: + +```json +{ + "exp": 1300819380, + "service": "my-service@prod" +} +``` + +### Claims + +The JWT must contain different [claims](https://jwt.io/introduction/#payload): + +* **Expiration time**: `exp`, the expiration time of the token. +* **Service information**: `service`, the name and stage of the service + +> In the future there might be support for more fine grained access control by introducing a concept of roles such as `["write:Log", "read:*"]` + +### Generating a signed JWT + +#### Prisma CLI + +Run `prisma token` to obtain a new signed JWT for your current Prisma service. + +#### JavaScript + +Consider the following `prisma.yml`: + +```yml +service: my-service + +stage: ${env:PRISMA_STAGE} +cluster: ${env:PRISMA_CLUSTER} + +datamodel: database/datamodel.graphql + +secret: ${env:PRISMA_SECRET} +``` + +> Note that this example uses [environment variables inside `prisma.yml`](!alias-nu5oith4da#environment-variables). + +A Node server could create a signed JWT, based on the [`jsonwebtoken`](https://github.com/auth0/node-jsonwebtoken) library, for the stage `PRISMA_STAGE` of the service `my-service` like this: + +```js +var jwt = require('jsonwebtoken') + +jwt.sign( + { + data: { + service: 'my-service@' + process.env.PRISMA_STAGE, + }, + }, + process.env.PRISMA_SECRET, + { + expiresIn: '1h', + } +) +``` + +### JWT verification + +For requests made against a Prisma service, the following properties of the JWT will be verified: + +* It must be signed with a secret configured for the service +* It must contain an `exp` claim with a time value in the future +* It must contain a `service` claim with service and stage matching the current request + +## Error handling + +When an error occurs for one of your queries or mutations, the response contains an `errors` property with more information about the error `code`, the error `message` and more. + +There are two kind of API errors: + +* **Application errors** usually indicate that your request was invalid. +* **Internal server errors** usually mean that something unexpected happened inside of the Prisma service. Check your service logs for more information. + +> **Note**: The `errors` field behaves according to the offical [GraphQL specification for error handling](http://facebook.github.io/graphql/October2016/#sec-Errors). + +### Application errors + +An error returned by the API usually indicates that something is not correct with the requested query or mutation. You might have accidentally made a typo or forgot a required argument in your query. Try to investigate your input for possible errors related to the error message. + +#### Troubleshooting + +Here is a list of common errors that you might encounter: + +##### Authentication + +###### Insufficient permissions / Invalid token + +```json +{ + "errors": [ + { + "code": 3015, + "requestId": "api:api:cjc3kda1l000h0179mvzirggl", + "message": + "Your token is invalid. It might have expired or you might be using a token from a different project." + } + ] +} +``` + +Check if the token you provided has not yet expired and is signed with a secret listed in [`prisma.yml`](!alias-foatho8aip). + +### Internal server errors + +Consult the service logs for more information on the error. For the local cluster, this can be done using the [prisma logs](!alias-aenael2eek) command. diff --git a/docs/1.1/04-Reference/02-Prisma-API/03-Queries.md b/docs/1.1/04-Reference/02-Prisma-API/03-Queries.md new file mode 100644 index 0000000000..c44eddc63b --- /dev/null +++ b/docs/1.1/04-Reference/02-Prisma-API/03-Queries.md @@ -0,0 +1,447 @@ +--- +alias: ahwee4zaey +description: Queries +--- + +# Queries + +The Prisma API offers two kinds of queries: + +* **Object queries**: Fetch single or multiple nodes of a certain [object type](!alias-eiroozae8u#object-types) +* **Connection queries**: Expose advanced features like aggregations and [Relay compliant connections](https://facebook.github.io/relay/graphql/connections.htm) enabling a powerful pagination model + +When working with the Prisma API, the following features are also useful to keep in mind: + +* **Hierarchical queries**: Fetch data across relations +* **Query arguments**: Allow for filtering, sorting, pagination and more + +In general, the Prisma API of a service is generated based on its [data model](!alias-eiroozae8u). To explore the operations in your Prisma API, you can use a [GraphQL Playground](https://github.com/graphcool/graphql-playground). + +In the following, we will explore example queries based on a Prisma service with this data model: + +```graphql +type Post { + id: ID! @unique + title: String! + published: Boolean! + author: User! +} + +type User { + id: ID! @unique + age: Int + email: String! @unique + name: String! + accessRole: AccessRole + posts: [Post!]! +} + +enum AccessRole { + USER + ADMIN +} +``` + +## Obect queries + +We can use **object queries** to fetch either a single node, or a list of nodes for a certain object type. + +Here, we use the `posts` query to fetch a list of `Post` nodes. In the response, we include only the `id` and `title` of each `Post` node: + +```graphql +query { + posts { + id + title + } +} +``` + +We can also query a specific `Post` node using the `post` query. Note that we're using the `where` argument to select the node: + +```graphql +query { + post(where: { + id: "cixnen24p33lo0143bexvr52n" + }) { + id + title + published + } +} +``` + +Because `User` is another type in our data model, `users` is another available query. Again, we can use the `where` argument to specify conditions for the returned users. In this example, we filter for all `User` nodes that have their `age` higher than `18`: + +```graphql +query { + users(where: { + age_gt: 18 + }) { + id + name + } +} +``` + +This also works across relations, here we're fetching those `Post` nodes that have an `author` with the `age` higher than `18`: + +```graphql +query { + posts(where: { + author: { + age_gt: 18 + } + }) { + id + title + author { + name + age + } + } +} +``` + +You can read more about [node selection here](!alias-utee3eiquo#node-selection). + +## Connection queries + +Object queries directly return a list of nodes. In special cases, or when using advanced features, using **connection queries** is the preferred option. They are an extension of (and fully compliant with) [Relay connections](https://facebook.github.io/relay/graphql/connections.htm). The core idea of Relay connections is to provide meta-information about the _edges_ in the data graph. For example, each edge not only has access to information about the corresponding object (the `node`) but also is associated with a `cursor` that allows to implement powerful pagination. + +Here, we fetch all `Post` nodes using the `postsConnection` query. Notice that we're also asking for the `cursor` of each edge: + +```graphql +# Fetch all posts +query { + postsConnection { + edges { + cursor + node { + id + title + } + } + } +} +``` + +Connection queries also expose **aggregation** features via `aggregate`: + +```graphql +# Count all posts with a title containing 'GraphQL' +query { + postsConnection(where: { + title_contains: "GraphQL" + }) { + aggregate { + count + } + } +} +``` + +> Note that more aggregations will be added over time. Find more information about the roadmap [here](https://github.com/graphcool/graphcool/issues/1312). + +## Querying data across relations + +Every available [relation](!alias-eiroozae8u#relations) in your data model adds a new field to the queries of the two models it connects. + +Here, we are fetching a specific `User`, and all her related `Post` nodes using the `posts` field: + +```graphql +query { + user(where: { + id: "cixnekqnu2ify0134ekw4pox8" + }) { + id + name + posts { + id + published + } + } +} +``` + +`user.posts` acts exactly like the top-level `posts` query in that it lets you specify which fields of the `Post` type you're interested in. + +## Query arguments + +Throughout the Prisma API, you'll find query arguments that you cam provide to further control the query response. It can be either of the following: + +- sorting nodes by any field value using `orderBy` +- selecting nodes in a query by scalar or relational filters using `where` +- paginating nodes in a query using `first` and `before`, `last` and `after`, and `skip` + +These query arguments can be combined to achieve very specific query responses. + +### Ordering by field + +When querying all nodes of a type you can supply the `orderBy` argument for every scalar field of the type: `orderBy: _ASC` or `orderBy: _DESC`. + +Order the list of all `Post` nodes ascending by `title`: + +```graphql +query { + posts(orderBy: title_ASC) { + id + title + published + } +} +``` + +Order the list of all `Post` nodes descending by `published`: + +```graphql +query { + posts(orderBy: published_DESC) { + id + title + published + } +} +``` + +> **Note**: The field you are ordering by does not have to be selected in the actual query. If you do not specify an ordering, the response is automatically ordered ascending by the `id` field. + +#### Limitations + +It's currently not possible to order responses [by multiple fields](https://github.com/graphcool/feature-requests/issues/62) or [by related fields](https://github.com/graphcool/feature-requests/issues/95). Join the discussion in the feature requests if you're interested in these features! + +### Filtering by field + +When querying all nodes of a type you can supply different parameters to the `where` argument to constrain the data in the response according to your requirements. The available options depend on the scalar and relational fields defined on the type in question. + +#### Applying single filters + +If you supply exactly one parameter to the `where` argument, the query response will only contain nodes that adhere to this constraint. Multiple filters can be combined using `AND` and/or `OR`, see [below](#arbitrary-combination-of-filters-with-and-and-or) for more. + +##### Filtering by value + +The easiest way to filter a query response is by supplying a field value to filter by. + +Query all `Post` nodes that are not yet `published`: + +```graphql +query { + posts(where: { + published: false + }) { + id + title + published + } +} +``` + +##### Advanced filter criteria + +Depending on the type of the field you want to filter by, you have access to different advanced criteria you can use to filter your query response. See how to [explore available filter criteria](#explore-available-filter-criteria). + +Query all `Post` nodes whose `title` is in a given list of strings: + +```graphql +query { + posts(where: { + title_in: ["My biggest Adventure", "My latest Hobbies"] + }) { + id + title + published + } +} +``` + +> **Note**: you have to supply a _list_ as the `_in` argument: `title_in: ["My biggest Adventure", "My latest Hobbies"]`. + +#### Relation filters + +For _to-one_ relations, you can define conditions on the related node by nesting the according argument in `where`. + +Query all `Post` nodes where the `author` has the `USER` access role: + +```graphql +query { + posts(where: { + author: { + accessRole: USER + } + }) { + title + } +} +``` + +For _to-many_ relations, three additional arguments are available: `every`, `some` and `none`, to define that a condition should match `every`, `some` or `none` related nodes. + +Query all `User` nodes that have _at least_ one `Post` node that's `published`: + +```graphql +query { + users(where: { + posts_some: { + published: true + } + }) { + id + posts { + published + } + } +} +``` + +Relation filters are also available in the nested arguments for _to-one_ or _to-many_ relations. + +Query all `User` nodes that did not _like_ a `Post` of an `author` in the `ADMIN` access role: + +```graphql +query { + users(where: { + likedPosts_none: { + author: { + accessRole: ADMIN + } + } + }) { + name + } +} +``` + +> **Note**: `likedPosts` is not part of the above mentioned data model but can easily be added by adding the corresponding field to the `User` type: `likedPosts: [Post!]! @relation(name: "LikedPosts")`. Note that we also provide a `name` for the relation to resolve the ambiguity we would otherwise create because there are two relation fields targetting `Post` on the `User` type. + +#### Combining multiple filters + +You can use the filter combinators `OR` and `AND` to create an arbitrary logical combination of filter conditions. + +##### Using `OR` or `AND` + +Let's start with an easy example: + +Query all `Post` nodes that are `published` _and_ whose `title` is in a given list of strings: + +```graphql +query { + posts(where: { + AND: [{ + title_in: ["My biggest Adventure", "My latest Hobbies"] + }, { + published: true + }] + }) { + id + title + published + } +} +``` + +> **Note**: `OR` and `AND` accept a _list_ as input where each list item is an object and therefore needs to be wrapped with `{}`, for example: `AND: [{title_in: ["My biggest Adventure", "My latest Hobbies"]}, {published: true}]` + +##### Arbitrary combination of filters with `AND` and `OR` + +You can combine and even nest the filter combinators `AND` and `OR` to create arbitrary logical combinations of filter conditions. + +Query all `Post` nodes that are either `published` _and_ whose `title` is in a list of given strings, _or_ have the specific `id` we supply: + +```graphql +query($published: Boolean) { + posts(where: { + OR: [{ + AND: [{ + title_in: ["My biggest Adventure", "My latest Hobbies"] + }, { + published: $published + }] + }, { + id: "cixnen24p33lo0143bexvr52n" + }] + }) { + id + title + published + } +} +``` + +> Notice how we nested the `AND` combinator inside the `OR` combinator, on the same level with the `id` value filter. + +#### Explore available filter criteria + +Apart from the filter combinators `AND` and `OR`, the available filter arguments for a query for all nodes of a type depend on the fields of the type and their types. + +Use the [GraphQL Playground](https://github.com/graphcool/graphql-playground) to explore available filter conditions. + +#### Limitations + +Currently, neither [**scalar list filters**](https://github.com/graphcool/feature-requests/issues/60) nor [**JSON filters**](https://github.com/graphcool/feature-requests/issues/148) are available. Join the discussion in the respective feature requests on GitHub. + +### Pagination + +When querying all nodes of a specific [object type](!alias-eiroozae8u#object-types), you can supply arguments that allow you to _paginate_ the query response. + +Pagination allows you to request a certain amount of nodes at the same time. You can seek forwards or backwards through the nodes and supply an optional starting node: + +- to seek forwards, use `first`; specify a starting node with `after`. +- to seek backwards, use `last`; specify a starting node with `before`. + +You can also skip an arbitrary amount of nodes in whichever direction you are seeking by supplying the `skip` argument. + +Consider a blog where only 3 `Post` nodes are shown at the front page. To query the first page: + +```graphql +query { + posts(first: 3) { + id + title + } +} +``` + +To query the first two `Post` node after the first `Post` node: + +```graphql +query { + posts( + first: 2 + after: "cixnen24p33lo0143bexvr52n" + ) { + id + title + } +} +``` + +We could reach the same result by combining `first` and `skip`: + +```graphql +query { + posts( + first: 2 + skip: 1 + ) { + id + title + } +} +``` + +Query the `last` 2 posts: + +```graphql +query { + posts(last: 2) { + id + title + } +} +``` + +> **Note**: You cannot combine `first` with `before` or `last` with `after`. You can also query for more nodes than exist without an error message. + +#### Limitations + +Note that *a maximum of 1000 nodes* can be returned per pagination field on the shared demo cluster. This limit can be increased on other clusters using [the cluster configuration](https://github.com/graphcool/framework/issues/748). diff --git a/docs/1.1/04-Reference/02-Prisma-API/04-Mutations.md b/docs/1.1/04-Reference/02-Prisma-API/04-Mutations.md new file mode 100644 index 0000000000..a979a60297 --- /dev/null +++ b/docs/1.1/04-Reference/02-Prisma-API/04-Mutations.md @@ -0,0 +1,370 @@ +--- +alias: ol0yuoz6go +description: A GraphQL mutation is used to modify data at a GraphQL endpoint. +--- + +# Mutations + +The Prisma API offers + +* **Simple mutations**: Create, update, upsert and delete single nodes of a certain object type +* **Batch mutations**: Update and delete many nodes of a certain model +* **Relation mutations**: Connect, disconnect, create, update and upsert nodes across relations + +In general, the Prisma API of a service is generated based on its [data model](!alias-eiroozae8u). To explore the operations in your Prisma API, you can use a [GraphQL Playground](https://github.com/graphcool/graphql-playground). + +In the following, we will explore example queries based on a Prisma service with this data model: + +```graphql +type Post { + id: ID! @unique + title: String! + published: Boolean! + author: User! +} + +type User { + id: ID! @unique + age: Int + email: String! @unique + name: String! + posts: [Post!]! +} +``` + +## Object mutations + +We can use **model mutations** to modify single nodes of a certain model. + +### Creating nodes + +Here, we use the `createUser` mutation to create a new user: + +```graphql +# Create a new user +mutation { + createUser( + data: { + age: 42 + email: "zeus@example.com" + name: "Zeus" + } + ) { + id + name + } +} +``` + +> **Note**: All required fields without a [default value](!alias-eiroozae8u#default-value) need to be specified in the `data` input object. + +### Updating nodes + +We can use `updateUser` to change the `email` and `name`. Note that we're [selecting the node](!alias-utee3eiquo#node-selection) to update using the `where` argument: + +```graphql +mutation { + updateUser( + data: { + email: "zeus2@example.com" + name: "Zeus2" + } + where: { + email: "zeus@example.com" + } + ) { + id + name + } +} +``` + +### Upserting nodes + +When we want to either update an existing node, or create a new one in a single mutation, we can use _upsert_ mutations. + +Here, we use `upsertUser` to update the `User` with a certain `email`, or create a new `User` if a `User` with that `email` doesn't exist yet: + +```graphql +# Upsert a user +mutation { + upsertUser( + where: { + email: "zeus@example.com" + } + create: { + email: "zeus@example.com" + age: 42 + name: "Zeus" + } + update: { + name: "Another Zeus" + } + ) { + name + } +} +``` + +> **Note**: `create` and `update` are of the same type as the `data` object in the `createUser` and `updateUser` mutations. + +### Deleting nodes + +To delete nodes, all we have to do is to use the [select the node(s)](!alias-utee3eiquo#node-selection) to be deleted in a `delete` mutation. + +Here, we use `deleteUser` to delete a user by its `id`: + +```graphql +mutation { + deleteUser(where: { + id: "cjcdi63l20adx0146vg20j1ck" + }) { + id + name + email + } +} +``` + +Because `email` is also annotated with the [`@unique`](!alias-eiroozae8u#unique) directive, we can also selected (and thus delete) `User` nodes by their `email`: + +```graphql +mutation { + deleteUser(where: { + email: "cjcdi63l20adx0146vg20j1ck" + }) { + id + name + email + } +} +``` + +## Nested mutations + +We can use create and update model mutations to modify nodes across relations at the same time. This is referred to as **nested mutations** and is executed [transactionally](!alias-utee3eiquo#transactional-mutations). + +### Overview + +Several nested mutation arguments exist: + +* `create` +* `update` +* `upsert` +* `delete` +* `connect` +* `disconnect` + +Their availability and the exact behaviour depends on the following two parameters: + +* the type of the parent mutation + * create mutation + * update mutation + * upsert mutation +* the type of the relation + * optional _to-one_ relation + * required _to-one_ + * _to-many_ relation + +For example + +* a create mutation only exposes nested `create` and `connect` mutations +* an update mutation exposes `update`, `upsert` mutations for a required `to-one` relation + +### Examples + +Rather than mapping out all possible scenarios at this point, we provide a list of examples. + +It's recommended to explore the behaviour of different nested mutations by using the [GraphQL Playground](https://github.com/graphcool/graphql-playground). + +#### Creating and connecting related nodes + +We can use the `connect` action within a nested input object field to `connect` to one or more related nodes. + +Here, we are creating a new `Post` and `connect` to an existing `author` via the unique `email` field. In this case, `connect` provides a way for [node selection](!alias-utee3eiquo#node-selection): + +```graphql +# Create a post and connect it to an author +mutation { + createPost(data: { + title: "This is a draft" + published: false + author: { + connect: { + email: "zeus@example.com" + } + } + }) { + id + author { + name + } + } +} +``` + +If we provide a `create` argument instead of `connect` within `author`, we would _create_ a related `author` and at the same time `connect` to it, instead of connecting to an existing `author`. + +When creating a `User` instead of a `Post`, we can actually `create` and `connect` to multiple `Post` nodes at the same time, because `User` has a _to-many_ relation `Post`. + +Here, we are creating a new `User` and directly connect it to several new and existing `Post` nodes: + +```graphql +# Create a user, create and connect new posts, and connect to existing posts +mutation { + createUser( + data: { + email: "zeus@example.com" + name: "Zeus" + age: 42 + posts: { + create: [{ + published: true + title: "First blog post" + }, { + published: true + title: "Second blog post" + }] + connect: [{ + id: "cjcdi63j80adw0146z7r59bn5" + }, { + id: "cjcdi63l80ady014658ud1u02" + }] + } + } + ) { + id + posts { + id + } + } +} +``` + +#### Updating and upserting related nodes + +When updating nodes, you can update one or more related nodes at the same time. + +```graphql +mutation { + updateUser( + data: { + posts: { + update: [{ + where: { + id: "cjcf1cj0r017z014605713ym0" + } + data: { + title: "Hello World" + } + }] + } + } + where: { + id: "cjcf1cj0c017y01461c6enbfe" + } + ) { + id + } +} +``` + +Note that `update` accepts a list of objects with `where` and `data` fields suitable for the `updatePost` mutation. + +Nested upserting works similarly: + +```graphql +mutation { + updatePost( + where: { + id: "cjcf1cj0r017z014605713ym0" + } + data: { + author: { + upsert: { + where: { + id: "cjcf1cj0c017y01461c6enbfe" + } + update: { + email: "zeus2@example.com" + name: "Zeus2" + } + create: { + email: "zeus@example.com" + name: "Zeus" + } + } + } + } + ) { + id + } +} +``` + +#### Deleting related nodes + +When updating nodes, you can delete one or more related nodes at the same time. In this case, `delete` provides a way [node selection](!alias-utee3eiquo#node-selection): + +```graphql +mutation { + updateUser( + data: { + posts: { + delete: [{ + id: "cjcf1cj0u01800146jii8h8ch" + }, { + id: "cjcf1cj0u01810146m84cnt34" + }] + } + } + where: { + id: "cjcf1cj0c017y01461c6enbfe" + } + ) { + id + } +} +``` + +## Batch Mutations + +Batch mutations are useful to update or delete many nodes at once. The returned data only contains the `count` of affected nodes. + +For updating many nodes, you can [select the affected nodes](!alias-utee3eiquo#node-selection) using the `where` argument, while you specify the new values with `data`. All nodes will be updated to the same value. + +Here, we are publishing all unpublished `Post` nodes that were created in 2017: + +```graphql +mutation { + updateManyPosts( + where: { + createdAt_gte: "2017" + createdAt_lt: "2018" + published: false + } + data: { + published: true + } + ) { + count + } +} +``` + +Here, we are deleting all unpublished `Post` nodes of a certain `author`: + +```graphql +mutation { + deleteManyPosts( + where: { + published: false + author: { + name: "Zeus" + } + } + ) { + count + } +} +``` diff --git a/docs/1.1/04-Reference/02-Prisma-API/05-Subscriptions.md b/docs/1.1/04-Reference/02-Prisma-API/05-Subscriptions.md new file mode 100644 index 0000000000..64497147e7 --- /dev/null +++ b/docs/1.1/04-Reference/02-Prisma-API/05-Subscriptions.md @@ -0,0 +1,467 @@ +--- +alias: aey0vohche +description: Use subscriptions to receive data updates in realtime. +--- + +# Subscriptions + +## Overview + +_GraphQL subscriptions_ allow you to be notified in realtime when changes are happening to your data. There are three kinds of _events_ that trigger a subscription: + +- A new node is **created** +- An existing node is **updated** +- An existing node is **deleted** + +This is an example subscription that notifies you whenever a new `Post` node is created. When the subscription fires, the payload that's sent by the server will contain the `description` and `imageUrl` of the `Post`: + +```graphql +subscription newPosts { + post(where: { + mutation_in: [CREATED] + }) { + mutation + node { + description + imageUrl + } + } +} +``` + +Subscriptions use a special websocket endpoint. + +Here's a list of available subscriptions. To explore them, use the [GraphQL Playground](https://github.com/graphcool/graphql-playground) inside your service. + +- For every [object type](!alias-eiroozae8u#object-types) in your data model, a [type subscription](#type-subscriptions) is available to listen for data changes on that type. +- Currently, connecting or disconnecting nodes in a [relation](!alias-eiroozae8u#relations) does not trigger a subscription! You can find more info in this [GitHub issue](https://github.com/graphcool/framework/issues/146) and read below for a [workaround](#relation-subscriptions). + +You can [combine multiple subscription triggers](#combining-subscriptions) within a single subscription request to control exactly what events you want to be notified of. The subscriptions API also uses the rich fitler system that's available for [queries](!alias-ahwee4zaey). + +## Subscription requests + +When using [Apollo Client](https://www.apollographql.com/client/), you can use the [`apollo-link-ws`](https://github.com/apollographql/apollo-link-ws) library to facilite subscription use. [Here's an example](https://github.com/graphcool-examples/react-graphql/tree/master/subscriptions-with-apollo-worldchat). + +You can also use the [GraphQL Playground](https://github.com/graphcool/graphql-playground) or any WebSocket client as described below. + +### Playground + +A [GraphQL Playground](https://github.com/graphcool/graphql-playground) can be used to explore and run GraphQL subscriptions. + +### Plain WebSockets + +#### 1. Establish connection + +Subscriptions are managed through WebSockets. First establish a WebSocket connection and specify the [`graphql-subscriptions`](https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md) protocol: + +```js +let webSocket = new WebSocket('wss://__CLUSTER__.prisma.sh/__WORKSPACE__/__SERVICE__/__STAGE__', 'graphql-subscriptions'); +``` + +#### 2. Initiate handshake + +Next you need to initiate a handshake with the WebSocket server. You do this by listening to the `open` event and then sending a JSON message to the server with the `type` property set to `init`: + +```js +webSocket.onopen = (event) => { + const message = { + type: 'init' + } + + webSocket.send(JSON.stringify(message)) +} +``` + +#### 3. Receive messages + +The server may respond with a variety of messages distinguished by their `type` property. You can react to each message as appropriate for your application: + +```js +webSocket.onmessage = (event) => { + const data = JSON.parse(event.data) + + switch (data.type) { + case 'init_success': { + console.log('init_success, the handshake is complete') + break + } + case 'init_fail': { + throw { + message: 'init_fail returned from WebSocket server', + data + } + } + case 'subscription_data': { + console.log('subscription data has been received', data) + break + } + case 'subscription_success': { + console.log('subscription_success') + break + } + case 'subscription_fail': { + throw { + message: 'subscription_fail returned from WebSocket server', + data + } + } + } +} +``` + +#### 4. Subscribe to data changes + +To subscribe to data changes, send a message with the `type` property set to `subscription_start`: + +```js +const message = { + id: '1', + type: 'subscription_start', + query: ` + subscription newPosts { + post(filter: { + mutation_in: [CREATED] + }) { + mutation + node { + description + imageUrl + } + } + } + ` +} + +webSocket.send(JSON.stringify(message)) +``` + +You should receive a message with `type` set to `subscription_success`. When data changes occur, you will receive messages with `type` set to `subscription_data`. The `id` property that you supply in the `subscription_start` message will appear on all `subscription_data` messages, allowing you to multiplex your WebSocket connection. + +#### 5. Unsubscribe from data changes + +To unsubscribe from data changes, send a message with the `type` property set to `subscription_end`: + +```js +const message = { + id: '1', + type: 'subscription_end' +} + +webSocket.send(JSON.stringify(message)) +``` + +## Type subscriptions + +For every available [object type](!alias-eiroozae8u#object-types) in your data model, certain subscriptions are automatically generated. + +As an example, consider the following data model with a single `Post` type: + +```graphql +type Post { + id: ID! @unique + title: String! + description: String +} +``` + +In the gerated [Prisma API](!alias-ohm2ouceuj), a `post` subscription will be available that you can use to be notified whenever certain nodes of type `Post` are [created](#subscribing-to-created-nodes), [updated](#subscribing-to-updated-nodes) or [deleted](#subscribing-to-deleted-nodes). + +### Subscribing to created nodes + +For a given type, you can subscribe to all nodes that are being created using the generated type subscription. + +#### Subscribe to all created nodes + +If you want to subscribe to created nodes of the `Post` type, you can use the `Post` subscription and specify the `where` object and set `mutation_in: [CREATED]`. + +```graphql +subscription { + post(where: { + mutation_in: [CREATED] + }) { + mutation + node { + description + imageUrl + author { + id + } + } + } +} +``` + +The payload contains: + +- `mutation`: In this case it will return `CREATED`. +- `node`: Allows you to query information on the created node (and potentially its related nodes). + +#### Subscribe to specific created nodes + +You can make use of a similar [filter system as for queries](!alias-nia9nushae#filtering-by-field) using the `node` argument of the `where` object. + +For example, to only be notified of a created `Post` if a specific user _follows_ the `author`: + +```graphql +subscription { + post(where: { + mutation_in: [CREATED] + node: { + author: { + followedBy_some: { + id: "cj03x3nacox6m0119755kmcm3" + } + } + } + }) { + mutation + node { + description + imageUrl + author { + id + } + } + } +} +``` + +### Subscribing to deleted nodes + +For a given type, you can subscribe to all nodes that are being deleted using the generated type subscription. + +#### Subscribe to all deleted nodes + +If you want to subscribe for updated nodes of the `Post` type, you can use the `Post` subscription and specify the `where` object and set `mutation_in: [DELETED]`. + +```graphql +subscription deletePost { + post(where: { + mutation_in: [DELETED] + }) { + mutation + previousValues { + id + } + } +} +``` + +The payload contains + +- `mutation`: In this case it will return `DELETED`. +- `previousValues`: Previous scalar values of the node. + +> **Note**: `previousValues` is always `null` for `CREATED` subscriptions. + +#### Subscribe to specific deleted nodes + +You can make use of a similar [filter system as for queries](!alias-nia9nushae#filtering-by-field) using the `node` argument of the `where` object. + +For example, to only be notified of a deleted `Post` if a specific user follows the `author`: + +```graphql +subscription { + post(where: { + mutation_in: [DELETED] + node: { + author: { + followedBy_some: { + id: "cj03x3nacox6m0119755kmcm3" + } + } + } + }) { + mutation + previousValues { + id + } + } +} +``` + +### Subscribing to updated nodes + +For a given type, you can subscribe to all nodes being updated using the generated type subscription. + +#### Subscribe to all updated nodes + +If you want to subscribe to updated nodes of the `Post` type, you can use the `Post` subscription and specify the `where` object and set `mutation_in: [UPDATED]`. + +```graphql +subscription { + post(where: { + mutation_in: [UPDATED] + }) { + mutation + node { + description + imageUrl + author { + id + } + } + updatedFields + previousValues { + description + imageUrl + } + } +} +``` + +The payload contains + +- `mutation`: In this case it will return `UPDATED`. +- `node`: Allows you to query information on the updated node and connected nodes. +- `updatedFields`: A list of the fields that changed. +- `previousValues`: Previous scalar values of the node. + +> **Note**: `updatedFields` is always `null` for `CREATED` and `DELETED` subscriptions. `previousValues` is always `null` for `CREATED` subscriptions. + +#### Subscribe to updated fields + +You can make use of a similar [filter system as for queries](!alias-nia9nushae#filtering-by-field) using the `node` argument of the `where` object. + +For example, to only be notified of an updated `Post` if its `description` changed: + +```graphql +subscription { + post(where: { + mutation_in: [UPDATED] + updatedFields_contains: "description" + }) { + mutation + node { + description + } + updatedFields + previousValues { + description + } + } +} +``` + +Similarily to `updatedFields_contains`, more filter conditions exist: + +- `updatedFields_contains_every: [String!]`: Matches if all fields specified have been updated. +- `updatedFields_contains_some: [String!]`: Matches if some of the specified fields have been updated. + +> **Note**: You cannot use the `updatedFields` filter conditions together with `mutation_in: [CREATED]` or `mutation_in: [DELETED]`! + +## Relation subscriptions + +Currently, subscriptions for relation updates are only available with a workaround using `UPDATED` subscriptions. + +### Subscribing to relation changes + +You can force a notification changes by _touching_ nodes. Add a `dummy: String` field to the type in question and update this field for the node whose relation status just changed. + +```graphql +mutation updatePost { + updatePost( + where: { + id: "some-id" + } + data: { + dummy: "dummy" # do a dummy change to trigger update subscription + } + ) +} +``` + +> If you're interested in a direct relation trigger for subscriptions, [please join the discussion on GitHub](https://github.com/graphcool/feature-requests/issues/146). + +## Combining subscriptions + +You can subscribe to multiple mutations on the same type in one subscription. + +### Subscribe to all changes to all nodes + +Using the `mutation_in` argument of the `where` object, you can select the type of mutation that you want to subscribe to. For example, to subscribe to the `createPost`, `updatePost` and `deletePost` mutations: + +```graphql +subscription { + post(where: { + mutation_in: [CREATED, UPDATED, DELETED] + }) { + mutation + node { + id + description + } + updatedFields + previousValues { + description + imageUrl + } + } +} +``` + +### Subscribe to all changes to specific nodes + +To select specific nodes that you want to be notified about, use the `node` argument of the `where` object. You can combine it with `mutation_in`. For example, to only be notified of created, updated and deleted posts if a specific user follows the author: + +```graphql +subscription { + post( + where: { + mutation_in: [CREATED, UPDATED, DELETED] + } + node: { + author: { + followedBy_some: { + id: "cj03x3nacox6m0119755kmcm3" + } + } + } + ) { + mutation + node { + id + description + } + updatedFields + previousValues { + description + imageUrl + } + } +} +``` + +> **Note**: `previousValues` is always `null` for `CREATED` subscriptions and `updatedFields` is always `null` for `CREATED` and `DELETED` subscriptions. + +### Advanced subscription filters + +You can make use of a similar [filter system as for queries](!alias-nia9nushae#filtering-by-field) using the `where` argument. + +For example, you can subscribe to all `CREATED` and `DELETE` subscriptions, as well as all `UPDATED` subscriptions when the `imageUrl` was updated: + +```graphql +subscription { + post(where: { + OR: [{ + mutation_in: [CREATED, DELETED] + }, { + mutation_in: [UPDATED] + updatedFields_contains: "imageUrl" + }] + }) { + mutation + node { + id + description + } + updatedFields + previousValues { + description + imageUrl + } + } +} +``` + +> **Note**: Using any of the `updatedFields` filter conditions together with `CREATED` or `DELETED` subscriptions results in an error. `previousValues` is always `null` for `CREATED` subscriptions and `updatedFields` is always `null` for `CREATED` and `DELETED` subscriptions. diff --git a/docs/1.1/04-Reference/02-Prisma-API/index.md b/docs/1.1/04-Reference/02-Prisma-API/index.md new file mode 100644 index 0000000000..ebbb0017ca --- /dev/null +++ b/docs/1.1/04-Reference/02-Prisma-API/index.md @@ -0,0 +1,3 @@ +--- +description: Learn about concepts and available operations in the Prisma API. +--- diff --git a/docs/1.1/04-Reference/03-Server_side-Subscriptions/01-Overview.md b/docs/1.1/04-Reference/03-Server_side-Subscriptions/01-Overview.md new file mode 100644 index 0000000000..98e67ba93a --- /dev/null +++ b/docs/1.1/04-Reference/03-Server_side-Subscriptions/01-Overview.md @@ -0,0 +1,65 @@ +--- +alias: to1ahf0ob6 +description: Overview +--- + +# Overview + +## Introduction + +A server-side subscription is equivalent in power to normal GraphQL subscriptions. That means they have the same API, e.g. allowing to provide the same filters in order to only get notified for the events you are interested in. + +When a server-side subscription is set up, Prisma will monitor data changes and execute the associated query when applicable, just like normal GraphQL Subscriptions. The difference is the delivery mechanism. + +Server-side subscriptions are designed to work well with modern serverless infrastructure. Currently, Prisma support delivering events via webhooks and in the future we will add support for direct AWS Lambda invocation as well as different queue implementations. + +## Configuration + +You configure a server-side subscription by adding the [`subscriptions`](!alias-ufeshusai8#subscriptions-optional) property in the [`prisma.yml`](!alias-foatho8aip) file for your service. + +### prisma.yml + +```yml +service: my-service + +stage: ${env:GRAPHCOOL_STAGE} +secret: ${env:GRAPHCOOL_SECRET} +cluster: ${env:GRAPHCOOL_CLUSTER} + +datamodel: database/datamodel.graphql + +subscriptions: + userChangedEmail: + webhook: + url: http://example.org/sendSlackMessage + headers: + Content-Type: application/json + Authorization: Bearer cha2eiheiphesash3shoofo7eceexaequeebuyaequ1reishiujuu6weisao7ohc + query: | + { + user({ + where: { + mutation_in: [UPDATED], + updatedFields_contains: "email" + } + }) { + name + email + } + } +``` + +### Example + +The `userChangedEmail` subscription configured above would be triggered by a mutation like this: + +```graphql +mutation { + updateUser( + data: { email: "new@email.com" }, + where: { id: "cjcgo976g5twb018740bzyy4q" } + ) { + id + } +} +``` diff --git a/docs/1.1/04-Reference/03-Server_side-Subscriptions/index.md b/docs/1.1/04-Reference/03-Server_side-Subscriptions/index.md new file mode 100644 index 0000000000..731e010302 --- /dev/null +++ b/docs/1.1/04-Reference/03-Server_side-Subscriptions/index.md @@ -0,0 +1,3 @@ +--- +description: Serverside Subscriptions can be used to invoke external business logic for specific events in a Prisma Service. +--- diff --git a/docs/1.1/04-Reference/04-Clusters/01-Overview.md b/docs/1.1/04-Reference/04-Clusters/01-Overview.md new file mode 100644 index 0000000000..61fd7ea669 --- /dev/null +++ b/docs/1.1/04-Reference/04-Clusters/01-Overview.md @@ -0,0 +1,39 @@ +--- +alias: eu2ood0she +description: Overview +--- + +# Overview + +Prisma services are deployed to so-called _clusters_. A cluster is a hosted environment for Prisma services. + +In essence, there are two kinds of _clusters_ you can deploy to: + +- **Self-hosted / local clusters**: Self-hosted clusters are running on Docker. They are created and managed using the Prisma CLI. For the vast majority of use cases, _self-hosted clusters are the preferred option to deploy Prisma services_. This chapter explains how to create and manage your own self-hosted clusters. +- **Public clusters** (based on Prisma Cloud): Allow to conventiently deploy your Prisma service to the web. Note that deploying to public clusters _does not require an account in the Prisma cloud_. Public clusters have certain limitations, such as rate limiting of incoming requests and an upperbound in storage capacity. Services deployed to public clusters are deleted after a certain period of inactivity. + +## Cluster registry + +When first used, the Prisma CLI creates a new directory (called `.prisma`) in your home directory. This directory contains the _cluster registry_: `~/.prisma/config.yml`. + +The cluster registry lists information about the clusters you can deploy your services to. It is used by the Prisma CLI to provision deployment options to you. + +Here is an example of what the cluster registry might look like: + +```yml +clusters: + local: + host: 'http://localhost:4466' + clusterSecret: "-----BEGIN RSA PRIVATE KEY----- [ long key omitted ] -----END RSA PRIVATE KEY-----\r\n" + digital-ocean: + host: 'http://45.55.177.154:4466' + clusterSecret: "-----BEGIN RSA PRIVATE KEY----- [ long key omitted ] -----END RSA PRIVATE KEY-----\r\n" +``` + +If you want to add a custom cluster, you can either use the `prisma cluster add` command or manually add a cluster entry to the file, providing the required information. + +You can list your clusters and more information using `prisma cluster list`. + +## Cluster deployment + +Check the tutorials for setting up the Docker container for the [Local Cluster](alias-meemaesh3k) or on [Digital Ocean](!alias-texoo9aemu). diff --git a/docs/1.1/04-Reference/04-Clusters/02-Local-Cluster.md b/docs/1.1/04-Reference/04-Clusters/02-Local-Cluster.md new file mode 100644 index 0000000000..eb42aaeb88 --- /dev/null +++ b/docs/1.1/04-Reference/04-Clusters/02-Local-Cluster.md @@ -0,0 +1,57 @@ +--- +alias: si4aef8hee +description: Overview +--- + +# Local Cluster + +This chapter describes advanced topics for the local Prisma cluster. To learn more about local cluster deployment, read [this tutorial](!alias-meemaesh3k). + +## Debugging + +You can view logs from your local Prisma cluster to debug issues. + +### Logs + +You can view normal debug logs: + +```sh +prisma local logs +``` + +### Docker logs + +If you need more extensive logs you can view the raw logs from the containers running MySQL and Prisma: + +```sh +docker logs prisma + +docker logs prisma-db +``` + +### Verify Docker containers + +If you get an error message saying `Error response from daemon: No such container` you can verify that the containers are running: + +```sh +docker ps +``` + +You should see output similar to this: + +``` +❯ docker ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +7210106b6650 prismagraphql/prisma:1.0.0 "/app/bin/single-ser…" About an hour ago Up About an hour 0.0.0.0:4466->4466/tcp prisma +1c15922e15ba mysql:5.7 "docker-entrypoint.s…" About an hour ago Up About an hour 0.0.0.0:3306->3306/tcp prisma-db +``` + +### Nuke + +If your local prisma cluster is in an unrecoverable state, the easiest option might be to completely reset it. Be careful as **this command will reset all data** in your local cluster. + +```sh +❯ prisma local nuke +Nuking local cluster 10.9s +Booting fresh local development cluster 18.4s +``` diff --git a/docs/1.1/04-Reference/04-Clusters/index.md b/docs/1.1/04-Reference/04-Clusters/index.md new file mode 100644 index 0000000000..92179dbb9c --- /dev/null +++ b/docs/1.1/04-Reference/04-Clusters/index.md @@ -0,0 +1,3 @@ +--- +description: Learn about local and remote Prisma clusters. +--- diff --git a/docs/1.1/04-Reference/05-Data-Import-&-Export/01-Data-Import.md b/docs/1.1/04-Reference/05-Data-Import-&-Export/01-Data-Import.md new file mode 100644 index 0000000000..f8c5cd853e --- /dev/null +++ b/docs/1.1/04-Reference/05-Data-Import-&-Export/01-Data-Import.md @@ -0,0 +1,109 @@ +--- +alias: ol2eoh8xie +description: Data Import +--- + +# Data Import + +Data to be imported needs to adhere to the Normalized Data Format (NDF). As of today, the conversion from any concrete data source (like MySQL, MongoDB or Firebase) to NDF must be performed manually. In the [future](https://github.com/graphcool/framework/issues/1410), the Prisma CLI will support importing from these data sources directly. + +Here is a general overview of the data import process: + +``` ++--------------+ +----------------+ +------------+ +| +--------------+ | | | | +| | | | | | | | +| | SQL | | (1) transform | NDF | (2) chunked upload | Prisma | +| | MongoDB | | +--------------> | | +-------------------> | | +| | JSON | | | | | | +| | | | | | | | ++--------------+ | +----------------+ +------------+ + +--------------+ +``` + +As mentioned above, step 1 has to be performed manually. Step 2 can then be done by either using the raw import API or the `prisma import` command from the CLI. + +> To view the current state of supported transformations in the CLI and submit a vote for the one you need, you can check out [this](https://github.com/graphcool/framework/issues/1410) GitHub issue. + +When uploading files in NDF, you need to provide the import data split across three different _kinds_ of files: + +- `nodes`: Data for individual nodes (i.e. databases records) +- `lists`: Data for a list of nodes +- `relations`: Data for related nodes + +You can upload an unlimited number of files for each of these types, but each file should be at most 10 MB large. + +## Data import with the CLI + +The Prisma CLI offers the `prisma import` command. It accepts one option: + +- `--data` (short: `-d`): A file path to a .zip-directory containing the data to be imported + +Under the hood, the CLI uses the import API that's described in the next section. However, using the CLI provides some major benefits: + +- uploading **multiple files** at once (rather than having to upload each file individually) +- **leveraging the CLI's authentication mechanism** (i.e. you don't need to manually send your authentication token) +- ability to **pause and resume** an ongoing import +- **import from various data sources** like MySQL, MongoDB or Firebase (_not available yet_) + +### Input format + +When importing data using the CLI, the files containing the data in NDF need to be located in directories called after their type: `nodes`, `lists` and `relations`. + +NDF files are JSON files following a specific structure, so each file containing import data needs to end on `.json`. When placed in their respective directories (`nodes`, `lists` or `relations`), the `.json`-files need to be numbered incrementally, starting with 1, e.g. `1.json`. The file name can be prepended with any number of zeros, e.g. `01.json` or `0000001.json`. + +### Example + +Consider the following file structure defining a Prisma service: + +``` +. +├── data +│   ├── lists +│   │   ├── 0001.json +│   │   ├── 0002.json +│   │   └── 0003.json +│   ├── nodes +│   │   ├── 0001.json +│   │   └── 0002.json +│   └── relations +│   └── 0001.json +├── data.zip +├── datamodel.graphql +└── prisma.yml +``` + +`data.zip` is the _compressed_ version of the `data` directory. Further, all files ending on `.json` are adhering to NDF. To import the data from these files, you can simply run the following command in the terminal: + +```sh +prisma import --source data.zip +``` + +## Data import using the raw import API + +The raw import API is exposed under the `/import` path of your service's HTTP endpoint. For example: + +- `http://localhost:60000/my-app/dev/import` +- `https://database.prisma.sh/my-app/prod/import` + +One request can upload JSON data (in NDF) of at most 10 MB in size. Note that you need to provide your authentication token in the HTTP `Authorization` header of the request! + +Here is an example `curl` command for uploading some JSON data (of NDF type `nodes`): + +```sh +curl 'http://localhost:60000/my-app/dev/import' \ +-H 'Content-Type: application/json' \ +-H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE1MTM1OTQzMTEsImV4cCI6MTU0NTEzMDMxMSwiYXVkIjasd3d3LmV4YW1wbGUuY29tIiwic3ViIjoianJvY2tldEBleGFtcGxlLmNvbSIsIkdpdmVuTmFtZSI6IkpvaG5ueSIsIlN1cm5hbWUiOiJSb2NrZXQiLCJFbWFpbCI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJSb2xlIjpbIk1hbmFnZXIiLCJQcm9qZWN0IEFkbWluaXN0cmF0b3IiXX0.L7DwH7vIfTSmuwfxBI82D64DlgoLBLXOwR5iMjZ_7nI' \ +-d '{"valueType":"nodes","values":[{"_typeName":"Model0","id":"0","a":"test","b":0,"createdAt":"2017-11-29 14:35:13"},{"_typeName":"Model1","id":"1","a":"test","b":1},{"_typeName":"Model2","id":"2","a":"test","b":2,"createdAt":"2017-11-29 14:35:13"},{"_typeName":"Model0","id":"3","a":"test","b":3},{"_typeName":"Model3","id":"4","a":"test","b":4,"createdAt":"2017-11-29 14:35:13","updatedAt":"2017-11-29 14:35:13"},{"_typeName":"Model3","id":"5","a":"test","b":5},{"_typeName":"Model3","id":"6","a":"test","b":6},{"_typeName":"Model4","id":"7"},{"_typeName":"Model4","id":"8","string":"test","int":4,"boolean":true,"dateTime":"1015-11-29 14:35:13","float":13.333,"createdAt":"2017-11-29 14:35:13","updatedAt":"2017-11-29 14:35:13"},{"_typeName":"Model5","id":"9","string":"test","int":4,"boolean":true,"dateTime":"1015-11-29 14:35:13","float":13.333,"createdAt":"2017-11-29 14:35:13","updatedAt":"2017-11-29 14:35:13"}]}' \ +-sSv +``` + +The generic version for `curl` (using placeholders) would look as follows: + +```sh +curl '__SERVICE_ENDPOINT__/import' \ +-H 'Content-Type: application/json' \ +-H 'Authorization: Bearer __JWT_AUTH_TOKEN__' \ +-d '{"valueType":"__NDF_TYPE__","values": __DATA__ }' \ +-sSv +``` diff --git a/docs/1.1/04-Reference/05-Data-Import-&-Export/02-Data-Export.md b/docs/1.1/04-Reference/05-Data-Import-&-Export/02-Data-Export.md new file mode 100644 index 0000000000..7d1018f381 --- /dev/null +++ b/docs/1.1/04-Reference/05-Data-Import-&-Export/02-Data-Export.md @@ -0,0 +1,74 @@ +--- +alias: pa0aip3loh +description: Data Export +--- + +# Data Export + +Exporting data can be done either using the CLI or the raw export API. In both cases, the downloaded data is formatted in JSON and adheres to the Normalized Data Format (NDF). As the exported data is in NDF, it can directly be imported into a service with an identical schema. This can be useful when test data is needed for a service, e.g. in a `dev` stage. + +## Data export with the CLI + +The PRrisma CLI offers the `prisma export` command. It accepts one option: + +- `--export-path` (short: `-e`): A file path to a .zip-directory which will be created by the CLI and where the exported data is stored + +Under the hood, the CLI uses the expport API that's described in the next section. However, using the CLI provides some major benefits: + +- **leveraging the CLI's authentication mechanism** (i.e. you don't need to manually send your authentication token) +- **writing downloaded data directly to file system** +- **cursor management** in case multiple requests are needed to export all application data (when doing this manually you need to send multiple requests and adjust the cursor upon each) + +### Output format + +The data is exported in NDF and will be placed in three directories that are named after the different NDF types: `nodes`, `lists` and `relations`. + +## Data export using the raw export API + +The raw export API is exposed under the `/export` path of your service's HTTP endpoint. For example: + +- `http://localhost:60000/my-app/dev/export` +- `https://database.prisma.sh/my-app/prod/export` + +One request can download JSON data (in NDF) of at most 10 MB in size. Note that you need to provide your authentication token in the HTTP `Authorization` header of the request! + +The endpoint expects a POST request where the body contains JSON with the following contents: + +```json +{ + "fileType": "nodes", + "cursor": { + "table": 0, + "row": 0, + "field": 0, + "array": 0 + } +} +``` + +The values in `cursor` describe the offsets in the database from where on data should be exported. Note that each response for an export request will return a new cursor with either of two states: + +- Terminated (_not full_): If all the values for `table`, `row`, `field` and `array` are returned as `-1` it means the export has completed. +- Non-terminated (__full_): If any of the values for `table`, `row`, `field` or `array` is different from `-1`, it means the maximum size of 10 MB for this response has been reached. If this happens, you can use the returned `cursor` values as the input for your next export request. + +### Example + +Here is an example `curl` command for uploading some JSON data (of NDF type `nodes`): + +```sh +curl 'http://localhost:60000/my-app/dev/export' \ +-H 'Content-Type: application/json' \ +-H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE1MTM1OTQzMTEsImV4cCI6MTU0NTEzMDMxMSwiYXVkIjasd3d3LmV4YW1wbGUuY29tIiwic3ViIjoianJvY2tldEBleGFtcGxlLmNvbSIsIkdpdmVuTmFtZSI6IkpvaG5ueSIsIlN1cm5hbWUiOiJSb2NrZXQiLCJFbWFpbCI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJSb2xlIjpbIk1hbmFnZXIiLCJQcm9qZWN0IEFkbWluaXN0cmF0b3IiXX0.L7DwH7vIfTSmuwfxBI82D64DlgoLBLXOwR5iMjZ_7nI' \ +-d '{"fileType":"nodes","cursor":{"table":0,"row":0,"field":0,"array":0}}' \ +-sSv +``` + +The generic version for `curl` (using placeholders) would look as follows: + +```sh +curl '__SERVICE_ENDPOINT__/export' \ +-H 'Content-Type: application/json' \ +-H 'Authorization: Bearer __JWT_AUTH_TOKEN__' \ +-d '{"fileType":"__NDF_TYPE__","cursor": {"table":__TABLE__,"row":__ROW__,"field":__FIELD__,"array":__ARRAY__}} }' \ +-sSv +``` diff --git a/docs/1.1/04-Reference/05-Data-Import-&-Export/03-Normalized-Data-Format.md b/docs/1.1/04-Reference/05-Data-Import-&-Export/03-Normalized-Data-Format.md new file mode 100644 index 0000000000..1cbd722b37 --- /dev/null +++ b/docs/1.1/04-Reference/05-Data-Import-&-Export/03-Normalized-Data-Format.md @@ -0,0 +1,126 @@ +--- +alias: teroo5uxih +description: Normalized Data Format +--- + +# Normalized Data Format (NDF) + +The Normalized Data Format (NDF) is used as an _intermediate_ data format for import and export in Prisma services. NDF describes a specific structure for JSON. + +## NDF value types + +When using the NDF, data is split across three different "value types": + +- **Nodes**: Contains data for the _scalar fields_ of nodes +- **Lists**: Contains data for _list fields_ of nodes +- **Relations**: Contains data to connect two nodes via a relation by their _relation fields_ + +## Structure + +The structure for a JSON document in NDF is an object with the following two keys: + +- `valueType`: Indicates the value type of the data in the document (this can be either `"nodes"`, `"lists"` or `"relations"`) +- `values`: Contains the actual data (adhering to the value type) as an array + +The examples in the following are based on this data model: + +```graphql +type User { + id: String! @unique + firstName: String! + lastName: String! + hobbies: [String!]! + partner: User +} +``` + +### Nodes + +In case the `valueType` is `"nodes"`, the structure for the objects inside the `values` array is as follows: + +```js +{ + "valueType": "nodes", + "values": [ + { "_typeName": STRING, "id": STRING, "": ANY, "": ANY, ..., "": ANY }, + ... + ] +} +``` + +The notations expresses that the fields `_typeName` and `id` are of type string. `_typeName` refers to the name of the SDL type from your data model. The ``-placeholders will be the names of the scalar fields of that SDL type. + +For example, the following JSON document can be used to import the scalar values for two `User` nodes: + +```json +{ + "valueType": "nodes", + "values": [ + {"_typeName": "User", "id": "johndoe", "firstName": "John", "lastName": "Doe"}, + {"_typeName": "User", "id": "sarahdoe", "firstName": "Sarah", "lastName": "Doe"} + ] +} +``` + +### Lists + +In case the `valueType` is `"lists"`, the structure for the objects inside the `values` array is as follows: + +```js +{ + "valueType": "lists", + "values": [ + { "_typeName": STRING, "id": STRING, "": [ANY] }, + ... + ] +} +``` + +The notations expresses that the fields `_typeName` and `id` are of type string. `_typeName` refers to the name of the SDL type from your data model. The ``-placeholder is the name of the of the list fields of that SDL type. Note that in contrast to the scalar list fields, each object can only values only for one field. + +For example, the following JSON document can be used to import the values for the `hobbies` list field of two `User` nodes: + +```json +{ + "valueType": "lists", + "values": [ + {"_typeName": "User", "id": "johndoe", "hobbies": ["Fishing", "Cooking"]}, + {"_typeName": "User", "id": "sarahdoe", "hobbies": ["Biking", "Coding"]} + ] +} +``` + +### Relations + +In case the `valueType` is `"relations"`, the structure for the objects inside the `values` array is as follows: + +```js +{ + "valueType": "relations", + "values": [ + [ + { "_typeName": STRING, "id": STRING, "fieldName": STRING }, + { "_typeName": STRING, "id": STRING, "fieldName": STRING } + ], + ... + ] +} +``` + +The notations expresses that the fields `_typeName`, `id` and `fieldName` are of type string. + +`_typeName` refers to a name of an SDL type from your data model. The ``-placeholder is the name of the of the relation field of that SDL type. Since the goal of the relation data is to connect two nodes via a relation, each element inside the `values` array by itself is a pair (written as an array which always contains exactly two elements) rather than a single object as was the case for `"nodes"` and `"lists"`. + +For example, the following JSON document can be used to create a relation between two `User` nodes via the `partner` relation field: + +```json +{ + "valueType": "relations", + "values": [ + [ + { "_typeName": "User", "id": "johndoe", "fieldName": "partner" }, + { "_typeName": "User", "id": "sarahdoe", "fieldName": "partner" } + ] + ] +} +``` diff --git a/docs/1.1/04-Reference/05-Data-Import-&-Export/index.md b/docs/1.1/04-Reference/05-Data-Import-&-Export/index.md new file mode 100644 index 0000000000..f27271ca5a --- /dev/null +++ b/docs/1.1/04-Reference/05-Data-Import-&-Export/index.md @@ -0,0 +1,3 @@ +--- +description: Learn about importing and exporting data for Prisma services. +--- diff --git a/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/01-prisma-init.md b/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/01-prisma-init.md new file mode 100644 index 0000000000..469224bc19 --- /dev/null +++ b/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/01-prisma-init.md @@ -0,0 +1,34 @@ +--- +alias: eeb1ohr4ec +description: Creates the local file structure for a new Prisma database service +--- + +# `prisma init` + +Creates the local file structure for a new Prisma database service: + +- `prisma.yml` contains the [service definition](!alias-opheidaix3) +- `datamodel.graphql` contains the definition of your [data model](!alias-eiroozae8u) +- `.graphqlconfig` is a configuration file following the standardized [`graphql-config`](https://github.com/graphcool/graphql-config) format and is used by various tools, e.g. the [GraphQL Playground](https://github.com/graphcool/graphql-playground) + +If you provide a directory name as an argument to the command, all these files will be placed inside a new directory with that name. + +#### Usage + +```sh +prisma init DIRNAME +``` + +#### Examples + +##### Create file structure for Prisma database service in current directory. + +```sh +prisma init +``` + +##### Create file structure for Prisma database service in directory called `database`. + +```sh +prisma init database +``` diff --git a/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/02-prisma-deploy.md b/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/02-prisma-deploy.md new file mode 100644 index 0000000000..38ee54b484 --- /dev/null +++ b/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/02-prisma-deploy.md @@ -0,0 +1,40 @@ +--- +alias: kee1iedaov +description: Deploys service definition changes +--- + +# `prisma deploy` + +Deploys service definition changes. Every time you're making a local change to any file in the service definition on your machine, you need to synchronize these changes with the remote service using this command. + +#### Usage + +```sh +prisma deploy [flags] +``` + +#### Flags + +``` +-D, --default Set specified stage as default +-d, --dry-run Perform a dry-run of the deployment +-f, --force Accept data loss caused by schema changes +-i, --interactive Force interactive mode to select the cluster +-j, --json JSON Output +--dotenv DOTENV Path to .env file to inject env vars +--no-seed Disable seed on initial service deploy +``` + +#### Examples + +##### Deploy service + +```sh +prisma deploy +``` + +##### Deploy service with specific environment variables + +```sh +prisma deploy --dotenv .env.prod +``` diff --git a/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/03-prisma-info.md b/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/03-prisma-info.md new file mode 100644 index 0000000000..3430f43533 --- /dev/null +++ b/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/03-prisma-info.md @@ -0,0 +1,17 @@ +--- +alias: cheeni9mae +description: Prints meta-data about a specific service +--- + +# `prisma info` + +Prints meta-data about a specific service. The information contains: + +- All clusters to which the service is currently deployed +- API endpoints + +#### Usage + +```sh +prisma info +``` diff --git a/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/05-prisma-token.md b/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/05-prisma-token.md new file mode 100644 index 0000000000..65d6edc3d0 --- /dev/null +++ b/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/05-prisma-token.md @@ -0,0 +1,14 @@ +--- +alias: shoo8cioto +description: Create a new service token +--- + +# `prisma token` + +Create a new service token + +#### Usage + +```sh +prisma token [flags] +``` diff --git a/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/06-prisma-logs.md b/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/06-prisma-logs.md new file mode 100644 index 0000000000..22cae84137 --- /dev/null +++ b/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/06-prisma-logs.md @@ -0,0 +1,14 @@ +--- +alias: aenael2eek +description: Prints the access logs of your Prisma service. +--- + +# `prisma logs` + +Prints the access logs of your Prisma service. + +#### Usage + +```sh +prisma logs [flags] +``` diff --git a/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/08-prisma-list.md b/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/08-prisma-list.md new file mode 100644 index 0000000000..ff198be2f4 --- /dev/null +++ b/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/08-prisma-list.md @@ -0,0 +1,14 @@ +--- +alias: out6eechoi +description: List all deployed services +--- + +# `prisma list` + +List all deployed services. + +#### Usage + +```sh +prisma list +``` diff --git a/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/09-prisma-delete.md b/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/09-prisma-delete.md new file mode 100644 index 0000000000..8058c87673 --- /dev/null +++ b/docs/1.1/04-Reference/06-CLI-Command-Reference/01-Database-Service/09-prisma-delete.md @@ -0,0 +1,20 @@ +--- +alias: eizai4ahno +description: Delete an existing target from the cluster its deployed to +--- + +# `prisma delete` + +Delete an existing target from the cluster its deployed to. + +#### Usage + +```sh +prisma delete [flags] +``` + +#### Flags + +``` + -f, --force Force delete, without confirmation +``` diff --git a/docs/1.1/04-Reference/06-CLI-Command-Reference/02-Data-Workflows/01-prisma-playground.md b/docs/1.1/04-Reference/06-CLI-Command-Reference/02-Data-Workflows/01-prisma-playground.md new file mode 100644 index 0000000000..41d4a5549f --- /dev/null +++ b/docs/1.1/04-Reference/06-CLI-Command-Reference/02-Data-Workflows/01-prisma-playground.md @@ -0,0 +1,21 @@ +--- +alias: anaif5iez3 +description: Open the GraphQL Playground +--- + +# `prisma playground` + +Open a [GraphQL Playground](https://github.com/graphcool/graphql-playground) for the current service. The current service is determined by the default environment that's specified in the `.prismarc` of the directory in which you're executing the command. + +#### Usage + +```sh +prisma playground [flags] +``` + +#### Flags + +``` +--dotenv DOTENV Path to .env file to inject env vars +-w, --web Open browser-based Playground +``` diff --git a/docs/1.1/04-Reference/06-CLI-Command-Reference/02-Data-Workflows/02-prisma-import.md b/docs/1.1/04-Reference/06-CLI-Command-Reference/02-Data-Workflows/02-prisma-import.md new file mode 100644 index 0000000000..2422371ff7 --- /dev/null +++ b/docs/1.1/04-Reference/06-CLI-Command-Reference/02-Data-Workflows/02-prisma-import.md @@ -0,0 +1,21 @@ +--- +alias: ah3phephev +description: Import data +--- + +# `prisma import` + +Import data into the database of your Prisma service. The data needs to be formatted according to the [Normalized Data Format](!alias-teroo5uxih). For more info, read the [Data Import](!alias-ol2eoh8xie) chapter. + +#### Usage + +```sh +prisma import [flags] +``` + +#### Flags + +``` +-d, --data PATH File path to a .zip directory with import data (NDF) +--dotenv DOTENV Path to .env file to inject env vars +``` diff --git a/docs/1.1/04-Reference/06-CLI-Command-Reference/02-Data-Workflows/03-prisma-export.md b/docs/1.1/04-Reference/06-CLI-Command-Reference/02-Data-Workflows/03-prisma-export.md new file mode 100644 index 0000000000..4c338a65c5 --- /dev/null +++ b/docs/1.1/04-Reference/06-CLI-Command-Reference/02-Data-Workflows/03-prisma-export.md @@ -0,0 +1,34 @@ +--- +alias: oonu0quai2 +description: Export service data to a local file +--- + +# `prisma export` + +Exports your service data. + +#### Usage + +```sh +prisma export [flags] +``` + +#### Flags + +``` +--dotenv DOTENV Path to .env file to inject env vars +``` + +#### Examples + +##### Export data + +```sh +prisma export +``` + +##### Export data with specific environment variables + +```sh +prisma export --dotenv .env.prods +``` diff --git a/docs/1.1/04-Reference/06-CLI-Command-Reference/02-Data-Workflows/04-prisma-reset.md b/docs/1.1/04-Reference/06-CLI-Command-Reference/02-Data-Workflows/04-prisma-reset.md new file mode 100644 index 0000000000..b06cb430f6 --- /dev/null +++ b/docs/1.1/04-Reference/06-CLI-Command-Reference/02-Data-Workflows/04-prisma-reset.md @@ -0,0 +1,18 @@ +--- +alias: clchg7lwe1 +description: Reset data +--- + +# `prisma reset` + +#### Usage + +```sh +prisma reset [flags] +``` + +#### Flags + +``` +--dotenv DOTENV Path to .env file to inject env vars +``` diff --git a/docs/1.1/04-Reference/06-CLI-Command-Reference/03-Local-Development/01-prisma-local-start.md b/docs/1.1/04-Reference/06-CLI-Command-Reference/03-Local-Development/01-prisma-local-start.md new file mode 100644 index 0000000000..2e7e286661 --- /dev/null +++ b/docs/1.1/04-Reference/06-CLI-Command-Reference/03-Local-Development/01-prisma-local-start.md @@ -0,0 +1,20 @@ +--- +alias: woh9sheith +description: Start local development cluster (Docker required) +--- + +# `prisma local start` + +Start local development cluster (Docker required). + +#### Usage + +```sh +prisma local start [flags] +``` + +#### Flags + +``` + -n, --name NAME Name of the cluster instance +``` diff --git a/docs/1.1/04-Reference/06-CLI-Command-Reference/03-Local-Development/02-prisma-local-stop.md b/docs/1.1/04-Reference/06-CLI-Command-Reference/03-Local-Development/02-prisma-local-stop.md new file mode 100644 index 0000000000..f220b526f7 --- /dev/null +++ b/docs/1.1/04-Reference/06-CLI-Command-Reference/03-Local-Development/02-prisma-local-stop.md @@ -0,0 +1,20 @@ +--- +alias: vu5ohngud5 +description: Stop local development cluster +--- + +# `prisma local stop` + +Stop local development cluster. + +#### Usage + +```sh +prisma local stop [flags] +``` + +#### Flags + +``` + -n, --name NAME Name of the cluster instance +``` diff --git a/docs/1.1/04-Reference/06-CLI-Command-Reference/03-Local-Development/03-prisma-local-upgrade.md b/docs/1.1/04-Reference/06-CLI-Command-Reference/03-Local-Development/03-prisma-local-upgrade.md new file mode 100644 index 0000000000..71125a95f8 --- /dev/null +++ b/docs/1.1/04-Reference/06-CLI-Command-Reference/03-Local-Development/03-prisma-local-upgrade.md @@ -0,0 +1,14 @@ +--- +alias: quungoogh9 +description: Download latest Docker image of the local cluster. +--- + +# `prisma local pull` + +Download latest Docker image of the local cluster. + +#### Usage + +```sh +prisma local upgrade +``` diff --git a/docs/1.1/04-Reference/06-CLI-Command-Reference/03-Local-Development/06-prisma-local-nuke.md b/docs/1.1/04-Reference/06-CLI-Command-Reference/03-Local-Development/06-prisma-local-nuke.md new file mode 100644 index 0000000000..81950dd8fd --- /dev/null +++ b/docs/1.1/04-Reference/06-CLI-Command-Reference/03-Local-Development/06-prisma-local-nuke.md @@ -0,0 +1,20 @@ +--- +alias: bai9yeitoa +description: Hard-reset local development cluster. +--- + +# `prisma local nuke` + +Hard-reset local development cluster. **This irrevocably wipes all the services including data in your local cluster**. + +#### Usage + +```sh +prisma local logs [flags] +``` + +#### Flags + +``` + -n, --name NAME Name of the cluster instance +``` diff --git a/docs/1.1/04-Reference/06-CLI-Command-Reference/04-Clusters/01-prisma-cluster-list.md b/docs/1.1/04-Reference/06-CLI-Command-Reference/04-Clusters/01-prisma-cluster-list.md new file mode 100644 index 0000000000..e0ea7a9284 --- /dev/null +++ b/docs/1.1/04-Reference/06-CLI-Command-Reference/04-Clusters/01-prisma-cluster-list.md @@ -0,0 +1,14 @@ +--- +alias: woh0sheith +description: List all clusters. +--- + +# `prisma cluster list` + +List all clusters + +#### Usage + +```sh +prisma cluster list [flags] +``` diff --git a/docs/1.1/04-Reference/06-CLI-Command-Reference/04-Clusters/02-prisma-cluster-logs.md b/docs/1.1/04-Reference/06-CLI-Command-Reference/04-Clusters/02-prisma-cluster-logs.md new file mode 100644 index 0000000000..79dddcf463 --- /dev/null +++ b/docs/1.1/04-Reference/06-CLI-Command-Reference/04-Clusters/02-prisma-cluster-logs.md @@ -0,0 +1,14 @@ +--- +alias: vu2ohngud7 +description: Output cluster logs. +--- + +# `prisma cluster logs` + +Output cluster logs. + +#### Usage + +```sh +prisma local logs [flags] +``` diff --git a/docs/1.1/04-Reference/06-CLI-Command-Reference/04-Clusters/03-prisma-cluster-add.md b/docs/1.1/04-Reference/06-CLI-Command-Reference/04-Clusters/03-prisma-cluster-add.md new file mode 100644 index 0000000000..036199e652 --- /dev/null +++ b/docs/1.1/04-Reference/06-CLI-Command-Reference/04-Clusters/03-prisma-cluster-add.md @@ -0,0 +1,14 @@ +--- +alias: quungoogh8 +description: Add an existing cluster. +--- + +# `prisma cluster add` + +Add an existing cluster. + +#### Usage + +```sh +prisma cluster add +``` diff --git a/docs/1.1/04-Reference/06-CLI-Command-Reference/04-Clusters/04-prisma-cluster-remove.md b/docs/1.1/04-Reference/06-CLI-Command-Reference/04-Clusters/04-prisma-cluster-remove.md new file mode 100644 index 0000000000..45a9695373 --- /dev/null +++ b/docs/1.1/04-Reference/06-CLI-Command-Reference/04-Clusters/04-prisma-cluster-remove.md @@ -0,0 +1,14 @@ +--- +alias: voh6pa5teo +description: Remove cluster. +--- + +# `prisma cluster remove` + +Remove cluster + +#### Usage + +```sh +prisma cluster remove +``` diff --git a/docs/1.1/04-Reference/06-CLI-Command-Reference/index.md b/docs/1.1/04-Reference/06-CLI-Command-Reference/index.md new file mode 100644 index 0000000000..4cca388d74 --- /dev/null +++ b/docs/1.1/04-Reference/06-CLI-Command-Reference/index.md @@ -0,0 +1,3 @@ +--- +description: A reference list of all Prisma CLI commands. +--- diff --git a/docs/1.1/05-FAQ/01-General.md b/docs/1.1/05-FAQ/01-General.md new file mode 100644 index 0000000000..77f7f3fb18 --- /dev/null +++ b/docs/1.1/05-FAQ/01-General.md @@ -0,0 +1,47 @@ +--- +alias: iph5dieph9 +description: Frequently asked questions about basic topics and general issues all around Prisma. +--- + +# General + +### What is Prisma? + +Prisma an _abstraction layer_ that turns your database into a GraphQL API. Instead of having to deal with SQL or the APIs of a NoSQL database, you'll be able to use the full power of [GraphQL](http://graphql.org/) to interact with your data. + +GraphQL is the future of API development, many big companies (like Facebook, Twitter, Yelp, IBM and [more](http://graphql.org/users/)) as well as smaller startups and teams are using it in production already today. Prisma makes it easy to build your own GraphQL server while taking advantage of the rich [GraphQL ecosystem](https://www.prismagraphql.com/docs/graphql-ecosystem/). + +> Note that GraphQL as well as Prisma are entirely **open source** - there is absolutely **no vendor lock-in** when building a GraphQL server with Prisma! + +### How can I use Prisma? + +There are two major ways for using Prisma: + +- Use Prisma as the foundation for your own GraphQL server +- Access Prisma's GraphQL API directly from the frontend + +With the first use case you have all the power and flexibility that comes along when building your own server. You can implemented your own business logic, provide custom authentication workflows and talk to 3rd-party APIs. + +The second use case gets you up and running with a hosted GraphQL API very quickly. It doesn't allow for much business logic as the API only provides CRUD operations for the types in your data model (including features like sorting, filtering and pagination). It therefore is better suited for simple applications that only need to fetch and store some data, for prototyping or if you just want to learn how to use GraphQL! + +Prisma services are managed with the [Prisma CLI](https://github.com/graphcool/prisma/tree/master/cli) which you can install as follows: + +```sh +npm install -g prisma +``` + +The best way to get started is through our [Quickstart](https://www.prismagraphql.com/docs/quickstart/) page. + +### What programming languages does Prisma work with? + +Prisma (like GraphQL) is language agnostic and will work with any programming language. That said, the best support for building GraphQL servers is currently provided by the JavaScript ecosystem, thanks to tooling like `graphql-js` or [GraphQL bindings](https://blog.graph.cool/reusing-composing-graphql-apis-with-graphql-bindings-80a4aa37cff5). However, it is definitely feasible to use GraphQL in different programming languages as well. Prisma itself is implemented in Scala and TypeScript. + +### What platforms and cloud providers does Prisma work with? + +Prisma is based on [Docker](https://www.docker.com/) which really makes it up to the developer _where_ and _how_ Prisma should be deployed. + +A few examples are [Digital Ocean](https://www.digitalocean.com/) (find a deployment tutorial [here](!alias-texoo9aemu)), [Microsoft Azure](https://azure.microsoft.com/en-us/), [Google Compute Engine](https://cloud.google.com/compute/), [AWS](https://aws.amazon.com/), [Heroku](https://www.heroku.com/). + +### Who should use Prisma? + +Prisma is _the_ tool for everyone who wants to build production-ready and scalable GraphQL servers - no matter the team size or project scope. diff --git a/docs/1.1/05-FAQ/02-Technical.md b/docs/1.1/05-FAQ/02-Technical.md new file mode 100644 index 0000000000..6276e09b55 --- /dev/null +++ b/docs/1.1/05-FAQ/02-Technical.md @@ -0,0 +1,54 @@ +--- +alias: eep0ugh1wa +description: Frequently asked questions about any technical matters regarding Prisma. +--- + +# Technical + +### Can I host Prisma myself? + +There are basically two ways for hosting Prisma: + +- Do it yourself (using any available cloud provider, such as Digital Ocean, AWS, Google Cloud, ...) +- In the Prisma Cloud (coming soon) + +### How do I connect my database to Prisma? + +At the moment, Prisma only supports MySQL as a database technology (with [a lot more](https://github.com/graphcool/graphcool/issues/1006) planned in the future). Connecting an existing MySQL database will require the following steps: + +1. Translate your SQL schema into a GraphQL data model written in [SDL](https://blog.graph.cool/graphql-sdl-schema-definition-language-6755bcb9ce51) +1. Deploy a Prisma service with that data model +1. If your database previously contained some data, [import the data](!alias-caith9teiy) into your Prisma service + +If you want to migrate from an existing data source, you can check out our plans to support automatic data imports [here](https://github.com/graphcool/graphcool/issues/1410). + +### What databases does Prisma support? + +**MySQL** is the very first database supported by Prisma. Here's a list of more databases to be supported soon: + +- **Postgres** (see [feature request](https://github.com/graphcool/prisma/issues/1641)) +- **MongoDB** (see [feature request](https://github.com/graphcool/prisma/issues/1643)) +- Oracle +- MS SQL +- ArangoDB +- Neo4j +- Druid +- Dgraph + +If you have any preferences on which of these you'd like to see implemented first, you can create a new feature request asking for support or give a +1 for an existing one. + +### What are the benefits of GraphQL? + +GraphQL comes with a plethora of benefits for application development: + +- GraphQL allows client applications to **request exactly the data they need from an API** (which reduces network traffic and increases performance). +- When accessing a GraphQL API from the frontend, you can use a GraphQL client library (such as Apollo Client or Relay) which **reduces frontend boilerplate** and provides **out-of-the-box support for features like caching, optimistic UI updates, realtime functionality, offline support and more**. +- GraphQL APIs are based on a strongly typed [schema](https://blog.graph.cool/graphql-server-basics-the-schema-ac5e2950214e) which effectively provides a way for you to have a **strongly typed API layer**. This means developers can be confident about the operations an API allows and the shape of the responsed to be returned by the server. +- GraphQL has an **amazing ecosystem of tooling** which greatly improve workflows and overall developer experience. For example, [GraphQL Playground](!alias-chaha125ho) which provides an interactive IDE for sending queries and mutations to an API (which can even be used by non-technical audiences). Another example are [GraphQL bindings](!alias-quaidah9ph) which enable to compose existing GraphQL APIs like LEGO bricks. +- The GraphQL ecosystem is made the **fantastic GraphQL community** who is putting in a lot of thought as well as hard work for how GraphQL can be evolved in the future and what other tools developers will benefit from. + +### How do backups work + +Since Prisma is only a layer _on top of your database_ but you still have full control over the database itself, you have the full power and flexibility regarding your own backup strategy. + +Prisma also offers a [data export](!alias-pa0aip3loh) feature which you can use to create continuous backups for your data from the API layer. diff --git a/docs/1.1/05-FAQ/03-Console-&-Dashboard.md b/docs/1.1/05-FAQ/03-Console-&-Dashboard.md new file mode 100644 index 0000000000..df2f40359e --- /dev/null +++ b/docs/1.1/05-FAQ/03-Console-&-Dashboard.md @@ -0,0 +1,10 @@ +--- +alias: ikahjeex0x +description: Frequently asked questions about everything that relates to the Prisma Console & Dashboard. +--- + +# Console & Dashboard + +The dashboard is **coming soon**. Here's a preview of what it's going to look like. + +![](https://imgur.com/45qEzeF.png) diff --git a/docs/1.1/05-FAQ/04-Pricing.md b/docs/1.1/05-FAQ/04-Pricing.md new file mode 100644 index 0000000000..aec288bba4 --- /dev/null +++ b/docs/1.1/05-FAQ/04-Pricing.md @@ -0,0 +1,12 @@ +--- +alias: fae2ooth2u +description: Frequently asked questions everything about Prisma's pricing model. +--- + +# Pricing + +More info on pricing structure will follow soon. For now, the following points are important: + +- Prisma is entirely open-source and be hosted with any cloud provider +- There is a free public cluster that can be used to deploy Prisma services without cost or even requiring authentication +- There will be hosting options in the Prisma Cloud in the future diff --git a/docs/1.1/05-FAQ/05-Other.md b/docs/1.1/05-FAQ/05-Other.md new file mode 100644 index 0000000000..850e8f6026 --- /dev/null +++ b/docs/1.1/05-FAQ/05-Other.md @@ -0,0 +1,26 @@ +--- +alias: reob2ohph7 +description: Frequently asked questions about Prisma as a company, the platform itself and other topics. +--- + +# Other + +### Where can I ask more questions? + +You can contact us through a variety of channels. + +If you have a **technical problem**, the best way to find help is either in our [Forum](https://www.graph.cool/forum/) or on [Stack Overflow](https://stackoverflow.com/questions/tagged/graphcool). + +To **get involved in our open source work** and **obtain insights into our roadmap**, you should check out our [GitHub organization](github.com/graphcool/). + +If you just want to hang out and chat with GraphQL enthusiasts, our [Slack](https://slack.graph.cool) channel is the place to be. + +Finally, for any direct requests, you can always reach out to us via email: [Sales](mailto:sales@graph.cool) & [Support](mailto:support@graph.cool). + +### How is this different from Graphcool Framework? + +The Graphcool Framework is a strongly opinionated open-source solution based on GraphQL and Serverless functions, that provides an entire web server setup with a powerful GraphQL API. + +Prisma is the result of many learnings and a lot of feedback from customers and the community, that focuses on the core of Graphcool Framework: the automatic mapping from your database to a GraphQL API. This enables you to take full control of your GraphQL server while still being able to benefit from an auto-generated and powerful GraphQL API. + +If you have further questions about how the Graphcool Framework and Prisma compare, go [join the discussion in the Forum](https://www.graph.cool/forum/t/graphcool-framework-and-prisma/2237?u=nilan). diff --git a/docs/1.1/06-GraphQL-Ecosystem/01-GraphQL-Yoga/01-Overview.md b/docs/1.1/06-GraphQL-Ecosystem/01-GraphQL-Yoga/01-Overview.md new file mode 100644 index 0000000000..50e2fc81ca --- /dev/null +++ b/docs/1.1/06-GraphQL-Ecosystem/01-GraphQL-Yoga/01-Overview.md @@ -0,0 +1,229 @@ +--- +alias: chaha122ho +description: GraphQL Yoga is a fully-featured GraphQL Server with focus on easy setup, performance & great developer experience. +--- + +# graphql-yoga + +[`graphql-yoga`](https://github.com/graphcool/graphql-yoga/) is a fully-featured GraphQL Server with focus on easy setup, performance & great developer experience. + +## Overview + +* **Easiest way to run a GraphQL server:** Sensible defaults & includes everything you need with minimal setup. +* **Includes Subscriptions:** Built-in support for GraphQL Subscriptions using WebSockets. +* **Compatible:** Works with all GraphQL clients (Apollo, Relay...) and fits seamless in your GraphQL workflow. + +`graphql-yoga` is based on the following libraries & tools: + +* [`express`](https://github.com/expressjs/express)/[`apollo-server`](https://github.com/apollographql/apollo-server): Performant, extensible web server framework +* [`graphql-subscriptions`](https://github.com/apollographql/graphql-subscriptions)/[`subscriptions-transport-ws`](https://github.com/apollographql/subscriptions-transport-ws): GraphQL subscriptions server +* [`graphql.js`](https://github.com/graphql/graphql-js)/[`graphql-tools`](https://github.com/apollographql/graphql-tools): GraphQL engine & schema helpers +* [`graphql-playground`](https://github.com/graphcool/graphql-playground): Interactive GraphQL IDE + +## Features + +* GraphQL spec-compliant +* File upload +* GraphQL Subscriptions +* TypeScript typings +* GraphQL Playground +* Extensible via Express middlewares +* Apollo Tracing +* Accepts both `application/json` and `application/graphql` content-type +* Runs everywhere: Can be deployed via `now`, `up`, AWS Lambda, Heroku etc + +## Install + +```sh +yarn add graphql-yoga +``` + +## Usage + +### Quickstart ([Hosted demo](https://hello-world-myitqprcqm.now.sh)) + +```ts +import { GraphQLServer } from 'graphql-yoga' +// ... or using `require()` +// const { GraphQLServer } = require('graphql-yoga') + +const typeDefs = ` + type Query { + hello(name: String): String! + } +` + +const resolvers = { + Query: { + hello: (_, { name }) => `Hello ${name || 'World'}`, + }, +} + +const server = new GraphQLServer({ typeDefs, resolvers }) +server.start(() => console.log('Server is running on localhost:4000')) +``` + +> To get started with `graphql-yoga`, follow the instructions in the READMEs of the [examples](./examples). + +### API + +#### GraphQLServer + +```ts +constructor(props: Props): GraphQLServer +``` + +The `props` argument accepts the following fields: + +| Key | Type | Default | Note | +| --- | --- | --- | --- | +| `typeDefs` | String | `null` | Contains GraphQL type definitions in [SDL](https://blog.graph.cool/graphql-sdl-schema-definition-language-6755bcb9ce51) or file path to type definitions (required if `schema` is not provided \*) | +| `resolvers` | Object | `null` | Contains resolvers for the fields specified in `typeDefs` (required if `schema` is not provided \*) | +| `schema` | Object | `null` | An instance of [`GraphQLSchema`](http://graphql.org/graphql-js/type/#graphqlschema) (required if `typeDefs` and `resolvers` are not provided \*) | +| `context` | Object or Function | `{}` | Contains custom data being passed through your resolver chain. This can be passed in as an object, or as a Function with the signature `(req: Request) => any` | + +> (*) There are two major ways of providing the [schema](https://blog.graph.cool/graphql-server-basics-the-schema-ac5e2950214e) information to the `constructor`: +> +> 1. Provide `typeDefs` and `resolvers` and omit the `schema`, in this case `graphql-yoga` will construct the `GraphQLSchema` instance using [`makeExecutableSchema`](https://www.apollographql.com/docs/graphql-tools/generate-schema.html#makeExecutableSchema) from [`graphql-tools`](https://github.com/apollographql/graphql-tools). +> 1. Provide the `schema` directly and omit `typeDefs` and `resolvers`. + +Here is example of creating a new server: + +```js +const typeDefs = ` + type Query { + hello(name: String): String! + } +` + +const resolvers = { + Query: { + hello: (_, { name }) => `Hello ${name || 'World'}`, + }, +} + +const server = new GraphQLServer({ typeDefs, resolvers }) +``` + +#### server.start(...) + +```ts +start(options: Options, callback: ((options: Options) => void) = (() => null)): Promise +``` + +Once your `GraphQLServer` is instantiated, you can call the `start` method on it. It takes two arguments: `options`, the options object defined above, and `callback`, a function that's invoked right before the server is started. As an example, the `callback` can be used to print information that the server was now started. + +The `options` object has the following fields: + +| Key | Type | Default | Note | +| --- | --- | --- | --- | +| `cors` | Object | `null` | Contains [configuration options](https://github.com/expressjs/cors#configuration-options) for [cors](https://github.com/expressjs/cors) | +| `tracing` | Boolean or String | `'http-header'` | Indicates whether [Apollo Tracing](https://github.com/apollographql/apollo-tracing) should be en- or disabled for your server (if a string is provided, accepted values are: `'enabled'`, `'disabled'`, `'http-header'`) | +| `port` | Number | `4000` | Determines the port your server will be listening on (note that you can also specify the port by setting the `PORT` environment variable) | +| `endpoint` | String | `'/'` | Defines the HTTP endpoint of your server | +| `subscriptions` | String or `false` | `'/'` | Defines the subscriptions (websocket) endpoint for your server; setting to `false` disables subscriptions completely | +| `playground` | String or `false` | `'/'` | Defines the endpoint where you can invoke the [Playground](https://github.com/graphcool/graphql-playground); setting to `false` disables the playground endpoint | +| `uploads` | Object or `false` | `null` | Provides information about upload limits; the object can have any combination of the following three keys: `maxFieldSize`, `maxFileSize`, `maxFiles`; each of these have values of type Number; setting to `false` disables file uploading | + +Additionally, the `options` object exposes these `apollo-server` options: + +| Key | Type | Note | +| --- | --- | --- | +| `cacheControl` | Boolean | Enable extension that returns Cache Control data in the response | +| `formatError` | Number | A function to apply to every error before sending the response to clients | +| `logFunction` | LogFunction | A function called for logging events such as execution times | +| `rootValue` | any | RootValue passed to GraphQL execution | +| `validationRules` | Array of functions | DAdditional GraphQL validation rules to be applied to client-specified queries | +| `fieldResolver` | GraphQLFieldResolver | Provides information about upload limits; the object can have any combination of the following three keys: `maxFieldSize`, `maxFileSize`, `maxFiles`; each of these have values of type Number; setting to `false` disables file uploading | +| `formatParams` | Function | A function applied for each query in a batch to format parameters before execution | +| `formatResponse` | Function | A function applied to each response after execution | +| `debug` | boolean | Print additional debug logging if execution errors occur | + +```js +const options = { + port: 8000, + endpoint: '/graphql', + subscriptions: '/subscriptions', + playground: '/playground', +} + +server.start(options, ({ port }) => console.log(`Server started, listening on port ${port} for incoming requests.`)) +``` + +#### PubSub + +See the original documentation in [`graphql-subscriptions`](https://github.com/apollographql/graphql-subscriptions). + +### Endpoints + +## Examples + +There are three examples demonstrating how to quickly get started with `graphql-yoga`: + +- [hello-world](https://github.com/graphcool/graphql-yoga/tree/master/examples/hello-world): Basic setup for building a schema and allowing for a `hello` query. +- [subscriptions](https://github.com/graphcool/graphql-yoga/tree/master/examples/subscriptions): Basic setup for using subscriptions with a counter that increments every 2 seconds and triggers a subscriptions. +- [fullstack](https://github.com/graphcool/graphql-yoga/tree/master/examples/fullstack): Fullstack example based on [`create-react-app`](https://github.com/facebookincubator/create-react-app) demonstrating how to query data from `graphql-yoga` with [Apollo Client 2.0](https://www.apollographql.com/client/). + +## Workflow + +Once your `graphql-yoga` server is running, you can use [GraphQL Playground](https://github.com/graphcool/graphql-playground) out of the box – typically running on `localhost:4000`. (Read [here](https://blog.graph.cool/introducing-graphql-playground-f1e0a018f05d) for more information.) + +[![](https://imgur.com/6IC6Huj.png)](https://www.graphqlbin.com/RVIn) + +## Deployment + +### `now` + +To deploy your `graphql-yoga` server with [`now`](https://zeit.co/now), follow these instructions: + +1. Download [**Now Desktop**](https://zeit.co/download) +1. Navigate to the root directory of your `graphql-yoga` server +1. Run `now` in your terminal + +### Heroku + +To deploy your `graphql-yoga` server with [Heroku](https://heroku.com), follow these instructions: + +1. Download and install the [Heroku Command Line Interface](https://devcenter.heroku.com/articles/heroku-cli#download-and-install) (previously Heroku Toolbelt) +1. Log In to the Heroku CLI with `heroku login` +1. Navigate to the root directory of your `graphql-yoga` server +1. Create the Heroku instance by executing `heroku create` +1. Deploy your GraphQL server by executing `git push heroku master` + +### `up` (Coming soon 🔜 ) + +### AWS Lambda (Coming soon 🔜 ) + +## FAQ + +### How does `graphql-yoga` compare to `apollo-server` and other tools? + +As mentioned above, `graphql-yoga` is built on top of a variety of other packages, such as `graphql.js`, `express` and `apollo-server`. Each of these provide a certain piece of functionality required for building a GraphQL server. + +Using these packages individually incurs overhead in the setup process and requires you to write a lot of boilerplate. `graphql-yoga` abstracts away the initial complexity and required boilerplate and let's you get started quickly with a set of sensible defaults for your server configuration. + +`graphql-yoga` is like [`create-react-app`](https://github.com/facebookincubator/create-react-app) for building GraphQL servers. + +### Can't I just setup my own GraphQL server using `express` and `graphql.js`? + +`graphql-yoga` is all about convenience and a great "Getting Started"-experience by abstracting away the complexity that comes when you're building your own GraphQL from scratch. It's a pragmatic approach to bootstrap a GraphQL server, much like [`create-react-app`](https://github.com/facebookincubator/create-react-app) removes friction when first starting out with React. + +Whenever the defaults of `graphql-yoga` are too tight of a corset for you, you can simply _eject_ from it and use the tooling it's build upon - there's no lock-in or any other kind of magic going on preventing you from this. + +### How to eject from the standard `express` setup? + +The core value of `graphql-yoga` is that you don't have to write the boilerplate required to configure your [express.js](https://github.com/expressjs/) application. However, once you need to add more customized behaviour to your server, the default configuration provided by `graphql-yoga` might not suit your use case any more. For example, it might be the case that you want to add more custom _middleware_ to your server, like for logging or error reporting. + +For these cases, `GraphQLServer` exposes the `express.Application` directly via its [`express`](./src/index.ts#L17) property: + +```js +server.express.use(myMiddleware()) +``` + +Middlewares can also be added specifically to the GraphQL endpoint route, by using: + +```js +server.express.post(server.options.endpoint, myMiddleware()) +``` + +Any middlewares you add to that route, will be added right before the `apollo-server-express` middleware. diff --git a/docs/1.1/06-GraphQL-Ecosystem/02-GraphQL-Binding/01-GraphQL-Binding.md b/docs/1.1/06-GraphQL-Ecosystem/02-GraphQL-Binding/01-GraphQL-Binding.md new file mode 100644 index 0000000000..60e1e0a8ae --- /dev/null +++ b/docs/1.1/06-GraphQL-Ecosystem/02-GraphQL-Binding/01-GraphQL-Binding.md @@ -0,0 +1,153 @@ +--- +alias: quaidah9ph +description: GraphQL Bindings are modular building blocks that allow to embed existing GraphQL APIs into your own GraphQL server. +--- + +# graphql-binding + +🔗 [`graphql-binding`](https://github.com/graphcool/graphql-binding/) is a package that simplifies the process of creating your own GraphQL bindings. GraphQL bindings are **modular building blocks** that allow to embed existing GraphQL APIs into your own GraphQL server. Think about it as turning (parts of) GraphQL APIs into reusable LEGO building blocks. + +> The idea of GraphQL bindings is introduced in detail in this blog post: [Reusing & Composing GraphQL APIs with GraphQL Bindings](https://blog.graph.cool/80a4aa37cff5) + +## Install + +```sh +yarn add graphql-binding +``` + +## API + +### Binding + +#### constructor + +```ts +constructor(options: BindingOptions): Binding +``` + +[`BindingOptions`](./src/types.ts#L27) has the following properties: + +| Key | Required | Type | Default | Note | +| --- | --- | --- | --- | --- | +| `schema` | Yes | `GraphQLSchema` | - | The executable [GraphQL schema](https://blog.graph.cool/ac5e2950214e) for binding | +| `fragmentReplacements` | No | `FragmentReplacements` | `{}` | A list of GraphQL fragment definitions, specifying fields that are required for the resolver to function correctly | +| `before` | No | `() => void` | `(() => undefined)` | A function that will be executed before a query/mutation is sent to the GraphQL API | +| `handler` | No | `any` | `null` | The [`handler`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler) object from [JS Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) | +| `subscriptionHandler` | No | `any` | `null` | ... | + +#### query & mutation + +```ts +binding.query.: QueryMap // where is the name of a field on the Query type in the mapped GraphQL schema +binding.mutation.: QueryMap // where is the name of a field on the Mutation type in the mapped GraphQL schema +``` + +A `binding` object exposes two properties which can be used to send queries and mutations to the API: `binding.query` and `binding.mutation`. + +Both are of type [`QueryMap`](src/types.ts#L11) and will expose methods that are named after the schema's root fields on the `Query` and `Mutation` types. + +These methods take three arguments: + +| Name | Required | Type | Note | +| --- | --- | --- | --- | +| `args` | No | `[key: string]: any` | An object that contains the arguments of the root field | +| `context` | No | `[key: string]: any` | The `context` object that's passed down the GraphQL resolver chain; every resolver can read from and write to that object | +| `info` | No | `GraphQLResolveInfo` | `string` | The `info` object (which contains an AST of the incoming query/mutation) that's passed down the GraphQL resolver chain or a string containing a [selection set](https://medium.com/front-end-developers/graphql-selection-sets-d588f6782e90) | + +##### Example + +Assume the following schema: + +```graphql +type Query { + user(id: ID!): User +} + +type Mutation { + createUser(): User! +} +``` + +If there is a `binding` for a GraphQL API that implements this schema, you can invoke the following methods on it: + +```js +binding.query.user({ id: 'abc' }) +binding.mutation.createUser() +``` + +When using the binding in a resolver implementation, it can be used as follows: + +```js +findUser(parent, args, context, info) { + return binding.user({ id: args.id }, context, info) +} + +newUser(parent, args, context, info) { + return binding.createUser({}, context, info) +} +``` + +#### subscription + +```ts +binding.subscription.(...): AsyncIterator | Promise> // where is the name of a field on the Subscription type in the mapped GraphQL schema +``` + +The `binding.subscription` property follows the same idea as `query` and `mutation`, but rather than returning a single value using a `Promise`, it returns a _stream_ of values using `AsyncIterator`. + + It is of type [`SubscriptionMap`](./src/types.ts#L19) and will expose methods that are named after the schema's root fields on the `Subscription` type. + + These methods take same three arguments as the generated methods on `query` and `mutation`, see above for the details. + +## Examples + +### Minimal example + +```js +const { makeExecutableSchema } = require('graphql-tools') +const { Binding } = require('graphql-binding') + +const users = [ + { + name: 'Alice', + }, + { + name: 'Bob', + }, +] + +const typeDefs = ` + type Query { + findUser(name: String!): User + } + type User { + name: String! + } +` + +const resolvers = { + Query: { + findUser: (parent, { name }) => users.find(u => u.name === name), + }, +} + +const schema = makeExecutableSchema({ typeDefs, resolvers }) + +const findUserBinding = new Binding({ + schema, +}) + +findUserBinding.findUser({ name: 'Bob' }) + .then(result => console.log(result)) +``` + +## Public GraphQL bindings + +You can find practical, production-ready examples here: + +- [`graphql-binding-github`](https://github.com/graphcool/graphql-binding-github) +- [`graphcool-binding`](https://github.com/graphcool/graphcool-binding) + +> Note: If you've created your own GraphQL binding based on this package, please add it to this list via a PR 🙌 + +If you have any questions, share some ideas or just want to chat about GraphQL bindings, join the [`#graphql-bindings`](https://graphcool.slack.com/messages/graphql-bindings) channel in our [Slack](https://slack.graph.cool/). diff --git a/docs/1.1/06-GraphQL-Ecosystem/02-GraphQL-Binding/02-Prisma-Binding.md b/docs/1.1/06-GraphQL-Ecosystem/02-GraphQL-Binding/02-Prisma-Binding.md new file mode 100644 index 0000000000..c35273a73c --- /dev/null +++ b/docs/1.1/06-GraphQL-Ecosystem/02-GraphQL-Binding/02-Prisma-Binding.md @@ -0,0 +1,162 @@ +--- +alias: gai5urai6u +description: Prisma Binding provides a GraphQL Binding for Prisma services (GraphQL Database) +--- + +# prisma-binding + +[`prisma-binding`](https://github.com/graphcool/prisma-binding/) is a dedicated [GraphQL binding](!alias-quaidah9ph) for Prisma services. + +> If you're curious about this topic, you can read the [blog post](https://blog.graph.cool/80a4aa37cff5) which introduces the general idea of GraphQL bindings. + +## Overview + +`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. + +Here is how it works: + +1. Create your Prisma service by defining data model +1. Download generated database schema definition `database.graphql` (contains the full CRUD API) +1. Define your application schema, typically called `app.graphql` +1. Instantiate `Prisma` with information about your Prisma service (such as its endpoint and the path to the database schema definition) +1. Implement the resolvers for your application schema by delegating to the underlying Prisma service using the generated delegate resolver functions + +> **Note**: If you're using a [GraphQL boilerplate](https://github.com/graphql-boilerplates/) project (e.g. with `graphql create`), the Prisma binding will already be configured and a few example resolvers implemented for you. You can either try the _dynamic binding_ (e.g. in the [`node-basic`](https://github.com/graphql-boilerplates/node-graphql-server/tree/master/basic) boilerplate) or a _static binding_ (e.g in the [`typescript-basic`](https://github.com/graphql-boilerplates/typescript-graphql-server/tree/master/basic) boilerplate). + +## Install + +```sh +yarn add prisma-binding +# or +npm install --save prisma-binding +``` + +## Example + +Consider the following data model for your Prisma service: + +```graphql +type User { + id: ID! @unique + name: String +} +``` + +If you instantiate `Prisma` based on this service, you'll be able to send the following queries/mutations: + +```js +// Instantiate `Prisma` based on concrete service +const prisma = new Prisma({ + typeDefs: 'schemas/database.graphql', + endpoint: 'https://api.graph.cool/simple/v1/my-prisma-service' + secret: 'my-super-secret-secret' +}) + +// Retrieve `name` of a specific user +prisma.query.user({ where { id: 'abc' } }, '{ name }') + +// Retrieve `id` and `name` of all users +prisma.query.users(null, '{ id name }') + +// Create new user called `Sarah` and retrieve the `id` +prisma.mutation.createUser({ data: { name: 'Sarah' } }, '{ id }') + +// Update name of a specific user and retrieve the `id` +prisma.mutation.updateUser({ where: { id: 'abc' }, data: { name: 'Sarah' } }, '{ id }') + +// Delete a specific user and retrieve the `name` +prisma.mutation.deleteUser({ where: { id: 'abc' } }, '{ id }') +``` + +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/graphcool/graphql-request)). + +The API also allows to ask whether a specific node exists in your Prisma database: + +```js +// Ask whether a post exists with `id` equal to `abc` and whose +// `author` is called `Sarah` (return boolean value) +prisma.exists.Post({ + id: 'abc', + author: { + name: 'Sarah' + } +}) +``` + +## API + +### Prisma + +#### constructor + +```ts +constructor(options: PrismaOptions): Prisma +``` + +The `PrismaOptions` type has the following fields: + +| Key | Required | Type | Default | Note | +| --- | --- | --- | --- | --- | +| `schemaPath` | Yes | `string` | - | File path to the schema definition of your Prisma service (typically a file called `database.graphql`) | +| `endpoint` | Yes | `string` | - | The endpoint of your Prisma service | +| `secret` | Yes | `string` | - | The secret of your Prisma service | +| `fragmentReplacements` | No | `FragmentReplacements` | `null` | A list of GraphQL fragment definitions, specifying fields that are required for the resolver to function correctly | +| `debug` | No | `boolean` | `false` | Log all queries/mutations to the console | + +#### query & mutation + +`query` and `mutation` are public properties on your `Prisma` instance (see also the [GraphQL Binding documentation](!alias-quaidah9ph) for more info). 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. + +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. + +Delegate resolver have the following interface: + +```js +(args: any, info: GraphQLResolveInfo | string): Promise +``` + +The input arguments are used as follows: + +- `args`: An object carrying potential arguments for the query/mutation +- `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)) + +The generic type `T` corresponds to the type of the respective field. + +#### exists + +`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. + +This function enables you to easily check whether a node of a specific type exists in your Prisma database. + +#### request + +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. + +Here is an example of how it can be used: + +```js +const query = ` + query ($userId: ID!){ + user(id: $userId) { + id + name + } + } +` + +const variables = { userId: 'abc' } + +prisma.request(query, variables) + .then(result => console.log(result)) +// sample result: +// {"data": { "user": { "id": "abc", "name": "Sarah" } } } +``` + +## Usage + +- [graphql-boilerplate](https://github.com/graphcool/graphql-boilerplate). +- [graphql-server-example](https://github.com/graphcool/graphql-server-example). + +## Next steps + +- Code generation at build-time for the auto-generated delegate resolvers diff --git a/docs/1.1/06-GraphQL-Ecosystem/03-GraphQL-Playground/01-Overview.md b/docs/1.1/06-GraphQL-Ecosystem/03-GraphQL-Playground/01-Overview.md new file mode 100644 index 0000000000..5153f0f89d --- /dev/null +++ b/docs/1.1/06-GraphQL-Ecosystem/03-GraphQL-Playground/01-Overview.md @@ -0,0 +1,174 @@ +--- +alias: chaha125ho +description: GraphQL Playground is a GraphQL IDE for better development workflows (GraphQL subscriptions, interactive docs & collaboration). +--- + +# graphql-playground + +🎮 [`graphql-playground`](https://github.com/graphcool/graphql-playground/) is a GraphQL IDE for better development workflows (GraphQL subscriptions, interactive docs & collaboration). + +**You can download the [desktop app](https://github.com/graphcool/graphql-playground/releases) or use the web version at graphqlbin.com: [Demo](https://www.graphqlbin.com/RVIn)** + +[![](https://i.imgur.com/AE5W6OW.png)](https://www.graphqlbin.com/RVIn) + +## Features + +* ✨ Context-aware autocompletion & error highlighting +* 📚 Interactive, multi-column docs (keyboard support) +* ⚡️ Supports real-time GraphQL Subscriptions +* ⚙ GraphQL Config support with multiple Projects & Endpoints +* 🚥 Apollo Tracing support + +## FAQ + +### How is this different from [GraphiQL](https://github.com/graphql/graphiql)? + +GraphQL Playground uses components of GraphiQL under the hood but is meant as a more powerful GraphQL IDE enabling better (local) development workflows. Compared to GraphiQL, the GraphQL Playground ships with the following additional features: + +* Interactive, multi-column schema documentation +* Automatic schema reloading +* Support for GraphQL Subscriptions +* Query history +* Configuration of HTTP headers +* Tabs + +See the following question for more additonal features. + +### What's the difference between the desktop app and the web version? + +The desktop app is the same as the web version but includes these additional features: + +* Support for [graphql-config](https://github.com/graphcool/graphql-config) enabling features like multi-environment setups. +* Double click on `*.graphql` files. + +### How does GraphQL Bin work? + +You can easily share your Playgrounds with others by clicking on the "Share" button and sharing the generated link. You can think about GraphQL Bin like Pastebin for your GraphQL queries including the context (endpoint, HTTP headers, open tabs etc). + +![](https://imgur.com/H1n64lL.png) + +> You can also find the announcement blog post [here](https://blog.graph.cool/introducing-graphql-playground-f1e0a018f05d). + +## Usage + +### Properties + +All interfaces, the React component `` and all middlewares expose the same set of options: + ++ `properties` + + `endpoint` [`string`] - the GraphQL endpoint url. + + `subscriptionEndpoint` [`string`] - the GraphQL subscriptions endpoint url. + + `setTitle` [`boolean`] - reflect the current endpoint in the page title + +### As React Component + +#### Install + +```sh +yarn add graphql-playground +``` + +#### Use + +GraphQL Playground provides a React component responsible for rendering the UI and Session management. +There are **3 dependencies** needed in order to run the `graphql-playground` React component. + +1. _Open Sans_ and _Source Code Pro_ fonts +1. Including `graphql-playground/playground.css` +1. Rendering the `` component + +The GraphQL Playground requires **React 16**. + +Including Fonts (`1.`) + +```html + +``` + +Including stylesheet and the component (`2., 3.`) + +```js +import React from 'react' +import ReactDOM from 'react-dom' +import Playground from 'graphql-playground' +import 'graphql-playground/playground.css' + +ReactDOM.render(, document.body) +``` + +### As Server Middleware + +#### Install + +```sh +# Pick the one that matches your server framework +yarn add graphql-playground-middleware-express # for Express or Connect +yarn add graphql-playground-middleware-hapi +yarn add graphql-playground-middleware-koa +yarn add graphql-playground-middleware-lambda +``` + +#### Usage with example + +We have a full example for each of the frameworks below: + +- **Express:** See [packages/graphql-playground-middleware-express/examples/basic](https://github.com/graphcool/graphql-playground/tree/master/packages/graphql-playground-middleware-express/examples/basic) + +- **Hapi:** See [packages/graphql-playground-middleware/examples/hapi](https://github.com/graphcool/graphql-playground/tree/master/packages/graphql-playground-middleware/examples/hapi) + +- **Koa:** See [packages/graphql-playground-middleware/examples/koa](https://github.com/graphcool/graphql-playground/tree/master/packages/graphql-playground-middleware/examples/koa) + +- **Lambda (as serverless handler):** See [serverless-graphql-apollo](https://github.com/serverless/serverless-graphql-apollo) or a quick example below. + +### As serverless handler + +#### Install + +```sh +yarn add graphql-playground-middleware-lambda +``` + +#### Usage + +`handler.js` + +```js +import lambdaPlayground from 'graphql-playground-middleware-lambda' +// or using require() +// const lambdaPlayground = require('graphql-playground-middleware-lambda').default + +exports.graphqlHandler = function graphqlHandler(event, context, callback) { + function callbackFilter(error, output) { + // eslint-disable-next-line no-param-reassign + output.headers['Access-Control-Allow-Origin'] = '*' + callback(error, output) + } + + const handler = graphqlLambda({ schema: myGraphQLSchema }) + return handler(event, context, callbackFilter) +} + +exports.playgroundHandler = lambdaPlayground({ + endpoint: '/dev/graphql', +}) +``` + +`serverless.yml` + +```yaml +functions: + graphql: + handler: handler.graphqlHandler + events: + - http: + path: graphql + method: post + cors: true + playground: + handler: handler.playgroundHandler + events: + - http: + path: playground + method: get + cors: true +``` diff --git a/docs/1.1/06-GraphQL-Ecosystem/04-GraphQL-CLI/01-Overview.md b/docs/1.1/06-GraphQL-Ecosystem/04-GraphQL-CLI/01-Overview.md new file mode 100644 index 0000000000..9b0175cf0a --- /dev/null +++ b/docs/1.1/06-GraphQL-Ecosystem/04-GraphQL-CLI/01-Overview.md @@ -0,0 +1,51 @@ +--- +alias: quaidah9pj +description: GraphQL CLI is a command line tool for common GraphQL development workflows. +--- + +# graphql-cli + +📟 [`graphql-cli`](https://github.com/graphql-cli/graphql-cli) is a command line tool for common GraphQL development workflows. + +## Install + +You can simply install the CLI using `npm` or `yarn` by running the following command. This will add the `graphql` (and shorter `gql`) binary to your path. + +```sh +npm install -g graphql-cli +``` + + +## Usage +``` +Usage: graphql [command] + +Commands: + graphql create [directory] Bootstrap a new GraphQL project + graphql add-endpoint Add new endpoint to .graphqlconfig + graphql add-project Add new project to .graphqlconfig + graphql get-schema Download schema from endpoint + graphql schema-status Show source & timestamp of local schema + graphql ping Ping GraphQL endpoint + graphql query Run query/mutation + graphql diff Show a diff between two schemas + graphql playground Open interactive GraphQL Playground + graphql lint Check schema for linting errors + graphql prepare Bundle schemas and generate bindings + graphql codegen [--target] [--output] Generates apollo-codegen + code/annotations from your + .graphqlconfig + +Options: + --dotenv Path to .env file [string] + -p, --project Project name [string] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] + +Examples: + graphql init Interactively setup .graphqlconfig file + graphql get-schema -e dev Update local schema to match "dev" endpoint + graphql diff -e dev -t prod Show schema diff between "dev" and "prod" + endpoints + +``` diff --git a/docs/1.1/06-GraphQL-Ecosystem/05-GraphQL-Config/01-Overview.md b/docs/1.1/06-GraphQL-Ecosystem/05-GraphQL-Config/01-Overview.md new file mode 100644 index 0000000000..eda9447eb9 --- /dev/null +++ b/docs/1.1/06-GraphQL-Ecosystem/05-GraphQL-Config/01-Overview.md @@ -0,0 +1,123 @@ +--- +alias: quaidah9pi +description: GraphQL Config is the easiest way to configure a development environment with a GraphQL schema (supported by most tools, editors & IDEs). +--- + +# graphql-config + +[`graphql-config`](https://github.com/graphcool/graphql-config) is the easiest way to configure your development environment with your GraphQL schema (supported by most tools, editors & IDEs) + +## How it works + +This project aims to be provide a unifying configuration file format to configure your GraphQL schema in your development environment. + +Additional to the format specification, it provides the [`graphql-config`](#graphql-config-api) library, which is used by [all supported tools and editor plugins](#supported-by). The library reads your provided configuration and passes the actual GraphQL schema along to the tool which called it. + +## Usage + +Install [`graphql-cli`](https://github.com/graphcool/graphql-cli) and run `graphql init`. Answer a few simple questions and you are set up! + +You can either configure your GraphQL endpoint via a configuration file `.graphqlconfig` +(or `.graphqlconfig.yaml`) which should be put into the root of your project + +### Simplest use case + +The simplest config specifies only `schemaPath` which is path to the file with introspection +results or corresponding SDL document + +```json +{ + "schemaPath": "schema.graphql" +} +``` + +or + +```json +{ + "schemaPath": "schema.json" +} +``` + +### Specifying includes/excludes files + +You can specify which files are included/excluded using the corresponding options: + +```json +{ + "schemaPath": "schema.graphql", + "includes": ["*.graphql"], + "excludes": ["temp/**"] +} +``` + +> Note: `excludes` and `includes` fields are globs that should match filename. +> So, just `temp` or `temp/` won't match all files inside the directory. +> That's why the example uses `temp/**` + +#### Specifying endpoint info + +You may specify your endpoints info in `.graphqlconfig` which may be used by some tools. +The simplest case: + +```json +{ + "schemaPath": "schema.graphql", + "extensions": { + "endpoints": { + "dev": "https://example.com/graphql" + } + } +} +``` + +In case you need provide additional information, for example headers to authenticate your GraphQL endpoint or +an endpoint for subscription, you can use expanded version: + +```json +{ + "schemaPath": "schema.graphql", + "extensions": { + "endpoints": { + "dev": { + "url": "https://example.com/graphql", + "headers": { + "Authorization": "Bearer ${env:AUTH_TOKEN_ENV}" + }, + "subscription": { + "url": "ws://example.com/graphql", + "connectionParams": { + "Token": "${env:YOUR_APP_TOKEN}" + } + } + } + } + } +} +``` + +> Note: do not save secure information in .graphqlconfig file. Use [Environment variables](https://github.com/graphcool/graphql-config/blob/master/specification.md#referencing-environment-variables) for that like in the example above. + +In case if you have multiple endpoints use the following syntax: + +```json +{ + "schemaPath": "schema.graphql", + "extensions": { + "endpoints": { + "prod": { + "url": "https://your-app.com/graphql", + "subscription": { + "url": "wss://subscriptions.graph.cool/v1/instagram" + } + }, + "dev": { + "url": "http://localhost:3000/graphql", + "subscription": { + "url": "ws://localhost:3001" + } + } + } + } +} +``` diff --git a/docs/1.1/06-GraphQL-Ecosystem/06-GraphQL-Request/01-Overview.md b/docs/1.1/06-GraphQL-Ecosystem/06-GraphQL-Request/01-Overview.md new file mode 100644 index 0000000000..af929bd6a4 --- /dev/null +++ b/docs/1.1/06-GraphQL-Ecosystem/06-GraphQL-Request/01-Overview.md @@ -0,0 +1,198 @@ +--- +alias: chinohsh2j +description: GraphQL Request is a minimal GraphQL client supporting Node and browsers for scripts or simple apps. +--- + +# graphql-request + +📡 [`graphql-request`](https://github.com/graphcool/graphql-request) is a minimal GraphQL client supporting Node and browsers for scripts or simple apps. + +## Features + +* Most **simple and lightweight** GraphQL client +* Promise-based API (works with `async` / `await`) +* Typescript support (Flow coming soon) + +## Install + +```sh +npm install graphql-request +``` + +## Quickstart + +Send a GraphQL query with a single line of code. ▶️ [Try it out](https://runkit.com/593130bdfad7120012472003/593130bdfad7120012472004). + +```js +import { request } from 'graphql-request' + +const query = `{ + Movie(title: "Inception") { + releaseDate + actors { + name + } + } +}` + +request('https://api.graph.cool/simple/v1/movies', query).then(data => console.log(data)) +``` + +## Usage + +```js +import { request, GraphQLClient } from 'graphql-request' + +// Run GraphQL queries/mutations using a static function +request(endpoint, query, variables).then(data => console.log(data)) + +// ... or create a GraphQL client instance to send requests +const client = new GraphQLClient(endpoint, { headers: {} }) +client.request(query, variables).then(data => console.log(data)) +``` + +## Examples + +### Authentication via HTTP header + +```js +import { GraphQLClient } from 'graphql-request' + +const client = new GraphQLClient('my-endpoint', { + headers: { + Authorization: 'Bearer my-jwt-token', + }, +}) + +const query = `{ + Movie(title: "Inception") { + releaseDate + actors { + name + } + } +}` + +client.request(query).then(data => console.log(data)) +``` + +### Passing more options to fetch + +```js +import { GraphQLClient } from 'graphql-request' + +const client = new GraphQLClient('my-endpoint', { + credentials: 'include', + mode: 'cors' +}) + +const query = `{ + Movie(title: "Inception") { + releaseDate + actors { + name + } + } +}` + +client.request(query).then(data => console.log(data)) +``` + +### Using variables + +```js +import { request } from 'graphql-request' + +const query = `query getMovie($title: String!) { + Movie(title: $title) { + releaseDate + actors { + name + } + } +}` + +const variables = { + title: 'Inception', +} + +request('my-endpoint', query, variables).then(data => console.log(data)) +``` + +### Error handling + +```js +import { request } from 'graphql-request' + +const wrongQuery = `{ + some random stuff +}` + +request('my-endpoint', query) + .then(data => console.log(data)) + .catch(err => { + console.log(err.response.errors) // GraphQL response errors + console.log(err.response.data) // Response data if available + }) +``` + +### Using `require` instead of `import` + +```js +const { request } = require('graphql-request') + +const query = `{ + Movie(title: "Inception") { + releaseDate + actors { + name + } + } +}` + +request('my-endpoint', query).then(data => console.log(data)) +``` + +### Cookie support for `node` + +```sh +npm install fetch-cookie/node-fetch +``` + +```js +import { GraphQLClient } from 'graphql-request' + +// use this instead for cookie support +global['fetch'] = require('fetch-cookie/node-fetch')(require('node-fetch')) + +const client = new GraphQLClient('my-endpoint') + +const query = `{ + Movie(title: "Inception") { + releaseDate + actors { + name + } + } +}` + +client.request(query).then(data => console.log(data)) +``` + +### More examples coming soon... + +* Fragments +* Using [`graphql-tag`](https://github.com/apollographql/graphql-tag) +* Typed Typescript return values + +## FAQ + +### What's the difference between `graphql-request`, Apollo and Relay? + +`graphql-request` is the most minimal and simplest to use GraphQL client. It's perfect for small scripts or simple apps. + +Compared to GraphQL clients like Apollo or Relay, `graphql-request` doesn't have a built-in cache and has no integrations for frontend frameworks. The goal is to keep the package and API as minimal as possible. + +### So what about Lokka? + +Lokka is great but it still requires [a lot of setup code](https://github.com/kadirahq/lokka-transport-http) to be able to send a simple GraphQL query. `graphql-request` does less work compared to Lokka but is a lot simpler to use. diff --git a/docs/1.1/06-GraphQL-Ecosystem/07-GraphQL-Import/01-Overview.md b/docs/1.1/06-GraphQL-Ecosystem/07-GraphQL-Import/01-Overview.md new file mode 100644 index 0000000000..c0978ecfff --- /dev/null +++ b/docs/1.1/06-GraphQL-Ecosystem/07-GraphQL-Import/01-Overview.md @@ -0,0 +1,88 @@ +--- +alias: quaidah9pn +description: GraphQL Import is a package that allows importing & exporting schema definitions in GraphQL SDL (also refered to as GraphQL modules). +--- + +# graphql-import + +[`graphql-import`](https://github.com/graphcool/graphql-import) is a package that allows importing & exporting schema definitions in GraphQL SDL (also refered to as GraphQL modules). + +## Install + +```sh +yarn add graphql-import +``` + +## Usage + +```ts +import { importSchema } from 'graphql-import' +import { makeExecutableSchema } from 'graphql-tools' + +const typeDefs = importSchema('schema.graphql') +const resolvers = {} + +const schema = makeExecutableSchema({ typeDefs, resolvers }) +``` + +## Example + +Assume the following directory structure: + +``` +. +├── a.graphql +├── b.graphql +└── c.graphql +``` + +`a.graphql` + +```graphql +# import B from "b.graphql" + +type A { + # test 1 + first: String + second: Float + b: B +} +``` + +`b.graphql` + +```graphql +# import C from 'c.graphql' + +type B { + c: C + hello: String! +} +``` + +`c.graphql` + +```graphql +type C { + id: ID! +} +``` + +Running `console.log(importSchema('a.graphql'))` procudes the following output: + +```graphql +type A { + first: String + second: Float + b: B +} + +type B { + c: C + hello: String! +} + +type C { + id: ID! +} +```