github.com/99designs/gqlgen@v0.17.45/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`. 11 Adding any of these to a schema will automatically add the marshalling behaviour to Go types. 12 13 ### Time 14 15 ```graphql 16 scalar Time 17 ``` 18 19 Maps a `Time` GraphQL scalar to a Go `time.Time` struct. 20 This scalar adheres to the [time.RFC3339Nano](https://pkg.go.dev/time#pkg-constants) format. 21 22 ### Universally Unique Identifier (UUID) 23 24 ```graphql 25 scalar UUID 26 ``` 27 This maps a `UUID` scalar value to a `uuid.UUID` type. 28 29 If you add to gqlgen.yml: 30 ```yaml 31 models: 32 UUID: 33 model: 34 - github.com/99designs/gqlgen/graphql.UUID 35 ``` 36 37 And then add `scalar UUID` to `schema.graphql` 38 39 See the _examples/uuid package for more examples. 40 41 ### Map 42 43 ```graphql 44 scalar Map 45 ``` 46 47 Maps an arbitrary GraphQL value to a `map[string]interface{}` Go type. 48 49 ### Upload 50 51 ```graphql 52 scalar Upload 53 ``` 54 55 Maps a `Upload` GraphQL scalar to a `graphql.Upload` struct, defined as follows: 56 57 ```go 58 type Upload struct { 59 File io.ReadSeeker 60 Filename string 61 Size int64 62 ContentType string 63 } 64 ``` 65 66 ### Any 67 68 ```graphql 69 scalar Any 70 ``` 71 72 Maps an arbitrary GraphQL value to a `interface{}` Go type. 73 74 ### Duration 75 76 ```graphql 77 scalar Duration 78 ``` 79 This maps a `Duration` scalar value conforming to the `ISO8601` standard (ex.: `P1Y2D`) to a `time.Duration` type. 80 81 If you add to gqlgen.yml: 82 ```yaml 83 models: 84 Duration: 85 model: 86 - github.com/99designs/gqlgen/graphql.Duration 87 ``` 88 89 And then add `scalar Duration` to `schema.graphql` 90 91 ## Custom scalars with user defined types 92 93 For user defined types you can implement the [graphql.Marshaler](https://pkg.go.dev/github.com/99designs/gqlgen/graphql#Marshaler) and [graphql.Unmarshaler](https://pkg.go.dev/github.com/99designs/gqlgen/graphql#Unmarshaler) or implement the [graphql.ContextMarshaler](https://pkg.go.dev/github.com/99designs/gqlgen/graphql#ContextMarshaler) and [graphql.ContextUnmarshaler](https://pkg.go.dev/github.com/99designs/gqlgen/graphql#ContextUnmarshaler) interfaces and they will be called. 94 95 ```go 96 package mypkg 97 98 import ( 99 "context" 100 "fmt" 101 "io" 102 "strconv" 103 ) 104 105 // 106 // Most common scalars 107 // 108 109 type YesNo bool 110 111 // UnmarshalGQL implements the graphql.Unmarshaler interface 112 func (y *YesNo) UnmarshalGQL(v interface{}) error { 113 yes, ok := v.(string) 114 if !ok { 115 return fmt.Errorf("YesNo must be a string") 116 } 117 118 if yes == "yes" { 119 *y = true 120 } else { 121 *y = false 122 } 123 return nil 124 } 125 126 // MarshalGQL implements the graphql.Marshaler interface 127 func (y YesNo) MarshalGQL(w io.Writer) { 128 if y { 129 w.Write([]byte(`"yes"`)) 130 } else { 131 w.Write([]byte(`"no"`)) 132 } 133 } 134 135 // 136 // Scalars that need access to the request context 137 // 138 139 type Length float64 140 141 // UnmarshalGQLContext implements the graphql.ContextUnmarshaler interface 142 func (l *Length) UnmarshalGQLContext(ctx context.Context, v interface{}) error { 143 s, ok := v.(string) 144 if !ok { 145 return fmt.Errorf("Length must be a string") 146 } 147 length, err := ParseLength(s) 148 if err != nil { 149 return err 150 } 151 *l = length 152 return nil 153 } 154 155 // MarshalGQLContext implements the graphql.ContextMarshaler interface 156 func (l Length) MarshalGQLContext(ctx context.Context, w io.Writer) error { 157 s, err := l.FormatContext(ctx) 158 if err != nil { 159 return err 160 } 161 w.Write([]byte(strconv.Quote(s))) 162 return nil 163 } 164 165 // ParseLength parses a length measurement string with unit on the end (eg: "12.45in") 166 func ParseLength(string) (Length, error) 167 168 // ParseLength formats the string using a value in the context to specify format 169 func (l Length) FormatContext(ctx context.Context) (string, error) 170 ``` 171 172 and then wire up the type in `.gqlgen.yml` or via directives like normal: 173 174 ```yaml 175 models: 176 YesNo: 177 model: github.com/me/mypkg.YesNo 178 ``` 179 180 ## Custom scalars with third party types 181 182 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 183 library (eg `string` or `time.Time`). To support this we can build an external marshaler: 184 185 ```go 186 package mypkg 187 188 import ( 189 "fmt" 190 "io" 191 "strings" 192 193 "github.com/99designs/gqlgen/graphql" 194 ) 195 196 197 func MarshalMyCustomBooleanScalar(b bool) graphql.Marshaler { 198 return graphql.WriterFunc(func(w io.Writer) { 199 if b { 200 w.Write([]byte("true")) 201 } else { 202 w.Write([]byte("false")) 203 } 204 }) 205 } 206 207 func UnmarshalMyCustomBooleanScalar(v interface{}) (bool, error) { 208 switch v := v.(type) { 209 case string: 210 return "true" == strings.ToLower(v), nil 211 case int: 212 return v != 0, nil 213 case bool: 214 return v, nil 215 default: 216 return false, fmt.Errorf("%T is not a bool", v) 217 } 218 } 219 ``` 220 221 Then in `.gqlgen.yml` point to the name without the Marshal|Unmarshal in front: 222 223 ```yaml 224 models: 225 MyCustomBooleanScalar: 226 model: github.com/me/mypkg.MyCustomBooleanScalar 227 ``` 228 229 **Note:** You also can (un)marshal to pointer types via this approach, simply accept a pointer in your 230 `Marshal...` func and return one in your `Unmarshal...` func. 231 232 **Note:** You can also (un)marshal with a context by having your custom marshal function return a 233 `graphql.ContextMarshaler` _and_ your unmarshal function take a `context.Context` as the first argument. 234 235 See the [_examples/scalars](https://github.com/99designs/gqlgen/tree/master/_examples/scalars) package for more examples. 236 237 ## Marshaling/Unmarshaling Errors 238 239 The errors that occur as part of custom scalar marshaling/unmarshaling will return a full path to the field. 240 For example, given the following schema: 241 242 ```graphql 243 extend type Mutation{ 244 updateUser(userInput: UserInput!): User! 245 } 246 247 input UserInput { 248 name: String! 249 primaryContactDetails: ContactDetailsInput! 250 secondaryContactDetails: ContactDetailsInput! 251 } 252 253 scalar Email 254 255 input ContactDetailsInput { 256 email: Email! 257 } 258 ``` 259 260 ... and the following variables: 261 262 ```json 263 { 264 "userInput": { 265 "name": "George", 266 "primaryContactDetails": { 267 "email": "not-an-email" 268 }, 269 "secondaryContactDetails": { 270 "email": "george@gmail.com" 271 } 272 } 273 } 274 ``` 275 276 ... and an unmarshal function that returns an error if the email is invalid. 277 The mutation will return an error containing the full path: 278 279 ```json 280 { 281 "message": "email invalid", 282 "path": [ 283 "updateUser", 284 "userInput", 285 "primaryContactDetails", 286 "email" 287 ] 288 } 289 ``` 290 291 **Note:** Marshaling errors can only be returned when using the `graphql.ContextMarshaler` style interface.