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

File upload #655

Merged
merged 42 commits into from
May 8, 2019
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
b454621
Add support to upload files.
Feb 26, 2019
9c17ce3
Add file upload
hantonelli Mar 2, 2019
5afb6b4
Add file upload to default schema
hantonelli Mar 3, 2019
10beedb
Remove not required file
hantonelli Mar 3, 2019
a7e95c5
Fix tests. Improve file generation
hantonelli Mar 3, 2019
998f767
Revert changing the stub file
hantonelli Mar 3, 2019
c493d1b
Revert changing to websocket_test
hantonelli Mar 3, 2019
db7a03b
Improve tests and names
hantonelli Mar 3, 2019
3c5f8bb
Improve some examples
hantonelli Mar 10, 2019
493d937
Improve examples
hantonelli Mar 10, 2019
61c1cb9
Improve examples
hantonelli Mar 10, 2019
68446e1
Revert change to websocket_test
hantonelli Mar 10, 2019
2c414ed
Improve and add tests
hantonelli Mar 10, 2019
4d92696
Clean up code and add tests
hantonelli Mar 10, 2019
be8d6d1
Improve test
hantonelli Mar 10, 2019
239bc46
Add comments
hantonelli Mar 10, 2019
3a6f2fb
Improve test code
hantonelli Mar 10, 2019
bd4aeaa
Merge remote-tracking branch 'upstream/master'
hantonelli Mar 31, 2019
bf79bc9
Merge branch 'master' into next
hantonelli Mar 31, 2019
f244442
Fix merge. Remove regexp check.
hantonelli Mar 31, 2019
662dc33
Move Upload to injected if defined in the schema as scalars
hantonelli Mar 31, 2019
fc31836
Improve format, inline const.
hantonelli Mar 31, 2019
849d4b1
Make uploadMaxMemory configurable
hantonelli Mar 31, 2019
425849a
Improve fileupload example readme. Update scalars.md. Add file-upload.md
hantonelli Mar 31, 2019
83cde4b
Fix tests. Improve code format.
hantonelli Mar 31, 2019
73b3a53
Fmt graphql.go
hantonelli Mar 31, 2019
2c1f857
Fix lint errors.
hantonelli Mar 31, 2019
d377039
Fix tests.
hantonelli Mar 31, 2019
2cf7f45
Fix comments (add request size limit, remove useless comments, improv…
hantonelli Apr 13, 2019
da52e81
Extend test and don't close form file.
hantonelli Apr 15, 2019
7ade7c2
Change graphql.Upload File field to FileData.
hantonelli Apr 15, 2019
0306783
Revert "Change graphql.Upload File field to FileData."
hantonelli Apr 18, 2019
f848415
Modify graphql.Upload to use io.ReadCloser. Change the way upload fil…
hantonelli Apr 19, 2019
bb02347
Lint code
hantonelli Apr 19, 2019
b961d34
Remove wrapper that is now not required
hantonelli Apr 19, 2019
43fc53f
Improve variable name
hantonelli Apr 19, 2019
54226cd
Add bytesReader to reuse read byte array
hantonelli May 1, 2019
f30f1c3
Fix fmt
hantonelli May 1, 2019
d9dca64
Improve documentation
hantonelli May 6, 2019
aeccbce
Update test include an example that uses io.Read interface directly
hantonelli May 6, 2019
8a0c34a
Merge branch 'master' into file-upload
vektah May 8, 2019
5d1dea0
run go generate
vektah May 8, 2019
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
7 changes: 4 additions & 3 deletions codegen/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -363,9 +363,10 @@ func (c *Config) InjectBuiltins(s *ast.Schema) {

// These are additional types that are injected if defined in the schema as scalars.
extraBuiltins := TypeMap{
"Time": {Model: StringList{"github.com/99designs/gqlgen/graphql.Time"}},
"Map": {Model: StringList{"github.com/99designs/gqlgen/graphql.Map"}},
"Any": {Model: StringList{"github.com/99designs/gqlgen/graphql.Any"}},
"Time": {Model: StringList{"github.com/99designs/gqlgen/graphql.Time"}},
"Map": {Model: StringList{"github.com/99designs/gqlgen/graphql.Map"}},
"Upload": {Model: StringList{"github.com/99designs/gqlgen/graphql.Upload"}},
"Any": {Model: StringList{"github.com/99designs/gqlgen/graphql.Any"}},
}

for typeName, entry := range extraBuiltins {
Expand Down
137 changes: 137 additions & 0 deletions docs/content/reference/file-upload.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
---
title: 'File Upload'
description: How to upload files.
linkTitle: File Upload
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.

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.
- 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.

# Examples

## Single file upload
For this use case, the schema could look like this.

```graphql
"The `UploadFile, // b.txt` scalar type represents a multipart file upload."
scalar Upload

"The `Query` type, represents all of the entry points into our object graph."
type Query {
...
}

"The `Mutation` type, represents all updates we can make to our data."
type Mutation {
singleUpload(file: Upload!): Bool!
}
```

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 } }' \
-F map='{ "0": ["variables.file"] }' \
-F [email protected]
```

That invokes the following operation:
```
{
query: `
mutation($file: Upload!) {
singleUpload(file: $file) {
id
}
}
`,
variables: {
file: File // a.txt
}
}
```

## 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

"The `File` type, represents the response of uploading a file."
type File {
id: Int!
name: String!
content: String!
}

"The `UploadFile` type, represents the request for uploading a file with a certain payload."
input UploadFile {
id: Int!
file: Upload!
}

"The `Query` type, represents all of the entry points into our object graph."
type Query {
...
}

"The `Mutation` type, represents all updates we can make to our data."
type Mutation {
multipleUpload(req: [UploadFile!]!): [File!]!
}

```

cURL can be used the make a query as follows:

```
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"] }' \
-F [email protected] \
-F [email protected]
```

That invokes the following operation:
```
{
query: `
mutation($req: [UploadFile!]!)
multipleUpload(req: $req) {
id,
name,
content
}
}
`,
variables: {
req: [
{
id: 1,
File, // b.txt
},
{
id: 2,
File, // c.txt
}
]
}
}
```

see the [example/fileupload](https://github.com/99designs/gqlgen/tree/master/example/fileupload) package for more examples.
15 changes: 14 additions & 1 deletion docs/content/reference/scalars.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ menu: { main: { parent: 'reference' } }

## Built-in helpers

gqlgen ships with three built-in helpers for common custom scalar use-cases, `Time`, `Any` 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 @@ -25,6 +25,19 @@ scalar Map

Maps an arbitrary GraphQL value to a `map[string]{interface}` Go type.


```graphql
scalar Upload
```

Maps a `Upload` GraphQL scalar to a `graphql.Upload` struct, defined as follows:
```
type Upload struct {
File io.Reader
Filename string
Size int64
}
```
### Any

```graphql
Expand Down
2 changes: 2 additions & 0 deletions example/fileupload/.gqlgen.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
model:
filename: model/generated.go
Loading