Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor Documentation Tweaks #904

Merged
merged 6 commits into from
Nov 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 30 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

[gqlgen](https://github.com/99designs/gqlgen) is a Go library for building GraphQL servers without any fuss. gqlgen is:

- **Schema first** — Define your API using the GraphQL [Schema Definition Language](http://graphql.org/learn/schema/).
- **Type safe** — You should never see `map[string]interface{}` here.
- **Codegen** — Let us generate the boring bits, so you can build your app quickly.
- **Schema first** — Define your API using the GraphQL [Schema Definition Language](http://graphql.org/learn/schema/).
- **Type safe** — You should never see `map[string]interface{}` here.
- **Codegen** — Let us generate the boring bits, so you can build your app quickly.

[Feature Comparison](https://gqlgen.com/feature-comparison/)

Expand All @@ -29,32 +29,40 @@ Read our [Contribution Guidelines](https://github.com/99designs/gqlgen/blob/mast
### How do I prevent fetching child objects that might not be used?

When you have nested or recursive schema like this:

```graphql
type User {
id: ID!
name: String!
friends: [User!]!
id: ID!
name: String!
friends: [User!]!
}
```

You need to tell gqlgen that we should only fetch friends if the user requested it. There are two ways to do this.

1. Write the model yourself and leave off friends.
#### Custom Models

Write a custom model that omits the Friends model:

```go
type User struct {
Id int
Name string
ID int
Name string
}
```

And reference the model in `gqlgen.yml`:

```yaml
# gqlgen.yml
models:
User:
model: github.com/you/pkg/model.User # go import path to the User struct above
```
2. Keep using the generated model, and mark the field as requiring a resolver explicitly
#### Explicit Resolvers
If you want to Keep using the generated model: mark the field as requiring a resolver explicitly in `gqlgen.yml`:

```yaml
# gqlgen.yml
Expand All @@ -66,33 +74,36 @@ models:
```

After doing either of the above and running generate we will need to provide a resolver for friends:

```go
func (r *userResolver) Friends(ctx context.Context, obj *User) ([]*User, error) {
// select * from user where friendid = obj.ID
return friends, nil
// select * from user where friendid = obj.ID
return friends, nil
}
```

### IDs are strings but I like ints, why cant I have ints?

You can by remapping it in config:

```yaml
models:
ID: # The GraphQL type ID is backed by
model:
- github.com/99designs/gqlgen/graphql.IntID # An go integer
- github.com/99designs/gqlgen/graphql.ID # or a go string
- github.com/99designs/gqlgen/graphql.IntID # An go integer
- github.com/99designs/gqlgen/graphql.ID # or a go string
```

This means gqlgen will be able to automatically bind to strings or ints for models you have written yourself, but the
first model in this list is used as the default type and it will always be used when:
- generating models based on schema
- as arguments in resolvers

- Generating models based on schema
- As arguments in resolvers

There isnt any way around this, gqlgen has no way to know what you want in a given context.

## Other Resources

- [Christopher Biscardi @ Gophercon UK 2018](https://youtu.be/FdURVezcdcw)
- [Introducing gqlgen: a GraphQL Server Generator for Go](https://99designs.com.au/blog/engineering/gqlgen-a-graphql-server-generator-for-go/)
- [Dive into GraphQL by Iván Corrales Solera](https://medium.com/@ivan.corrales.solera/dive-into-graphql-9bfedf22e1a)
- [Christopher Biscardi @ Gophercon UK 2018](https://youtu.be/FdURVezcdcw)
- [Introducing gqlgen: a GraphQL Server Generator for Go](https://99designs.com.au/blog/engineering/gqlgen-a-graphql-server-generator-for-go/)
- [Dive into GraphQL by Iván Corrales Solera](https://medium.com/@ivan.corrales.solera/dive-into-graphql-9bfedf22e1a)
12 changes: 7 additions & 5 deletions docs/content/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ weight: -5
gqlgen can be configured using a `gqlgen.yml` file, by default it will be loaded from the current directory, or any parent directory.

Example:

```yml
# You can pass a single schema file
schema: schema.graphql
Expand Down Expand Up @@ -44,7 +45,7 @@ resolver:
# Optional, turns on binding to field names by tag provided
struct_tag: json

# Optional, set to true if you prefer []*Thing over []Thing
# Optional, set to true if you prefer []Thing over []*Thing
omit_slice_element_pointers: false

# Instead of listing out every model like below, you can automatically bind to any matching types
Expand Down Expand Up @@ -79,6 +80,7 @@ Everything has defaults, so add things as you need.
gqlgen ships with some builtin directives that make it a little easier to manage wiring.
To start using them you first need to define them:
```graphql
directive @goModel(model: String, models: [String!]) on OBJECT
| INPUT_OBJECT
Expand All @@ -90,7 +92,7 @@ directive @goModel(model: String, models: [String!]) on OBJECT
directive @goField(forceResolver: Boolean, name: String) on INPUT_FIELD_DEFINITION
| FIELD_DEFINITION
```
> Here be dragons
>
> gqlgen doesnt currently support user-configurable directives for SCALAR, ENUM, INTERFACE or UNION. This only works
Expand All @@ -99,8 +101,8 @@ directive @goField(forceResolver: Boolean, name: String) on INPUT_FIELD_DEFINITI
Now you can use these directives when defining types in your schema:
```graphql
type User @goModel(model:"github.com/my/app/models.User") {
id: ID! @goField(name:"todoId")
name: String! @goField(forceResolver: true)
type User @goModel(model: "github.com/my/app/models.User") {
id: ID! @goField(name: "todoId")
name: String! @goField(forceResolver: true)
}
```
2 changes: 1 addition & 1 deletion docs/content/reference/dataloaders.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,4 @@ The generated UserLoader has a few other useful methods on it:
- `LoadAll(keys)`: If you know up front you want a bunch users
- `Prime(key, user)`: Used to sync state between similar loaders (usersById, usersByNote)

You can see the full working example [here](https://github.com/vektah/gqlgen-tutorials/tree/master/dataloader)
You can see the full working example [here](https://github.com/vektah/gqlgen-tutorials/tree/master/dataloader).
39 changes: 23 additions & 16 deletions docs/content/reference/file-upload.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
---
title: 'File Upload'
title: "File Upload"
description: How to upload files.
linkTitle: File Upload
menu: { main: { parent: 'reference' } }
menu: { main: { parent: "reference" } }
---

Graphql server has an already built-in Upload scalar to upload files using a multipart request. \
It implements the following spec https://github.com/jaydenseric/graphql-multipart-request-spec,
that defines an interoperable multipart form field structure for GraphQL requests, used by
various file upload client implementations.
It implements the following spec https://github.com/jaydenseric/graphql-multipart-request-spec,
that defines an interoperable multipart form field structure for GraphQL requests, used by
various file upload client implementations.

To use it you need to add the Upload scalar in your schema, and it will automatically add the
marshalling behaviour to Go types.

# Configuration

There are two specific options that can be configured for uploading files:

- uploadMaxSize \
This option specifies the maximum number of bytes used to parse a request body as multipart/form-data.
This option specifies the maximum number of bytes used to parse a request body as multipart/form-data.
- uploadMaxMemory \
This option specifies the maximum number of bytes used to parse a request body as
multipart/form-data in memory, with the remainder stored on disk in temporary files.
This option specifies the maximum number of bytes used to parse a request body as
multipart/form-data in memory, with the remainder stored on disk in temporary files.

# Examples

## Single file upload

For this use case, the schema could look like this.

```graphql
Expand All @@ -41,7 +44,8 @@ type Mutation {
}
```

cURL can be used the make a query as follows:
cURL can be used the make a query as follows:

```
curl localhost:4000/graphql \
-F operations='{ "query": "mutation ($file: Upload!) { singleUpload(file: $file) { id } }", "variables": { "file": null } }' \
Expand All @@ -50,7 +54,8 @@ curl localhost:4000/graphql \
```
That invokes the following operation:
```
```javascript
{
query: `
mutation($file: Upload!) {
Expand All @@ -66,8 +71,9 @@ That invokes the following operation:
```

## Multiple file upload

For this use case, the schema could look like this.

```graphql
"The `Upload` scalar type represents a multipart file upload."
scalar Upload
Expand Down Expand Up @@ -97,9 +103,9 @@ type Mutation {

```

cURL can be used the make a query as follows:
cURL can be used the make a query as follows:

```
```bash
curl localhost:4000/query \
-F operations='{ "query": "mutation($req: [UploadFile!]!) { multipleUpload(req: $req) { id, name, content } }", "variables": { "req": [ { "id": 1, "file": null }, { "id": 2, "file": null } ] } }' \
-F map='{ "0": ["variables.req.0.file"], "1": ["variables.req.1.file"] }' \
Expand All @@ -108,7 +114,8 @@ curl localhost:4000/query \
```

That invokes the following operation:
```

```javascript
{
query: `
mutation($req: [UploadFile!]!)
Expand All @@ -129,9 +136,9 @@ That invokes the following operation:
id: 2,
File, // c.txt
}
]
]
}
}
```

see the [example/fileupload](https://github.com/99designs/gqlgen/tree/master/example/fileupload) package for more examples.
See the [example/fileupload](https://github.com/99designs/gqlgen/tree/master/example/fileupload) package for more examples.
23 changes: 11 additions & 12 deletions docs/content/reference/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
linkTitle: Plugins
title: How to write plugins for gqlgen
description: Use plugins to customize code generation and integrate with other libraries
menu: { main: { parent: 'reference' } }
menu: { main: { parent: "reference" } }
---

Plugins provide a way to hook into the gqlgen code generation lifecycle. In order to use anything other than the
default plugins you will need to create your own entrypoint:


## Using a plugin

```go
// +build ignore

Expand All @@ -36,7 +36,7 @@ func main() {
}


err = api.Generate(cfg,
err = api.Generate(cfg,
api.AddPlugin(yourplugin.New()), // This is the magic line
)
if err != nil {
Expand All @@ -45,18 +45,17 @@ func main() {
}
}

```
```

## Writing a plugin

There are currently only two hooks:
- MutateConfig: Allows a plugin to mutate the config before codegen starts. This allows plugins to add
custom directives, define types, and implement resolvers. see
[modelgen](https://github.com/99designs/gqlgen/tree/master/plugin/modelgen) for an example
- GenerateCode: Allows a plugin to generate a new output file, see
[stubgen](https://github.com/99designs/gqlgen/tree/master/plugin/stubgen) for an example

Take a look at [plugin.go](https://github.com/99designs/gqlgen/blob/master/plugin/plugin.go) for the full list of
available hooks. These are likely to change with each release.

- MutateConfig: Allows a plugin to mutate the config before codegen starts. This allows plugins to add
custom directives, define types, and implement resolvers. see
[modelgen](https://github.com/99designs/gqlgen/tree/master/plugin/modelgen) for an example
- GenerateCode: Allows a plugin to generate a new output file, see
[stubgen](https://github.com/99designs/gqlgen/tree/master/plugin/stubgen) for an example

Take a look at [plugin.go](https://github.com/99designs/gqlgen/blob/master/plugin/plugin.go) for the full list of
available hooks. These are likely to change with each release.
17 changes: 10 additions & 7 deletions docs/content/reference/scalars.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
linkTitle: Scalars
title: Mapping GraphQL scalar types to Go types
description: Mapping GraphQL scalar types to Go types
menu: { main: { parent: 'reference' } }
menu: { main: { parent: "reference" } }
---

## Built-in helpers

gqlgen ships with three built-in helpers for common custom scalar use-cases, `Time`, `Any`, `Upload` and `Map`. Adding any of these to a schema will automatically add the marshalling behaviour to Go types.
gqlgen ships with three built-in helpers for common custom scalar use-cases, `Time`, `Any`, `Upload` and `Map`. Adding any of these to a schema will automatically add the marshalling behaviour to Go types.

### Time

Expand All @@ -32,13 +32,15 @@ scalar Upload
```

Maps a `Upload` GraphQL scalar to a `graphql.Upload` struct, defined as follows:
```

```go
type Upload struct {
File io.Reader
Filename string
Size int64
}
```

### Any

```graphql
Expand All @@ -47,7 +49,7 @@ scalar Any

Maps an arbitrary GraphQL value to a `interface{}` Go type.

## Custom scalars with user defined types
## Custom scalars with user defined types

For user defined types you can implement the graphql.Marshaler and graphql.Unmarshaler interfaces and they will be called.

Expand Down Expand Up @@ -88,13 +90,13 @@ func (y YesNo) MarshalGQL(w io.Writer) {
```

and then in .gqlgen.yml point to the name without the Marshal|Unmarshal in front:

```yaml
models:
YesNo:
model: github.com/me/mypkg.YesNo
```


## Custom scalars with third party types

Sometimes you cant add methods to a type because its in another repo, part of the standard
Expand Down Expand Up @@ -136,11 +138,12 @@ func UnmarshalMyCustomBooleanScalar(v interface{}) (bool, error) {
}
```

and then in .gqlgen.yml point to the name without the Marshal|Unmarshal in front:
Then in .gqlgen.yml point to the name without the Marshal|Unmarshal in front:

```yaml
models:
MyCustomBooleanScalar:
model: github.com/me/mypkg.MyCustomBooleanScalar
```

see the [example/scalars](https://github.com/99designs/gqlgen/tree/master/example/scalars) package for more examples.
See the [example/scalars](https://github.com/99designs/gqlgen/tree/master/example/scalars) package for more examples.