Библиотека генерации GraphQL API
Стандартный набор бибилиотек, предназначенных для реализации API с использованием GraphQL
, не предоставляет ни какой
возможности для генерации API
, все параметры/типы/методы приходится прописывать вручную или генерировать при помощи
аннотаций, что не всегда удобно, например, когда необходимо реализовать достаточно динамичное API
для запросов. Данная
библиотека решает эту проблему, предоставляя взоможность сгенерировать API GraphQL по определенному шаблону.
Возможности
Библиотека предоставляет слудующие возможности:
Генерация запроса выборки листинга сущности.
Библиотека может сформировать набор параметров для стандартной библиотеки GraphQL
для выбора листинга сущностей
определенного вида.
Для этого используется следующий формат:
query Test {
test_list (
where: {
is_active: {
_equals: true
}
}
offset: 0
limit: 0
order: [{
by: name
direction: asc
priority: 1
}]
) {
id
name
stat
active_date
is_active
}
}
Доступные для выбора параметры
:
where - Фильтрация запроса
limit - Количество записей в результате
offset - Смещение (для пагенации)
rder - Сортировка запроса
Генерация запроса аггрегации
На основе переданного объекта библиотека формирует новый запрос на аггрегацию значений
сущности. Формат:
query Test {
test_aggregate(
groupBy:[name, active_date]
having: {
is_active: {
_equals: true
}
}
order: [{
by: name
direction: asc
priority: 1
}]
){
count
avg {
stat
}
variants {
name
id
}
min {
stat
}
max {
stat
}
sum {
stat
}
}
}
Доступные для выбора параметры
:
where - Фильтрация запроса
limit - Количество записей в результате
offset - Смещение (для пагенации)
rder - Сортировка запроса
groupBy - Аналог SQL GroupBy
having - Аналог SQL Having
Доступные операторы
аггрегации:
count - Количество записей
avg - Вычисление среднего значения
min - Поиск минимального значения
max - Поиск максимального значения
sum - Сумма всех значений
variants - Уникальные варианты значений для переданных полей
Генерация мутации вставки
значений
Библиотека может сгенерировать мутацию вставки значений для сущности. Формат:
mutation Test {
test_insert(
objects: [{
name: "test"
is_active: true
active_date: "2002-02-02T21:00:16.000Z"
}]
) {
affected_rows
returning {
id
active_date
name
is_active
stat
}
}
}
Для передачи вставляемых значений используется параметр objects
, который представляет собой массив объектов.
В качестве результата доступны 2 параметра:
affected_rows - Количество вставленных значений
returning - Массив вставленных объектов.
Генерация мутации обновления
значений
Библиотека генерирует мутацию обновления значений по следующему формату:
mutation Test {
test_update(
set: {
is_active: false
}
where: {
is_active: {
_equals: true
}
}
) {
affected_rows
returning {
id
name
}
}
}
Для передачи устанавливаемого значения используется параметр set
, в котором передаются только те значения, которые
необходимо изменить.
В качестве результата доступны 2 параметра:
affected_rows - Количество обновленных значений
returning - Массив обновленных объектов.
Генерация мутации удаления
значений
Библиотека генерирует мутацию удаления записей об объектах по следующему формату:
mutation Test {
test_delete(
where: {
is_active: {
_equals: false
}
}
) {
affected_rows
}
}
Для фильтрации удаления используется параметр where
, который позволяет ограничить удаляемые значения.
В качестве результата можно получить количество удаленных значений, используя поле: affected_rows
Генерация параметров Where/Having
Данные поля могут быть сгенерированы только для следующих полей сущности:
Доступные операторы:
-
_and - Логическое И для дочерних подопераций
-
_or - Логическое ИЛИ для дочерних подопераций
-
_not - Отрицание дочерней подоперации
Для операторов И и ИЛИ указывается массив групп операций. Внутри каждой группы операции объединяются оператором И
. Пример:
Для переданного параметра
where: {
is_active: {
_equals: true
}
_or: [
{
id: {
_equals: 1
}
}
{
id: {
_equals: 2
}
stat: {
_equals: 5
}
}
]
}
будет эквивалентна следующая запись:
is_active = true AND (id = 1 OR (id = 2 AND stat = 5))
Доступные операции:
-
_equals - Операция равенства
. Доступна для всех подходящих полей.
-
_more - Операция >
. Доступна для числовых значений и дат.
-
_more_or_equals - Операция >=
. Доступна для числовых значений и дат.
-
_less - Операция <
. Доступна для числовых значений и дат.
-
_less_or_equals - Операция <=
. Доступна для числовых значений и дат.
-
_like - Операция поиска подстроки. Доступна только для строковых полей.
-
_in - Операция поиска по массиву значений. Доступна для всех полей
-
_between - Операция поиска значений в промежутке. Доступна для числовых значений и дат.
Установка
Для установки достаточно выполнить команду
:
go get -u bitbucket.org/graph-ql-schema/sbuilder
Использование
Для использования библиотеки необходимо импортировать ее в какой либо скрипт:
import "bitbucket.org/graph-ql-schema/sbuilder"
Для генерации API необходимо использовать фабрику генератора:
var loggerFactory = configurable_logger.LoggerFactoryGenerator(false)
var schemaBuilder = sbuilder.NewGraphQlSchemaBuilder(loggerFactory)
После генерации фабрики станет доступн следующий функционал:
type GraphQlSchemaBuilderInterface interface {
RegisterEntity(object *graphql.Object, queries EntityQueries, operations []configurable_logger.LogOperation)
RegisterQuery(key string, field *graphql.Field)
RegisterMutation(key string, field *graphql.Field)
SetServerConfig(config GraphQlServerConfig)
BuildServer() (GraphQlServerInterface, error)
}
Использвоать данный функционал можно следующим образом:
var sqlTestObj = graphql.NewObject(
graphql.ObjectConfig{
Name: "test",
Fields: graphql.Fields{
"id": &graphql.Field{
Type: graphql.ID,
Name: "id",
},
"name": &graphql.Field{
Type: graphql.String,
Name: "name",
},
"active_date": &graphql.Field{
Type: graphql.NewNonNull(graphql.DateTime),
Name: "active_date",
},
"stat": &graphql.Field{
Type: graphql.Int,
Name: "stat",
},
"is_active": &graphql.Field{
Type: graphql.NewNonNull(graphql.Boolean),
Name: "is_active",
},
},
Description: "test entity",
},
)
type TestData struct {
Id int64 `db:"id"`
ActiveDate time.Time `db:"active_from" json:"active_date"`
Name string `db:"name"`
Stat int `db:"stat"`
IsActive bool `db:"is_active" json:"is_active"`
}
func testEntityResolver(params sbuilder.Parameters) (i interface{}, err error) {
sql := ""
if nil != params.Arguments.Where {
sql, err = params.Arguments.Where.ToSQL(params.GraphQlObject, map[string]string{
"active_date": "active_from",
})
if nil != err {
return nil, err
}
}
results := pgsqlTestDataLoad(sql)
return results, nil
}
schemaBuilder.RegisterEntity(sqlTestObj, sbuilder.EntityQueries{
sbuilder.ListQuery: testEntityResolver,
sbuilder.AggregateQuery: func(params sbuilder.Parameters) (i interface{}, err error) {
return nil, nil
},
sbuilder.InsertMutation: func(params sbuilder.Parameters) (i interface{}, err error) {
return nil, nil
},
sbuilder.UpdateMutation: func(params sbuilder.Parameters) (i interface{}, err error) {
return nil, nil
},
sbuilder.DeleteMutation: func(params sbuilder.Parameters) (i interface{}, err error) {
return nil, nil
},
}, nil)
server, err := schemaBuilder.BuildServer()
if nil != err {
log.Fatal(err)
}
log.Fatal(server.Run())
В качестве Web сервера библиотека использует FastHTTP - https://github.com/valyala/fasthttp
Входные параметры для резолвера
type Parameters struct {
Arguments ParsedArguments
Context context.Context
Fields GraphQlRequestedFields
GraphQlObject *graphql.Object
GraphqlParams graphql.ResolveParams
}
Подтипы для ParsedArguments
type ParsedArguments struct {
Objects Objects
Set Set
GroupBy GroupBy
OrderBy []Order
Pagination *Pagination
Where Operation
Having Operation
}
type Object = map[string]interface{}
type Objects = []Object
type Set = map[string]interface{}
type GroupBy = []string
type Order struct {
Priority int `json:"priority"`
By string `json:"by"`
Direction OrderDirection `json:"order"`
}
type Pagination struct {
Limit uint64
Offset uint64
}
type Operation interface {
Type() string
Value() interface{}
Field() string
ToSQL(object *graphql.Object, fieldsMap map[string]string) (string, error)
}
Для операций Where и Having доступна автоматизированная конвертация в SQL. Для этого необходимо использовать:
sql, err = params.Arguments.Where.ToSQL(params.GraphQlObject, nil)
Поля контекста запроса (context.Context)
В контексте передаются следующие поля:
type context struct {
context *fasthttp.RequestCtx
operations []configurable_logger.LogOperation
}
где:
context - Контекст запроса FastHTTP
operations - Корневые операции запроса для каскадного логирования.
Подтипы для GraphQlRequestedFields
Данный тип предназначен для описания запрошенных полей сущности GraphQL
type GraphQlRequestedFieldInterface interface {
GetFieldName() string
HasSubFields() bool
GetSubFields() []GraphQlRequestedFieldInterface
}
type GraphQlRequestedFields = []GraphQlRequestedFieldInterface