docs: graphql
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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) |
|
||||
|
||||
@@ -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
|
||||
@@ -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
93
docs/GraphQL/overview.mdx
Normal 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).
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
```
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Configure Email
|
||||
label: Configure Email
|
||||
order: 30
|
||||
---
|
||||
|
||||
TODO: Configure SendGrid or similar
|
||||
@@ -10,3 +10,7 @@ order: 20
|
||||
- Max Depth
|
||||
- CSRF
|
||||
- CORS
|
||||
|
||||
### Limiting GraphQL Complexity
|
||||
|
||||
^^ Keep this header here
|
||||
|
||||
Reference in New Issue
Block a user