お題
表題の通り。備忘録として。
開発環境
# OS - Linux(Ubuntu)
$ cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.4 LTS (Bionic Beaver)"
# 言語 - Golang
$ go version
go version go1.13.9 linux/amd64
# ツール - gqlgen
$ gqlgen version
v0.11.3-dev
結果
今回のソースは下記。
https://github.com/sky0621/study-gqlgen/tree/v0.1/types
Null"不可"のケース
型名 | GraphQLスキーマ上の定義 | gqlgen自動生成後の型 | 備考 |
---|---|---|---|
ID型 | ID! | string | Uniqueであることが前提 |
UTF8文字列型 | String! | string | - |
符号付き32bit整数型 | Int! | int | - |
符号付き倍精度浮動小数点数型 | Float! | float64 | - |
真偽値型 | Boolean! | bool | - |
日付型 | Date! | string | Date型で定義しても自動的に言語依存の日付型にはマッピングされない |
列挙型 | Signal! | Signal | enumはGolangではstring型の定数となる |
時刻型(gqlgenビルトイン) | Time! | time.Time | - |
マップ型(gqlgenビルトイン) | Map! | map[string]interface{} | GraphQLスキーマ上はNull"不可"の定義だが、map なので nil が入りうる |
アップロード型(gqlgenビルトイン) | Upload! | graphql.Upload | - |
なんでもあり型(gqlgenビルトイン) | Any! | interface{} | GraphQLスキーマ上はNull"不可"の定義だが、interface なので nil が入りうる |
カスタムScalar型 | YesNo! | YesNo | 事前定義した型にマッピングされる |
Object構造型 | SomeType! | *Object | GraphQLスキーマ上はNull"不可"の定義だが、参照型で自動生成されるので nil が入りうる |
文字列型配列 | [String!]! | []string | GraphQLスキーマ上はNull"不可"の定義だが、Slice なので nil が入りうる |
マップ型配列 | [Map!]! | []map[string]interface{} | GraphQLスキーマ上はNull"不可"の定義だが、Slice なので nil が入りうる 内部の要素も map なので nil が入りうる |
なんでもあり型配列 | [Any!]! | []interface{} | GraphQLスキーマ上はNull"不可"の定義だが、Slice なので nil が入りうる 内部の要素も interface なので nil が入りうる |
Object構造型配列 | [SomeType!]! | []*Object | GraphQLスキーマ上はNull"不可"の定義だが、Slice なので nil が入りうる 内部の要素も参照型なので nil が入りうる |
Null"可"のケース
型名 | GraphQLスキーマ上の定義 | gqlgen自動生成後の型 | 備考 |
---|---|---|---|
UTF8文字列型 | String | *string | - |
符号付き32bit整数型 | Int | *int | - |
符号付き倍精度浮動小数点数型 | Float | *float64 | - |
真偽値型 | Boolean | *bool | - |
日付型 | Date | *string | Date型で定義しても自動的に言語依存の日付型にはマッピングされない |
列挙型 | Signal | *Signal | enumはGolangではstring型の定数となる |
時刻型(gqlgenビルトイン) | Time | *time.Time | - |
マップ型(gqlgenビルトイン) | Map | map[string]interface{} | - |
アップロード型(gqlgenビルトイン) | Upload | *graphql.Upload | - |
なんでもあり型(gqlgenビルトイン) | Any | interface{} | - |
カスタムScalar型 | YesNo | *YesNo | 事前定義した型にマッピングされる |
Object構造型 | SomeType | *Object | - |
文字列型配列 | [String] | []*string | - |
文字列型配列 | [String]! | []*string | - |
文字列型配列 | [String!] | []string | - |
マップ型配列 | [Map] | []map[string]interface{} | - |
マップ型配列 | [Map]! | []map[string]interface{} | - |
マップ型配列 | [Map!] | []map[string]interface{} | - |
なんでもあり型配列 | [Any] | []interface{} | - |
なんでもあり型配列 | [Any]! | []interface{} | - |
なんでもあり型配列 | [Any!] | []interface{} | - |
Object構造型配列 | [SomeType] | []*Object | - |
Object構造型配列 | [SomeType]! | []*Object | - |
Object構造型配列 | [SomeType!] | []*Object | - |
補足
GraphQLスキーマ
types/graph/schema.graphqls
# Global Object Identification ... 全データを共通のIDでユニーク化
interface Node {
id: ID!
}
schema {
query: Query
mutation: Mutation
}
type Query {
node(id: ID!): Node
}
type Mutation {
noop(input: NoopInput): NoopPayload
}
input NoopInput {
clientMutationId: String
}
type NoopPayload {
clientMutationId: String
}
type MutationResponse {
id: ID
}
scalar Date
scalar Time
scalar Map
scalar Upload
scalar Any
scalar YesNo
enum Signal {
RED
YELLOW
GREEN
}
types/graph/various.graphqls
extend type Query {
nonNullTypes: [NonNullType!]!
nullableTypes: [NullableType!]!
}
"""
https://graphql.org/learn/schema/#scalar-types
https://github.com/99designs/gqlgen/blob/master/docs/content/reference/scalars.md
"""
type NonNullType implements Node {
"ID型 - ID!"
id: ID!
"UTF8文字列型 - String!"
stringNonNull: String!
"符号付き32bit整数型 - Int!"
intNonNull: Int!
"符号付き倍精度浮動小数点数型 - Float!"
floatNonNull: Float!
"真偽値型 - Boolean!"
booleanNonNull: Boolean!
"日付型 - Date!"
dateNonNull: Date!
"列挙型 - Signal!"
signalNonNull: Signal!
"時刻型(gqlgenビルトイン) - Time!"
timeNonNull: Time!
"マップ型(gqlgenビルトイン) - Map!"
mapNonNull: Map!
"アップロード型(gqlgenビルトイン) - Upload!"
uploadNonNull: Upload!
"なんでもあり型(gqlgenビルトイン) - Any!"
anyNonNull: Any!
"カスタムScalar型 - YesNo!"
yesNoNonNull: YesNo!
"Object構造型 - SomeType!"
objectNonNull: Object!
"文字列型配列 - [String!]!"
stringsNonNull: [String!]!
"マップ型配列 - [Map!]!"
mapsNonNull: [Map!]!
"なんでもあり型配列 - [Any!]!"
anyTypesNonNull: [Any!]!
"Object構造型配列 - [SomeType!]!"
objectsNonNull: [Object!]!
}
type NullableType implements Node {
"ID型 - ID!"
id: ID!
"UTF8文字列型 - String"
stringNullable: String
"符号付き32bit整数型 - Int"
intNullable: Int
"符号付き倍精度浮動小数点数型 - Float"
floatNullable: Float
"真偽値型 - Boolean"
booleanNullable: Boolean
"日付型 - Date"
dateNullable: Date
"列挙型 - Signal"
signalNullable: Signal
"時刻型(gqlgenビルトイン) - Time"
timeNullable: Time
"マップ型(gqlgenビルトイン) - Map"
mapNullable: Map
"アップロード型(gqlgenビルトイン) - Upload"
uploadNullable: Upload
"なんでもあり型(gqlgenビルトイン) - Any"
anyNullable: Any
"カスタムScalar型 - YesNo"
yesNoNullable: YesNo
"Object構造型 - SomeType"
objectNullable: Object
"文字列型配列 - [String]"
stringsNullable: [String]
"文字列型配列 - [String]!"
stringsObjectNullable: [String]!
"文字列型配列 - [String!]"
stringsArrayNullable: [String!]
"マップ型配列 - [Map]"
mapsNullable: [Map]
"マップ型配列 - [Map]!"
mapsObjectNullable: [Map]!
"マップ型配列 - [Map!]"
mapsArrayNullable: [Map!]
"なんでもあり型配列 - [Any]"
anyTypesNullable: [Any]
"なんでもあり型配列 - [Any]!"
anyTypesObjectNullable: [Any]!
"なんでもあり型配列 - [Any!]"
anyTypesArrayNullable: [Any!]
"Object構造型配列 - [SomeType]"
objectsNullable: [Object]
"Object構造型配列 - [SomeType]!"
objectsObjectNullable: [Object]!
"Object構造型配列 - [SomeType!]"
objectsArrayNullable: [Object!]
}
type Object implements Node {
id: ID!
自動生成モデル
types/graph/model/models_gen.go
// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
package model
import (
"fmt"
"io"
"strconv"
"time"
"github.com/99designs/gqlgen/graphql"
)
type Node interface {
IsNode()
}
type MutationResponse struct {
ID *string `json:"id"`
}
// https://graphql.org/learn/schema/#scalar-types
// https://github.com/99designs/gqlgen/blob/master/docs/content/reference/scalars.md
type NonNullType struct {
// ID型 - ID!
ID string `json:"id"`
// UTF8文字列型 - String!
StringNonNull string `json:"stringNonNull"`
// 符号付き32bit整数型 - Int!
IntNonNull int `json:"intNonNull"`
// 符号付き倍精度浮動小数点数型 - Float!
FloatNonNull float64 `json:"floatNonNull"`
// 真偽値型 - Boolean!
BooleanNonNull bool `json:"booleanNonNull"`
// 日付型 - Date!
DateNonNull string `json:"dateNonNull"`
// 列挙型 - Signal!
SignalNonNull Signal `json:"signalNonNull"`
// 時刻型(gqlgenビルトイン) - Time!
TimeNonNull time.Time `json:"timeNonNull"`
// マップ型(gqlgenビルトイン) - Map!
MapNonNull map[string]interface{} `json:"mapNonNull"`
// アップロード型(gqlgenビルトイン) - Upload!
UploadNonNull graphql.Upload `json:"uploadNonNull"`
// なんでもあり型(gqlgenビルトイン) - Any!
AnyNonNull interface{} `json:"anyNonNull"`
// カスタムScalar型 - YesNo!
YesNoNonNull YesNo `json:"yesNoNonNull"`
// Object構造型 - SomeType!
ObjectNonNull *Object `json:"objectNonNull"`
// 文字列型配列 - [String!]!
StringsNonNull []string `json:"stringsNonNull"`
// マップ型配列 - [Map!]!
MapsNonNull []map[string]interface{} `json:"mapsNonNull"`
// なんでもあり型配列 - [Any!]!
AnyTypesNonNull []interface{} `json:"anyTypesNonNull"`
// Object構造型配列 - [SomeType!]!
ObjectsNonNull []*Object `json:"objectsNonNull"`
}
func (NonNullType) IsNode() {}
type NoopInput struct {
ClientMutationID *string `json:"clientMutationId"`
}
type NoopPayload struct {
ClientMutationID *string `json:"clientMutationId"`
}
type NullableType struct {
// ID型 - ID!
ID string `json:"id"`
// UTF8文字列型 - String
StringNullable *string `json:"stringNullable"`
// 符号付き32bit整数型 - Int
IntNullable *int `json:"intNullable"`
// 符号付き倍精度浮動小数点数型 - Float
FloatNullable *float64 `json:"floatNullable"`
// 真偽値型 - Boolean
BooleanNullable *bool `json:"booleanNullable"`
// 日付型 - Date
DateNullable *string `json:"dateNullable"`
// 列挙型 - Signal
SignalNullable *Signal `json:"signalNullable"`
// 時刻型(gqlgenビルトイン) - Time
TimeNullable *time.Time `json:"timeNullable"`
// マップ型(gqlgenビルトイン) - Map
MapNullable map[string]interface{} `json:"mapNullable"`
// アップロード型(gqlgenビルトイン) - Upload
UploadNullable *graphql.Upload `json:"uploadNullable"`
// なんでもあり型(gqlgenビルトイン) - Any
AnyNullable interface{} `json:"anyNullable"`
// カスタムScalar型 - YesNo
YesNoNullable *YesNo `json:"yesNoNullable"`
// Object構造型 - SomeType
ObjectNullable *Object `json:"objectNullable"`
// 文字列型配列 - [String]
StringsNullable []*string `json:"stringsNullable"`
// 文字列型配列 - [String]!
StringsObjectNullable []*string `json:"stringsObjectNullable"`
// 文字列型配列 - [String!]
StringsArrayNullable []string `json:"stringsArrayNullable"`
// マップ型配列 - [Map]
MapsNullable []map[string]interface{} `json:"mapsNullable"`
// マップ型配列 - [Map]!
MapsObjectNullable []map[string]interface{} `json:"mapsObjectNullable"`
// マップ型配列 - [Map!]
MapsArrayNullable []map[string]interface{} `json:"mapsArrayNullable"`
// なんでもあり型配列 - [Any]
AnyTypesNullable []interface{} `json:"anyTypesNullable"`
// なんでもあり型配列 - [Any]!
AnyTypesObjectNullable []interface{} `json:"anyTypesObjectNullable"`
// なんでもあり型配列 - [Any!]
AnyTypesArrayNullable []interface{} `json:"anyTypesArrayNullable"`
// Object構造型配列 - [SomeType]
ObjectsNullable []*Object `json:"objectsNullable"`
// Object構造型配列 - [SomeType]!
ObjectsObjectNullable []*Object `json:"objectsObjectNullable"`
// Object構造型配列 - [SomeType!]
ObjectsArrayNullable []*Object `json:"objectsArrayNullable"`
}
func (NullableType) IsNode() {}
type Object struct {
ID string `json:"id"`
}
func (Object) IsNode() {}
type Signal string
const (
SignalRed Signal = "RED"
SignalYellow Signal = "YELLOW"
SignalGreen Signal = "GREEN"
)
var AllSignal = []Signal{
SignalRed,
SignalYellow,
SignalGreen,
}
func (e Signal) IsValid() bool {
switch e {
case SignalRed, SignalYellow, SignalGreen:
return true
}
return false
}
func (e Signal) String() string {
return string(e)
}
func (e *Signal) UnmarshalGQL(v interface{}) error {
str, ok := v.(string)
if !ok {
return fmt.Errorf("enums must be strings")
}
*e = Signal(str)
if !e.IsValid() {
return fmt.Errorf("%s is not a valid Signal", str)
}
return nil
}
func (e Signal) MarshalGQL(w io.Writer) {
fmt.Fprint(w, strconv.Quote(e.String()))
}
カスタムScalar:「YesNo
」型
types/graph/model/custom_scalar.go
package model
import (
"fmt"
"io"
)
type YesNo bool
// UnmarshalGQL implements the graphql.Unmarshaler interface
func (y *YesNo) UnmarshalGQL(v interface{}) error {
yes, ok := v.(string)
if !ok {
return fmt.Errorf("points must be strings")
}
if yes == "yes" {
*y = true
} else {
*y = false
}
return nil
}
// MarshalGQL implements the graphql.Marshaler interface
func (y YesNo) MarshalGQL(w io.Writer) {
if y {
if _, err := w.Write([]byte(`"yes"`)); err != nil {
fmt.Println(err)
}
} else {
if _, err := w.Write([]byte(`"no"`)); err != nil {
fmt.Println(err)
}
}
}
gqlgen.yml
types/gqlgen.yml
# Where are all the schema files located? globs are supported eg src/**/*.graphqls
schema:
- graph/*.graphqls
〜〜省略〜〜
models:
ID:
model:
- github.com/99designs/gqlgen/graphql.ID
- github.com/99designs/gqlgen/graphql.Int
- github.com/99designs/gqlgen/graphql.Int64
- github.com/99designs/gqlgen/graphql.Int32
Int:
model:
- github.com/99designs/gqlgen/graphql.Int
- github.com/99designs/gqlgen/graphql.Int64
- github.com/99designs/gqlgen/graphql.Int32
YesNo:
model:
- github.com/sky0621/study-gqlgen/types/graph/model.YesNo