docs: graphql

This commit is contained in:
James
2021-01-02 19:25:00 -05:00
parent f1c5cfe1a5
commit d76c1f862c
10 changed files with 165 additions and 285 deletions

View File

@@ -34,6 +34,10 @@ Technically, both of these options will work for third-party integrations but th
To enable API keys on a collection, set the `useAPIKey` auth option to `true`. From there, a new interface will appear in the Admin panel for each document within the collection that allows you to generate an API key for each user in the Collection.
<Banner type="success">
User API keys are encrypted within the database, meaning that if your database is compromised, your API keys will not be.
</Banner>
##### Authenticating via API Key
To utilize your API key while interacting with the REST or GraphQL API, add the `Authorization` header.

View File

@@ -107,7 +107,7 @@ For more about how to automatically include cookies in requests from your app to
### CSRF Protection
CSRF (cross-site request forgery) attacks are common and dangerous. By using an HTTP-only cookie, Payload removes any XSS vulnerabilities, however, CSRF attacks can still be possible.
CSRF (cross-site request forgery) attacks are common and dangerous. By using an HTTP-only cookie, Payload removes many XSS vulnerabilities, however, CSRF attacks can still be possible.
For example, let's say you have a very popular app running at coolsite.com. This app allows users to manage finances and send / receive money. As Payload is using HTTP-only cookies, that means that browsers automatically will include cookies when sending requests to your domain - no matter what page created the request.

View File

@@ -20,7 +20,7 @@ Payload is a *config-based*, code-first CMS and application framework. The Paylo
| `globals` | An array of all Globals that Payload will manage. For more on Globals and their configs, [click here](/docs/configuration/globals). |
| `admin` | Base Payload admin configuration. Specify custom components, control metadata, set the Admin user collection, and [more](/docs/admin/overview#options). |
| `localization` | Opt-in and control how Payload handles the translation of your content into multiple locales. [More](/docs/configuration/localization) |
| `graphQL` | Manage GraphQL-specific functionality here. Define your own queries and mutations, manage query complexity limits, and [more](/docs/graphql/config). |
| `graphQL` | Manage GraphQL-specific functionality here. Define your own queries and mutations, manage query complexity limits, and [more](/docs/graphql/overview#config). |
| `cookiePrefix` | A string that will be prefixed to all cookies that Payload sets. |
| `cors` | Either a whitelist array of URLS to allow CORS requests from, or a wildcard string (`'*'`) to accept incoming requests from any domain. |
| `csrf` | A whitelist array of URLs to allow Payload cookies to be accepted from as a form of CSRF protection. [More](/docs/authentication/overview#csrf-protection) |

View File

@@ -1,11 +0,0 @@
---
title: GraphQL Overview
label: Overview
order: 10
---
Go over GraphQL configuration options.
- Naming conventions
- List of all queries and mutations w/ examples
- Context

View File

@@ -4,4 +4,65 @@ label: Custom Queries and Mutations
order: 20
---
Talk about how to add your own queries and mutations.
You can add your own GraphQL queries and mutations to Payload, making use of all the types that Payload has defined for you.
To do so, add your queries and mutations to the main Payload config as follows:
| Config Path | Description |
| -------------------- | -------------|
| `graphQL.queries` | Function that returns an object containing keys to custom GraphQL queries |
| `graphQL.mutations` | Function that returns an object containing keys to custom GraphQL mutations |
The above properties each receive a function that is defined with the following arguments:
**`GraphQL`**
This is Payload's GraphQL dependency. You should not install your own copy of GraphQL as a dependency due to underlying restrictions based on how GraphQL works. Instead, you can use the Payload-provided copy via this argument.
**`payload`**
This is a copy of the currently running Payload instance, which provides you with existing GraphQL types for all of your Collections and Globals - among other things.
##### Return value
Both `graphQL.queries` and `graphQL.mutations` functions should return an object with properties equal to your newly written GraphQL queries and mutations.
### Example
`payload.config.js`:
```js
import { buildConfig } from 'payload/config';
import myCustomQueryResolver from './graphQL/resolvers/myCustomQueryResolver';
export default buildConfig({
serverURL: 'http://localhost:3000',
graphQL: {
// highlight-start
queries: (GraphQL, payload) => {
return {
MyCustomQuery: {
type: new GraphQL.GraphQLObjectType({
name: 'MyCustomQuery',
fields: {
text: {
type: GraphQL.GraphQLString,
},
someNumberField: {
type: GraphQL.GraphQLFloat,
},
},
args: {
argNameHere: {
type: new GraphQL.GraphQLNonNull(GraphQLString),
}
},
resolve: myCustomQueryResolver,
})
}
}
}
// highlight-end
}
})
```

93
docs/GraphQL/overview.mdx Normal file
View File

@@ -0,0 +1,93 @@
---
title: GraphQL Overview
label: Overview
order: 10
---
In addition to its REST and Local APIs, Payload ships with a fully featured and extensible GraphQL API.
By default, the GraphQL API is exposed via `/api/graphql`, but you can customize this URL via specifying your `routes` within the main Payload config.
The labels you provide for your Collections and Globals are used to format the GraphQL types that are created to correspond to your config. Special characters and spaces are removed.
### Collections
Everything that can be done to a Collection via the REST or Local API can be done with GraphQL (outside of uploading files, which is REST-only). If you have a collection as follows:
```js
const Post = {
slug: 'public-users',
auth: true, // Auth is enabled
labels: {
singular: 'Public User',
plural: 'Public Users',
},
fields: [
...
],
}
```
**Payload will automatically open up the following queries:**
| Query Name | Operation |
| ---------------------- | -------------|
| **`PublicUser`** | `findByID` |
| **`PublicUsers`** | `find` |
| **`mePublicUser`** | `me` auth operation |
**And the following mutations:**
| Query Name | Operation |
| ------------------------------ | -------------|
| **`createPublicUser`** | `create` |
| **`updatePublicUser`** | `update` |
| **`deletePublicUser`** | `delete` |
| **`forgotPasswordPublicUser`** | `forgotPassword` auth operation |
| **`resetPasswordPublicUser`** | `resetPassword` auth operation |
| **`unlockPublicUser`** | `unlock` auth operation |
| **`verifyPublicUser`** | `verify` auth operation |
| **`loginPublicUser`** | `login` auth operation |
| **`logoutPublicUser`** | `logout` auth operation |
| **`refreshTokenPublicUser`** | `refresh` auth operation |
### Globals
Globals are also fully supported. For example:
```js
const Header = {
slug: 'header',
label: 'Header',
fields: [
...
],
}
```
**Payload will open the following query:**
| Query Name | Operation |
| ---------------------- | -------------|
| **`Header`** | `findOne` |
**And the following mutation:**
| Query Name | Operation |
| ---------------------- | -------------|
| **`updateHeader`** | `update` |
### GraphQL Playground
GraphQL Playground is enabled by default for development purposes, but disabled in production. You can enable it in production by passing `graphQL.disablePlaygroundInProduction` a `false` setting in the main Payload config.
You can even log in using the `login` mutation to use the Playground as an authenticated user.
<Banner type="success">
<strong>Tip:</strong><br/>
To see more regarding how the above queries and mutations are used, visit your GraphQL playground (by default at <a href="http://localhost:3000/api/graphql-playground">(http://localhost:3000/api/graphql-playground)</a> while your server is running. There, you can use the "Schema" and "Docs" buttons on the right to see a ton of detail about how GraphQL operates within Payload.
</Banner>
### Query complexity limits
Payload comes with a built-in query complexity limiter to prevent bad people from trying to slow down your server by running massive queries. To learn more, [click here](/docs/production/security#graphql-complexity).

View File

@@ -1,11 +0,0 @@
---
title: Using the GraphQL Playground
label: Playground
order: 30
---
Talk about the GraphQL Playground
Talk about how to enable / disable it in production
Talk about how to log in

View File

@@ -1,253 +0,0 @@
---
title: Blog API From Scratch
label: Blog API
order: 20
---
In this guide, we will be creating a Blog API from scratch.
Prerequisites:
- Node
- npm or yarn
- MongoDB server
## Initial Setup
Let's get started by creating a project in a blank directory
```sh
yarn init -y
```
We then will install Payload and Express
```sh
yarn add payload express
```
### Server
Create a file named `server.js` in the root folder with the following contents
```js
const express = require('express');
const app = express();
app.listen(3000, async () => {
console.log('Express is now listening for incoming connections on port 3000.');
});
```
This is a basic Express application. Now let's pull in Payload and fill in the `init` parameters. `secret` and `mongoURL` can be changed as needed.
```js
const express = require('express');
const payload = require('payload'); // highlight-line
const app = express();
// highlight-start
payload.init({
secret: 'SECRET_KEY',
mongoURL: 'mongodb://localhost/payload-blog',
express: app,
})
// highlight-end
app.listen(3000, async () => {
console.log('Express is now listening for incoming connections on port 3000.');
});
```
### Payload Configuration
Next, let's get some basics put into our `payload.config.js` file
```js
module.exports = {
serverURL: 'http://localhost:3000',
collections: [],
}
```
#### Collections
We'll need a few different collections for our blog:
- Posts
- Categories
- Tags
The Posts will have the ability to have a single category and multiple tags
Let's create a `collections` directory and create a `.js` file for each
```js:title=Posts.js
module.exports = {
slug: 'posts',
labels: {
singular: 'Post',
plural: 'Posts',
},
admin: {
useAsTitle: 'title',
},
fields: [
{
name: 'title',
label: 'Title',
type: 'text'
},
{
name: 'content',
label: 'Content',
type: 'textarea',
},
{
name: 'category',
label: 'Category',
type: 'relationship',
relationTo: 'categories', // Categories Slug // highlight-line
},
{
name: 'tags',
label: 'Tags',
type: 'relationship',
relationTo: 'tags', // Tags Slug // highlight-line
hasMany: true, // Allow multiple tags per post
},
]
};
```
```js:title=Categories.js
module.exports = {
slug: 'categories',
labels: {
singular: 'Category',
plural: 'Categories',
},
admin: {
useAsTitle: 'name',
},
fields: [
{
name: 'name',
label: 'Name',
type: 'text',
},
],
};
```
```js:title=Tags.js
module.exports = {
slug: 'tags',
labels: {
singular: 'Tag',
plural: 'Tags',
},
admin: {
useAsTitle: 'name',
},
fields: [
{
name: 'name',
label: 'Name',
type: 'text',
},
],
};
```
Once these are created, we can pull them into the `collections` array in our `payload.config.js`
```js:title=payload.config.js
const Admins = require('./collections/Admins');
// highlight-start
const Posts = require('./collections/Posts');
const Categories = require('./collections/Categories');
const Tags = require('./collections/Tags');
// highlight-end
module.exports = {
serverURL: 'http://localhost:3000',
admin: {
user: 'admins',
},
collections: [
Admins,
// highlight-start
Posts,
Categories,
Tags
// highlight-end
],
}
```
### Create Content
**TODO: Should a guide like this use the Admin interface or `curl`?**
Navigate to the admin interface at `http://localhost:3000/admin` and create your first user.
Then create some Categories, Tags, and a Post.
Let's use `curl` to quickly create some data. The following commands will create 2 tags and 1 category.
```sh
curl -H "Content-Type: application/json" -X POST -d '{"name": "JavaScript"}' http://localhost:3000/api/tags
curl -H "Content-Type: application/json" -X POST -d '{"name": "TypeScript"}' http://localhost:3000/api/tags
curl -H "Content-Type: application/json" -X POST -d '{"name": "Code"}' http://localhost:3000/api/categories
```
We'll then make a request to create a Post, this will inclue a relationship to the category and tags created previously.
TODO: Somehow retrieve tag and category IDs then include them in a request to create a Post
Once complete, navigate to `http://localhost:3000/api/posts`, and you should see something similar to the following:
```js
{
"docs": [
{
"tags": [
{
"name": "TypeScript",
"createdAt": "2020-11-13T11:48:05.993Z",
"updatedAt": "2020-11-13T11:48:05.993Z",
"id": "5fae72758315da656fb3a8f0"
},
{
"name": "JavaScript",
"createdAt": "2020-11-13T11:48:00.064Z",
"updatedAt": "2020-11-13T11:48:00.064Z",
"id": "5fae72708315da656fb3a8ef"
}
],
"title": "My Title",
"content": "This is some content",
"category": {
"name": "Code",
"createdAt": "2020-11-13T11:48:10.351Z",
"updatedAt": "2020-11-13T11:48:36.358Z",
"id": "5fae727a8315da656fb3a8f1"
},
"createdAt": "2020-11-13T11:50:14.312Z",
"updatedAt": "2020-11-13T11:50:14.312Z",
"id": "5fae72f68e314b67609e05d1"
}
],
"totalDocs": 1,
"limit": 10,
"totalPages": 1,
"page": 1,
"pagingCounter": 1,
"hasPrevPage": false,
"hasNextPage": false,
"prevPage": null,
"nextPage": null
}
```

View File

@@ -1,7 +0,0 @@
---
title: Configure Email
label: Configure Email
order: 30
---
TODO: Configure SendGrid or similar

View File

@@ -10,3 +10,7 @@ order: 20
- Max Depth
- CSRF
- CORS
### Limiting GraphQL Complexity
^^ Keep this header here