Реализация GraphQL на чистой архитектуре Golang
Чистая архитектура - одна из самых популярных архитектур в программировании. Он известен своим хорошим разделением между каждым слоем. Каждому слою не нужно знать о реализации другого слоя, поэтому мы можем легко изменить реализацию, не внося изменений на другом уровне. Если вы хотите узнать больше о чистой архитектуре, вы можете прочитать ее здесь, потому что я не буду подробно объяснять это в этом посте.
Сегодня я хочу попробовать реализовать GraphQL в коде моего друга о чистой архитектуре в Golang, вы можете прочитать его замечательный пост Пробуем чистую архитектуру на Golang. В этом посте автор использует REST API в качестве уровня доставки, теперь я попытаюсь добавить еще уровень HTTP, который использует GraphQL.
GraphQL
Что такое GraphQL? По определению с их сайта:
GraphQL - это язык запросов для API и среда выполнения для выполнения этих запросов с вашими существующими данными. GraphQL предоставляет полное и понятное описание данных в вашем API, дает клиентам возможность запрашивать именно то, что им нужно, и не более того, упрощает развитие API с течением времени и предоставляет мощные инструменты разработчика.
Другими словами, GraphQL - это язык запросов, позволяющий Клиенту получать только то, что они просят, без получения неиспользуемых данных. Итак, если у нас есть объект статьи, подобный этому:
{ "id": "article-id", "title": "Indonesia won the award of best clean air of South East Asia", "author": "Kurio" }
И клиенту нужно только поле title
, сервер вернет только:
{ "title": "Indonesia won the award of best clean air of South East Asia" }
Схема GraphQL
Чтобы начать использовать GraphQL, нам нужно определить нашу схему на основе нашего слоя Model
и Usecase
. Итак, на основе этого github у нас есть структура статьи:
Мы можем сделать тип статьи в нашей схеме GraphQL следующим образом:
На GraphQL по умолчанию 5 скалярных типов, а это:
- Int
- Плавать
- Нить
- Логический
- ID
Благодаря этому мы можем сопоставить наши типы данных Golang string
и int64
со скалярными типами String
и Int
на GraphQL. Для типа Time
на Golang GraphQL поддерживает создание пользовательских скалярных типов, поэтому нам нужно определить Time
скалярные типы в схеме, которую мы написали.
После создания типа объекта нам нужно создать Query
и Mutation
для схемы GraphQL. Эти 2 типа будут созданы на основе Usecase
интерфейса чистого кода архитектуры, вот код интерфейса usecase
:
В чем разница между Query
и Mutation
в GraphQL? Для краткости Query
используется для извлечения данных, а Mutation
используется для изменения или создания данных на сервере. Итак, на основе usecase
интерфейса мы можем написать запрос и мутацию следующим образом:
Вы, должно быть, спрашиваете,
Подождите, что такое ArticlesResult в строке FetchArticle? Раньше в схеме типов не было типа ArticlesResult! Почему бы вместо этого просто не вернуть список статей?
В функции FetchArticle
нам нужна функция разбивки на страницы и курсора, поэтому мы не сможем получить все статьи по одному запросу. В GraphQL есть стандартный тип для реализации разбивки на страницы, на основе этой страницы нам нужно создать соединение (край) и информацию (pageInfo) текущего объекта, и именно поэтому нам нужно создать объект ArticlesResult
. Вот тип схемы для ArticlesResult
:
Тип Edge
будет иметь cursor
с типом String
и node
с типом Article
. курсор - это значение соединения для текущей статьи с соседней статьей. Мы можем получить следующую статью с этим значением cursor
.
Тип PageInfo
будет иметь endCursor
с типом String
и hasNextPage
с типом Boolean
. endCursor
- это значение последнего курсора текущих ребер, поэтому мы можем получить следующие ребра с этим значением. hasNextPage
будет нашим флагом независимо от того, будет ли у этого списка краев следующая страница или нет.
Тип ArticlesResult
будет иметь тип edges
с массивом типа Edge
, pageInfo
с типом PageInfo
и totalCount
с типом Int
. totalCount
будет иметь значение общего количества элементов текущих ребер.
Все типы GraphQL (объект, мутация и схема) могут быть записаны в одном файле, поэтому вот файл schema.graphql
:
Погрузитесь в GraphQL Go
После того, как схема уже определена, нам нужно преобразовать ее в код Голанга. Для этого урока мы будем использовать пакет graphql. Я решил использовать этот пакет из-за его модульности, поэтому мы можем использовать его с нашей архитектурой чистого кода.
Преобразование схемы типа объекта
Во-первых, нам нужно создать объект GraphQL на основе нашей схемы, вот код:
Подготовка резолвера
Чтобы иметь возможность использовать пакетную функцию распознавателя, нам нужно создать функцию, которая реализует FieldResolveFn
. Мы можем просто создать функцию для каждого резолвера, но на этот раз мы создадим интерфейс, который будет иметь все функции Query
и Mutation
из схемы, чтобы его можно было инициировать с введенным уровнем сервиса статьи (и более легким тестированием).
Создание конструктора схемы
Нам нужно будет создать объект GraphQL со всем явно написанным типом. Я имею в виду, что мы должны создать объект для Mutation
с объявленными UpdateArticle
, StoreArticle
и DeleteArticle
. Предыдущий преобразователь будет внедрен в схему объекта GraphQL, чтобы иметь возможность использовать его метод. Вот код:
Реализация резолвера
Не забудьте написать реализацию интерфейса Resolver
. Мы создадим внутреннюю структуру, которая реализует все необходимые методы интерфейса, а также введем уровень сервиса статьи, чтобы мы могли получить доступ к данным статьи.
Почему бы нам просто не внедрить слой репозитория статей напрямую? Это связано с тем, что мы рассматриваем преобразователь как еще один уровень доставки, уровень доставки не может напрямую обращаться к уровню репозитория, поэтому нам нужно использовать уровень сервиса.
- FetchArticle
- UpdateArticle
Я думаю, что будет хорошей практикой написать другую реализацию самостоятельно, чтобы вы могли изучить, какие еще варианты есть в пакете. Но в целом код будет выглядеть так:
Инициализация доставки GraphQL
И на последнем этапе нам нужно инициализировать нашу доставку GraphQL в файле main.go
. Просто измените файл, как этот:
Мы используем пакет https://github.com/graphql-go/handler для создания обработчика HTTP GraphQL и передачи обработчика в функцию echo
WrapHandler, но если вы не хотите его использовать, вы можете создать свой собственный обработчик следуя правилам https://graphql.org/learn/serving-over-http/.
Теперь у нашей go-clean-arch уже есть еще один уровень доставки, который использует GraphQL, просто запустите свое приложение и получите доступ к нему по пути /graphql
. У нас также будет пользовательский интерфейс GraphiQL, чтобы попробовать запрос GraphQL.
Надеюсь, это руководство поможет вам понять GraphQL и полезность чистой архитектуры в Golang.
Вы можете увидеть полный код из моего Github здесь:
Удачного дня!
Благодарим Иман Туморанг за архитектуру чистого кода на Голанге, Бастиан Паскаль Ситуморанг, Резу Индру, Нугрохо Кахионо из Kurio, которые помогли мне реализовать GraphQL в Golang 😎