Учебник по Go GraphQL

Go
Учебник по Go GraphQL

Учебник по Go GraphQL

Всем привет, меня зовут Се Вэй, я программист.

Сегодняшняя тема: Учебник по Go GraphQL.

RESTful API-дизайн

Общая веб-разработка заключается в использовании стиля RESTful для разработки API.Общий процесс этого стиля RESTful разработки API:

  • анализ спроса
  • дизайн модели
  • Реализация кодирования
    • Дизайн маршрутизации:
    • Работа с параметрами: проверка, запрос
    • Ответ: формат JSON, код состояния

Ресурс обычно может абстрагироваться от четырех типов маршрутов, таких как интерфейсы голосования:

# 获取所有投票信息
GET /v1/api/votes

# 获取单个投票信息
GET /v1/api/vote/{vote_id}

# 创建投票
POST /v1/api/vote

# 更新投票
PATCH  /v1/api/vote/{vote_id}

# 删除投票
DELETE /v1/api/vote/{vote_id}

Соответственно, соответствующие получению, созданию, обновлению, удалению ресурсов.

Для бэкенд-разработчиков важно разрабатывать такие API таким образом, чтобы они соответствовали их потребностям.

Разработка таких API обычно требует решения следующих конкретных проблем:

  • Дизайн модели в соответствии с требованиями: уровень модели, ядро ​​​​дизайна модели соответствует таблицам базы данных, поэтому необходимо спроектировать поля, типы полей и отношения «многие ко многим» таблиц в соответствии с требованиями.
  • Абстрагируйте объекты ресурсов и выполняйте операции добавления, удаления, изменения и запроса ресурсов.
  • Возвращает ответ в формате JSON, код состояния или сообщение об ошибке.

Фронтенд или клиент, в соответствии с конкретными требованиями, вызывает интерфейс и обрабатывает поля, возвращаемые интерфейсом. Хотя иногда требования не требуют заполнения всех полей, а иногда требования требуют Вызов нескольких интерфейсов и сборка в большом формате для выполнения требований.

Сколько сущностей абстрагируется от бэкенда, соответственно будут разработаны интерфейсы различных сущностей ресурса. Последующие требования меняются, чтобы быть совместимыми, необходимо поддерживать все больше и больше интерфейсов.

Смотрите, вот такой дизайн интерфейса:

  • Необходимо поддерживать несколько типов интерфейсов, требования постоянно меняются, и поддерживается все больше и больше интерфейсов.
  • Приобретение полей не может быть определено фронтендом или клиентом, а возвращается все сразу, а затем обрабатывается соответствующими разработчиками
  • Интерфейсная версия должна быть рассмотрена ...

GraphQL API

GraphQL — это язык запросов, специально используемый для API, он был запущен крупной компанией Facebook, но до сих пор GraphQLне привело к широкому использованию, Большинство из них все еще разрабатываются в стиле RESTful API.

GraphQL пытается решить следующие проблемы:

  • Синтаксис запроса и результаты запроса очень похожи
  • Получить поля по запросу
  • Получение множества запросов маршрутизации может привести
  • Нет необходимости взаимодействовать на управление версиями

1

Поскольку это язык запросов, предназначенный для API, он должен иметь некоторые ограничения спецификации или синтаксиса. Какие знания содержит GraphQL?

  • Схема — это набор типизированных языков, которые определяют конкретные операции (например: запрос, изменение) и информацию об объекте (например: поля ответа)

schema.graphql

type Query {
    ping(data: String): Pong
}

type Mutation {
    createVote(name: String!): Vote
}

type Pong{
    data: String
    code: Int
}

type Vote {
    id: ID!
    name: String!
}

Конкретно определяет коллекцию запроса: Запрос, изменение или создание коллекции: Мутация, определяет два типа объекта: Pong, Vote, объект содержит поля и типы.

Этот файл схемы является документом разработки для внутренних разработчиков и документом API для внешних или клиентских разработчиков.

Предполагая, что back-end разработчик завершил разработку по файлу схемы, как вызвать API?

Рекомендуется: почтальон

# ping 请求动作
query {
    ping{
        data
        code
    }
}
# mutation 更改动作
mutation {
    createVote(name:"have a lunch") {
        id
        name 
    }
}

Можете ли вы найти некоторые закономерности?

  • Файл схемы практически определяет конкретную форму запроса, формат запроса и формат ответа.
  • Действия запроса API включают: тип операции (запрос, изменение, подписка), имя операции, имя запроса и поля запроса.
query HeartBeat {
    ping{
        data
        code
    }
}
  • Тип операции: запрос
  • Название операции: HeartBeat (название операции обычно не указывается)
  • Имя запроса: пинг
  • Ответ: объект Pong данных поля, код

GraphQL — это язык запросов, специализированный для API, с ограничениями синтаксиса.

В частности, включают:

  • Псевдонимы: переименование полей или объектов, в основном для разрешения конфликтов.
  • Фрагмент: Проще говоря, это извлечение общедоступных полей для повторного использования.
  • Переменные: параметры запроса в виде переменных
  • Директива: динамически отображать поля в соответствии с условиями: включает ли @include это поле, включает ли @skip это поле, отбрасывает ли @deprecate это поле
  • Встроенный фрагмент: получение полей более низкого уровня в типе интерфейса или типе объединения.
  • Мета-поле
  • Определение типа, определение объекта
  • Встроенные типы: ID, Int, Float, String, Boolean, другие типы могут использовать базовые типы для создания типов объектов.
  • Перечисление: набор необязательных значений.
  • Модификатор:!значит не пустой
  • Интерфейс: интерфейс
  • Тип союза:|Состоит из типов объектов
  • Тип ввода: Для решения проблемы передачи сложных параметров

Сказав так много, на самом деле лучший способ — вызвать интерфейс самостоятельно, обратиться к официальной документации, попробовать каждый вызов и ознакомиться с этим набором спецификаций синтаксиса.

Лучше всего конечно: GraphQL API 4 на Github (developer.github.com/v4/)

  • Знаком со спецификацией синтаксиса GraphQL.
  • Изучите спецификацию дизайна GraphQL

Войдите в свою учетную запись: Доступ:developer.GitHub.com/V4/explorer…

Просто назову несколько примеров:

0. viewer: User!

  • Название запроса: зритель
  • Объект ответа: User не пуст, то есть будет возвращен объект User.Объект User состоит из ряда полей и объектов.

1. Основное действие запроса

{
  viewer {
    __typename
    ... on User {
      name
    }
  }
}

// 结果

{
  "data": {
    "viewer": {
      "__typename": "User",
      "name": "XieWei"
    }
  }
}

2. Псевдонимы

{
  AliasForViewer:viewer {
    __typename
    ... on User {
      name
    }
  }
}


# 结果
{
  "data": {
    "AliasForViewer": {
      "__typename": "User",
      "name": "XieWei"
    }
  }
}

3. Имена операций, переменные, инструкции

query PrintViewer($Repository: String!,$Has: Boolean!){
  AliasForViewer:viewer{
    __typename
    ... on User {
      name
    }
    url
    status{
      createdAt
      emoji
      id
    }
    repository(name: $Repository) {
      name
      createdAt
      description @include(if:$Has)
      
    }
  
  }
}

# 变量
{
  "Repository": "2019-daily",
  "Has": false
}

# 结果

{
  "data": {
    "AliasForViewer": {
      "__typename": "User",
      "name": "XieWei",
      "url": "https://github.com/wuxiaoxiaoshen",
      "status": null,
      "repository": {
        "name": "2019-daily",
        "createdAt": "2019-01-11T15:17:43Z"
      }
    }
  }
}

# 如果变量为:

{
  "Repository": "2019-daily",
  "Has": true
}

# 则结果为

{
  "data": {
    "AliasForViewer": {
      "__typename": "User",
      "name": "XieWei",
      "url": "https://github.com/wuxiaoxiaoshen",
      "status": null,
      "repository": {
        "name": "2019-daily",
        "createdAt": "2019-01-11T15:17:43Z",
        "description": "把2019年的生活过成一本书"
      }
    }
  }
}

Попробуйте с документацией.

Вышеизложенное в основном касается синтаксиса операций запросов с использованием GraphQL.

2

Схема — это совокупность всех запросов, ответов и объявлений объектов, для бэкенда — основа разработки, а для фронтенда — документ API.

Как определить схему?

Вам просто нужно знать эти вещи:

  • Встроенный скалярный тип: ID (сущность — строка, уникальный идентификатор), Boolean, String, Float
  • модификатор!значит не пустой
  • Тип объекта:typeключевые слова
  • Тип перечисления:enumключевые слова
  • Тип ввода:inputключевые слова

Чтобы привести конкретный пример: Мини-программа: Голосование Tencent

титульная страница

Подробности

Шаг 1: Определите поля объекта типа

Объект определенного типа и дизайн поля ответа почти одинаковы.

# 类似于 map, 左边表示字段名称,右边表示类型
# [] 表示列表
# ! 修饰符表示非空
type Vote {
    id: ID!
    createdAt: Time
    updatedAt: Time
    deletedAt: Time
    title: String
    description: String
    options: [Options!]!
    deadline: Time
    class: VoteClass
}

type Options {
    name: String
}

# 输入类型: 一般用户更改资源中的输入是列表对象,完成复杂任务

input optionsInput {
    name:String!
}

# 枚举类型:投票区分:单选、多选两个选项值
enum VoteClass {
    SINGLE
    MULTIPLE
}

# 自定义类型,默认类型(ID、String、Boolean、Float)不包含 Time 类型
scalar Time

# 对象类型,用于检查服务是否完好
type Ping {
    data: String
    code: Int

}

Шаг 2: Определите тип операции: запрос используется для запроса, мутация используется для создания, изменения и удаления ресурсов.


# Query、Mutation 关键字固定
# 左边表示操作名称,右边表示返回的值的类型
# Query 一般完成查询操作
# Mutation 一般完成资源的创建、更改、删除操作

type Query {
    ping: Ping
    pinWithData(data: String): Ping
    vote(id:ID!): Vote
}

type Mutation {
    createVote(title:String!, options:[optionsInput],deadline:Time, description:String, class:VoteClass!): Vote
    updateVote(title:String!, description:String!): Vote
}

Схема завершает определение типов объектов и некоторых операций.Это документ разработки для внутренних разработчиков и документ API для внешних разработчиков.

3

Как клиент использует: Go : (graphql-go)

Тема: Мини-программа Tencent Voting

Step0: Структура проекта


├── Makefile
├── README.md
├── cmd
│   ├── root_cmd.go
│   └── sync_cmd.go
├── main.go
├── model
│   └── vote.go
├── pkg
│   ├── database
│   │   └── database.go
│   └── router
│       └── router.go
├── schema.graphql
├── script
│   └── db.sh
└── web
    ├── mutation
    │   └── mutation_type.go
    ├── ping
    │   └── ping_query.go
    ├── query
    │   └── query_type.go
    └── vote
        ├── vote_curd.go
        ├── vote_params.go
        └── vote_type.go
  • cmd: файл командной строки: в основном используется для синхронизации структуры таблицы базы данных
  • Основная запись функции main.go
  • Определение модели модели, отдельно для каждого ресурса, например Vote.go
  • Инфраструктура pkg: подключение к базе данных, проектирование маршрутизации
  • Бизнес-путь веб-ядра, обычно разделенный на папки по ресурсам
    • vote
      • Добавление, удаление и модификация ресурсов voice_curd.go
      • Параметры запроса voice_params.go
      • Ресурс в схеме voice_type.go, то есть определение типа объекта
    • query
      • query.go
    • mutation
      • mutation.go

По сути, это та же структура, что и в предыдущем дизайн-проекте RESTful API.

Шаг 1: В соответствии с определением схемы: завершите определение модели базы данных.

type base struct {
	Id        int64      `xorm:"pk autoincr notnull" json:"id"`
	CreatedAt time.Time  `xorm:"created" json:"created_at"`
	UpdatedAt time.Time  `xorm:"updated" json:"updated_at"`
	DeletedAt *time.Time `xorm:"deleted" json:"deleted_at"`
}

const (
	SINGLE = iota
	MULTIPLE
)

var ClassMap = map[int]string{}

func init() {
	ClassMap = make(map[int]string)
	ClassMap[SINGLE] = "SINGLE"
	ClassMap[MULTIPLE] = "MULTIPLE"
}

type Vote struct {
	base        `xorm:"extends"`
	Title       string    `json:"title"`
	Description string    `json:"description"`
	OptionIds   []int64   `json:"option_ids"`
	Deadline    time.Time `json:"deadline"`
	Class       int       `json:"class"`
}

type VoteSerializer struct {
	Id          int64              `json:"id"`
	CreatedAt   time.Time          `json:"created_at"`
	UpdatedAt   time.Time          `json:"updated_at"`
	Title       string             `json:"title"`
	Description string             `json:"description"`
	Options     []OptionSerializer `json:"options"`
	Deadline    time.Time          `json:"deadline"`
	Class       int                `json:"class"`
	ClassString string             `json:"class_string"`
}

func (V Vote) TableName() string {
	return "votes"
}

func (V Vote) Serializer() VoteSerializer {
	var optionSerializer []OptionSerializer
	var options []Option
	database.Engine.In("id", V.OptionIds).Find(&options)
	for _, i := range options {
		optionSerializer = append(optionSerializer, i.Serializer())
	}
	classString := func(value int) string {
		if V.Class == SINGLE {
			return "单选"
		}
		if V.Class == MULTIPLE {
			return "多选"
		}
		return ""
	}
	return VoteSerializer{
		Id:          V.Id,
		CreatedAt:   V.CreatedAt.Truncate(time.Second),
		UpdatedAt:   V.UpdatedAt.Truncate(time.Second),
		Title:       V.Title,
		Description: V.Description,
		Options:     optionSerializer,
		Deadline:    V.Deadline,
		Class:       V.Class,
		ClassString: classString(V.Class),
	}
}

type Option struct {
	base `xorm:"extends"`
	Name string `json:"name"`
}

type OptionSerializer struct {
	Id        int64     `json:"id"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
	Name      string    `json:"name"`
}

func (O Option) TableName() string {
	return "options"
}

func (O Option) Serializer() OptionSerializer {
	return OptionSerializer{
		Id:        O.Id,
		CreatedAt: O.CreatedAt.Truncate(time.Second),
		UpdatedAt: O.UpdatedAt.Truncate(time.Second),
		Name:      O.Name,
	}
}

По-прежнему сохраняйте стиль дизайна личной модели:

  • Определить структуру, соответствующую таблице базы данных
  • Определите сериализованную структуру, соответствующую ответу модели
  • Одиночный выбор, множественный выбор, по сути он представлен 0, 1 в базе данных, а ответ выводится на китайском языке: одиночный выбор, множественный выбор

Шаг 2: описание файла query.go


var Query = graphql.NewObject(graphql.ObjectConfig{
	Name: "Query",
	Fields: graphql.Fields{
		"ping": &graphql.Field{
			Type: ping.Ping,
			Resolve: func(p graphql.ResolveParams) (i interface{}, e error) {
				return ping.Default, nil
			},
		},
	},
})

func init() {
	Query.AddFieldConfig("pingWithData", &graphql.Field{
		Type: ping.Ping,
		Args: graphql.FieldConfigArgument{
			"data": &graphql.ArgumentConfig{
				Type: graphql.NewNonNull(graphql.String),
			},
		},
		Resolve: func(p graphql.ResolveParams) (i interface{}, e error) {
			if p.Args["data"] == nil {
				return ping.Default, nil
			}
			return ping.MakeResponseForPing(p.Args["data"].(string)), nil
		},
	})
}

func init() {
	Query.AddFieldConfig("vote", &graphql.Field{
		Type: vote.Vote,
		Args: graphql.FieldConfigArgument{
			"id": &graphql.ArgumentConfig{
				Type: graphql.NewNonNull(graphql.ID),
			},
		},
		Resolve: func(p graphql.ResolveParams) (i interface{}, e error) {
			id := p.Args["id"]
			ID, _ := strconv.Atoi(id.(string))
			return vote.GetOneVote(int64(ID))
		},
	})
}

В основном то же самое, что и определение запроса в файле схемы:

type Query {
    ping: Ping
    pinWithData(data: String): Ping
    vote(id:ID!): Vote
}
  • Поля представляют поля объекта
  • Тип указывает тип возвращаемого значения.
  • Args представляет параметры
  • Resolve представляет собой конкретную функцию обработки

Встроенные типы: (ID, String, Boolean, Float)

- graphql.ID
- graphql.String
- graphql.Boolean
- graphql.Float
...

Проще говоря: все объекты и поля должны иметь функции-обработчики.

var Query = graphql.NewObject(graphql.ObjectConfig{
	Name: "Query",
	Fields: graphql.Fields{
		"ping": &graphql.Field{
			Type: ping.Ping,
			Resolve: func(p graphql.ResolveParams) (i interface{}, e error) {
				return ping.Default, nil
			},
		},
	},
})

func init() {
	Query.AddFieldConfig("pingWithData", &graphql.Field{
		Type: ping.Ping,
		Args: graphql.FieldConfigArgument{
			"data": &graphql.ArgumentConfig{
				Type: graphql.NewNonNull(graphql.String),
			},
		},
		Resolve: func(p graphql.ResolveParams) (i interface{}, e error) {
			if p.Args["data"] == nil {
				return ping.Default, nil
			}
			return ping.MakeResponseForPing(p.Args["data"].(string)), nil
		},
	})
}

var Ping = graphql.NewObject(graphql.ObjectConfig{
	Name: "ping",
	Fields: graphql.Fields{
		"data": &graphql.Field{
			Type: graphql.String,
			Resolve: func(p graphql.ResolveParams) (i interface{}, e error) {
				if response, ok := p.Source.(ResponseForPing); ok {
					return response.Data, nil
				}
				return nil, fmt.Errorf("field not found")
			},
		},
		"code": &graphql.Field{
			Type: graphql.String,
			Resolve: func(p graphql.ResolveParams) (i interface{}, e error) {
				if response, ok := p.Source.(ResponseForPing); ok {
					return response.Code, nil
				}
				return nil, fmt.Errorf("field not found")
			},
		},
	},
})

type ResponseForPing struct {
	Data string `json:"data"`
	Code int    `json:"code"`
}

var Default = ResponseForPing{
	Data: "pong",
	Code: http.StatusOK,
}

func MakeResponseForPing(data string) ResponseForPing {
	return ResponseForPing{
		Data: data,
		Code: http.StatusOK,
	}
}

С клиентом Go Graphql-go большая часть работы заключается в определении объектов, определении типов полей, определении обработчиков полей и т. д.

  • graphql.Object
  • graphql.InputObject
  • graphql.Enum

Шаг 3: описание файлаmutation.go

var Mutation = graphql.NewObject(graphql.ObjectConfig{
	Name: "Mutation",
	Fields: graphql.Fields{
		"createVote": &graphql.Field{
			Type: vote.Vote,
			Args: graphql.FieldConfigArgument{
				"title": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
				"options": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.NewList(vote.OptionInput)),
				},
				"description": &graphql.ArgumentConfig{
					Type: graphql.String,
				},
				"deadline": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
				"class": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(vote.Class),
				},
			},
			Resolve: func(p graphql.ResolveParams) (i interface{}, e error) {
				log.Println(p.Args)
				var params vote.CreateVoteParams
				params.Title = p.Args["title"].(string)
				if p.Args["description"] != nil {
					params.Description = p.Args["description"].(string)
				}
				params.Deadline = p.Args["deadline"].(string)
				params.Class = p.Args["class"].(int)
				var options []vote.OptionParams
				for _, i := range p.Args["options"].([]interface{}) {
					var one vote.OptionParams
					k := i.(map[string]interface{})
					one.Name = k["name"].(string)
					options = append(options, one)
				}
				params.Options = options
				log.Println(params)
				result, err := vote.CreateVote(params)
				if err != nil {
					return nil, err
				}
				return result, nil

			},
		},
		"updateVote": &graphql.Field{
			Type: vote.Vote,
			Args: graphql.FieldConfigArgument{
				"title": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
				"description": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
				"id": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.ID),
				},
			},
			Resolve: func(p graphql.ResolveParams) (i interface{}, e error) {
				var params vote.UpdateVoteParams
				id := p.Args["id"]
				ID, _ := strconv.Atoi(id.(string))
				params.Id = int64(ID)
				params.Title = p.Args["title"].(string)
				params.Description = p.Args["description"].(string)
				return vote.UpdateOneVote(params)
			},
		},
	},
})

Шаг 4: Создайте схему для запуска службы


func RegisterSchema() *graphql.Schema {
	schema, err := graphql.NewSchema(
		graphql.SchemaConfig{
			Query:    query.Query,
			Mutation: mutation.Mutation,
		})
	if err != nil {
		panic(fmt.Sprintf("schema init fail %s", err.Error()))
	}
	return &schema

}

func Register() *handler.Handler {
	return handler.New(&handler.Config{
		Schema:   RegisterSchema(),
		Pretty:   true,
		GraphiQL: true,
	})
}
func StartWebServer() {
	log.Println("Start Web Server...")
	http.Handle("/graphql", Register())
	log.Fatal(http.ListenAndServe(":7878", nil))
}

Шаг 5: запуск, вызов интерфейса

  • Есть только один маршрут:/graphql
  • Управление версиями не требуется
  • Все методы запроса:POST(Конечно, действие запроса также может использовать Get, что не удобно, когда есть много параметров запроса)

Примеры: (интерфейс вызывает документ запроса, в соответствии с потребностями вызывающего абонента выберите поле ответа)

mutation {
    createVote(
        title: "去哪玩?",
        description:"本次团建去哪玩?",
        options:[
            {
                name: "杭州西湖"
            },{
                name:"安徽黄山"
            },{
                name:"香港九龙"
            }
            ],
        deadline: "2019-08-01 00:00:00",
        class: SINGLE
        ) {
            id
            title
            deadline
            description
            createdAt
            updatedAt
            options{
                name
            }
            class
            classString
        }
}

# 结果

{
	"data": {
		"vote": {
			"class": "SINGLE",
			"classString": "单选",
			"createdAt": "2019-07-30T19:33:27+08:00",
			"deadline": "2019-08-01T00:00:00+08:00",
			"description": "本次团建去哪玩?",
			"id": "1",
			"options": [
				{
					"name": "杭州西湖"
				},
				{
					"name": "安徽黄山"
				},
				{
					"name": "香港九龙"
				}
			],
			"title": "去哪玩?",
			"updatedAt": "2019-07-30T19:33:27+08:00"
		}
	}
}


query{
    vote(id:1){
            id
            title
            deadline
            description
            createdAt
            updatedAt
            options{
                name
            }
            class
            classString
    }
}

# 结果

{
	"data": {
		"createVote": {
			"class": "SINGLE",
			"classString": "SINGLE",
			"createdAt": "2019-07-30T19:33:27+08:00",
			"deadline": "2019-08-01T00:00:00+08:00",
			"description": "本次团建去哪玩?",
			"id": "1",
			"options": {
				{
					"name": "杭州西湖"
				},
				{
					"name": "安徽黄山"
				},
				{
					"name": "香港九龙"
				}
			},
			"title": "去哪玩?",
			"updatedAt": "2019-07-30T19:33:27+08:00"
		}
	}

}

4

предположение:

  • Design First: схема, руководство для разработчиков
  • Если запросов или изменений слишком много, разделите их по функциям или ресурсам (структура проекта разделена по функциям, что помогает в определенной степени снизить нагрузку на размышления)
var Query = graphql.NewObject(graphql.ObjectConfig{}

func init(){
    // 资源一
    Query.AddFieldConfig("filedsName", &graphql.Field{})
}

func init(){
    // 资源二
}
  • Как обрабатывать сложные параметры запроса:
var Mutation = graphql.NewObject(graphql.ObjectConfig{
	Name: "Mutation",
	Fields: graphql.Fields{
		"createVote": &graphql.Field{
			Type: vote.Vote,
			Args: graphql.FieldConfigArgument{
				"title": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
				"options": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.NewList(vote.OptionInput)),
				},
				"description": &graphql.ArgumentConfig{
					Type: graphql.String,
				},
				"deadline": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
				"class": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(vote.Class),
				},
			},
			Resolve: func(p graphql.ResolveParams) (i interface{}, e error) {
				log.Println(p.Args)
				var params vote.CreateVoteParams
				params.Title = p.Args["title"].(string)
				if p.Args["description"] != nil {
					params.Description = p.Args["description"].(string)
				}
				params.Deadline = p.Args["deadline"].(string)
				params.Class = p.Args["class"].(int)
				var options []vote.OptionParams
				for _, i := range p.Args["options"].([]interface{}) {
					var one vote.OptionParams
					k := i.(map[string]interface{})
					one.Name = k["name"].(string)
					options = append(options, one)
				}
				params.Options = options
				log.Println(params)
				result, err := vote.CreateVote(params)
				if err != nil {
					return nil, err
				}
				return result, nil

			},
		},
	},
})

Args определяет все поля и типы для этого запроса. p.Args type (map[string]interface), можно получить параметры запроса. Возврат представляет собой интерфейс в соответствии с типом, определенным в Args, преобразование типов

5

Резюме: Эта статья кратко объясняет синтаксис GraphQL и пройти программирование для реализации операций GraphQL.

Как посоветуете учиться?