github.com/maeglindeveloper/gqlgen@v0.13.1-0.20210413081235-57808b12a0a0/docs/content/reference/scalars.md (about) 1 --- 2 linkTitle: Scalars 3 title: Mapping GraphQL scalar types to Go types 4 description: Mapping GraphQL scalar types to Go types 5 menu: { main: { parent: "reference", weight: 10 } } 6 --- 7 8 ## Built-in helpers 9 10 gqlgen ships with some 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. 11 12 ### Time 13 14 ```graphql 15 scalar Time 16 ``` 17 18 Maps a `Time` GraphQL scalar to a Go `time.Time` struct. 19 20 ### Map 21 22 ```graphql 23 scalar Map 24 ``` 25 26 Maps an arbitrary GraphQL value to a `map[string]interface{}` Go type. 27 28 ### Upload 29 30 ```graphql 31 scalar Upload 32 ``` 33 34 Maps a `Upload` GraphQL scalar to a `graphql.Upload` struct, defined as follows: 35 36 ```go 37 type Upload struct { 38 File io.Reader 39 Filename string 40 Size int64 41 ContentType string 42 } 43 ``` 44 45 ### Any 46 47 ```graphql 48 scalar Any 49 ``` 50 51 Maps an arbitrary GraphQL value to a `interface{}` Go type. 52 53 ## Custom scalars with user defined types 54 55 For user defined types you can implement the graphql.Marshaler and graphql.Unmarshaler interfaces and they will be called. 56 57 ```go 58 package mypkg 59 60 import ( 61 "fmt" 62 "io" 63 ) 64 65 type YesNo bool 66 67 // UnmarshalGQL implements the graphql.Unmarshaler interface 68 func (y *YesNo) UnmarshalGQL(v interface{}) error { 69 yes, ok := v.(string) 70 if !ok { 71 return fmt.Errorf("YesNo must be a string") 72 } 73 74 if yes == "yes" { 75 *y = true 76 } else { 77 *y = false 78 } 79 return nil 80 } 81 82 // MarshalGQL implements the graphql.Marshaler interface 83 func (y YesNo) MarshalGQL(w io.Writer) { 84 if y { 85 w.Write([]byte(`"yes"`)) 86 } else { 87 w.Write([]byte(`"no"`)) 88 } 89 } 90 ``` 91 92 and then wire up the type in .gqlgen.yml or via directives like normal: 93 94 ```yaml 95 models: 96 YesNo: 97 model: github.com/me/mypkg.YesNo 98 ``` 99 100 ## Custom scalars with third party types 101 102 Sometimes you are unable to add add methods to a type - perhaps you don't own the type, or it is part of the standard 103 library (eg string or time.Time). To support this we can build an external marshaler: 104 105 ```go 106 package mypkg 107 108 import ( 109 "fmt" 110 "io" 111 "strings" 112 113 "github.com/99designs/gqlgen/graphql" 114 ) 115 116 117 func MarshalMyCustomBooleanScalar(b bool) graphql.Marshaler { 118 return graphql.WriterFunc(func(w io.Writer) { 119 if b { 120 w.Write([]byte("true")) 121 } else { 122 w.Write([]byte("false")) 123 } 124 }) 125 } 126 127 func UnmarshalMyCustomBooleanScalar(v interface{}) (bool, error) { 128 switch v := v.(type) { 129 case string: 130 return "true" == strings.ToLower(v), nil 131 case int: 132 return v != 0, nil 133 case bool: 134 return v, nil 135 default: 136 return false, fmt.Errorf("%T is not a bool", v) 137 } 138 } 139 ``` 140 141 Then in .gqlgen.yml point to the name without the Marshal|Unmarshal in front: 142 143 ```yaml 144 models: 145 MyCustomBooleanScalar: 146 model: github.com/me/mypkg.MyCustomBooleanScalar 147 ``` 148 149 **Note:** you also can un/marshal to pointer types via this approach, simply accept a pointer in your 150 `Marshal...` func and return one in your `Unmarshal...` func. 151 152 See the [example/scalars](https://github.com/99designs/gqlgen/tree/master/example/scalars) package for more examples. 153 154 ## Unmarshaling Errors 155 156 The errors that occur as part of custom scalar unmarshaling will return a full path to the field. 157 For example, given the following schema ... 158 159 ```graphql 160 extend type Mutation{ 161 updateUser(userInput: UserInput!): User! 162 } 163 164 input UserInput { 165 name: String! 166 primaryContactDetails: ContactDetailsInput! 167 secondaryContactDetails: ContactDetailsInput! 168 } 169 170 scalar Email 171 input ContactDetailsInput { 172 email: Email! 173 } 174 ``` 175 176 ... and the following variables: 177 178 ```json 179 180 { 181 "userInput": { 182 "name": "George", 183 "primaryContactDetails": { 184 "email": "not-an-email" 185 }, 186 "secondaryContactDetails": { 187 "email": "george@gmail.com" 188 } 189 } 190 } 191 ``` 192 193 ... and an unmarshal function that returns an error if the email is invalid. The mutation will return an error containing the full path: 194 ```json 195 { 196 "message": "email invalid", 197 "path": [ 198 "updateUser", 199 "userInput", 200 "primaryContactDetails", 201 "email" 202 ] 203 } 204 ``` 205 206