Начнем с официального определения GraphQL:
GraphQL — это язык запросов для API и среда выполнения для выполнения этих запросов с вашими существующими данными. GraphQL предоставляет полное и понятное описание данных в вашем API, дает клиентам возможность запрашивать именно то, что им нужно, и ничего больше, упрощает постепенное развитие API и предоставляет мощные инструменты для разработчиков.
В этой статье мы увидим, что такое GraphQL, преимущества использования GraphQL путем создания простого сервера GraphQL с Spring Boot и MongoDB, а также его преимущества по сравнению с реализацией REST.
С приведенным выше официальным определением мы можем понять следующие пункты
- Это язык запросов для API и среда выполнения для выполнения запросов.
- Он также предоставляет полное описание данных API, что помогает клиенту извлекать данные по мере необходимости.
GraphQL позволяет нам определять структуру и формат данных, которые нам нужно получить, а также позволяет запрашивать несколько моделей в одном запросе.
Схема GraphQL будет определена в файле с расширением «.graphqls», который содержит типы Schema, Query, Mutation, Object.
Как GraphQL устраняет недостатки REST API:
- GraphQL предоставляет потребителям возможность запрашивать атрибуты по мере необходимости, т. е. предоставляет динамические данные в запросе. Ответ REST API всегда фиксирован, так как он отправляет весь объект JSON для каждого запроса.
- REST API имеет проблемы с избыточной и недостаточной выборкой.
- Лучшая производительность с меньшим количеством кода.
- GraphQL предоставляет единую конечную точку для всех операций с запросами и мутациями, а также метод HTTP POST. В REST каждая операция имеет отдельный API, использующий разные HTTP-глаголы (GET, PUT, POST, DELETE) в соответствии с требованиями.
- GraphQL зависит от файла схемы, определенного для приложения. Потребителям будут доступны только свойства или операции, указанные в файле схемы.
Схема GraphQL:
Схема представляет GraphQL API с точки зрения операций запроса и мутации, а также их типов и свойств.
schema { query : GadgetQuery mutation: GadgetMutation }
Тип запроса:
Тип запроса — это корневой тип в схеме GraphQL, используемый для создания запроса на получение данных с сервера GraphQL. Он обычно используется для определения операций только для чтения (GET). Давайте рассмотрим пример приложения галереи гаджетов. Тип запроса можно использовать для определения набора операций, как показано ниже.
Примечание. Массив или список объектов обозначаются парой квадратных/круглых скобок, например: [Гаджет] и восклицательный знак указывают на его обязательное/обязательное свойство.
Выбрать гаджет по GadgetId
Выбрать все гаджеты
Выбрать гаджеты по категориям
Выбрать доступные гаджеты по категориям
## Root type type GadgetQuery { application : String gadget(gadgetId : String!) : GadgetResponse allGadgets : [GadgetResponse]! }
Тип мутации:
Тип мутации — это еще один корневой тип в схеме GraphQL, используемый для определения операций по управлению данными (POST, PUT, DELETE). Давайте рассмотрим тот же пример приложения галереи гаджетов. Тип мутации можно использовать для определения операций, как показано ниже.
type GadgetMutation { persistGadgetData(gadgetInput : GadgetInput) : GadgetResponse }
Тип объекта:
Тип объекта используется для определения определяемых пользователем типов (класс в Java/Kotlin) со свойствами и типами данных, используемыми в качестве параметра ввода/вывода для выполнения операций с типами запросов и мутаций, как определено в файле схемы.
Пример.Тип гаджета можно определить в файле схемы, как показано ниже.
Примечание: восклицательный знак указывает на обязательный/обязательный параметр. например: Строка!
type Gadget { gadgetId: String! gadgetName: String! gadgetCategory: String gadgetAvailability: Boolean! gadgetPrice: Float! }
Резолверы GraphQL:
- GraphQLQueryResolver:
Это один из основных преобразователей, используемых для разрешения операций типа Query. Он действует как отправная точка для всех операций только для чтения, определенных в приложении (файле схемы).
GadgetQueryResolver реализует GraphQLQueryResolver и обеспечивает реализацию операций запросов, определенных в файле схемы. Spring сканирует структуру пакета на наличие bean-компонентов распознавателя и вызывает правильный метод, объявленный в файле схемы.
class GadgetQueryResolver : GraphQLQueryResolver {...}
- GraphQLMutationResolver:
Это еще один основной преобразователь, используемый для разрешения операций типа Mutation. Он действует как отправная точка для всех операций изменения данных, определенных в файле схемы GraphQL (т. е. операций POST, PUT и DELETE).
Класс GadgetMutationResolver реализует GraphQLMutationResolver и предоставляет реализацию для всех методов изменения, определенных в файле схемы.
class GadgetMutationResolver : GraphQLMutationResolver {...}
- GraphQLResolver:
Он действует как универсальный преобразователь для всех других типов (настраиваемых пользовательских типов) в файле схемы GraphQL. Это особенно используется, когда у нас есть несколько классов моделей, связанных друг с другом некоторыми сопоставлениями. Для определения типа используются дженерики.
class PhoneTypeResolver : GraphQLResolver<Phone> {...}
Сервер GraphQL: практический пример
Технологии/инструменты:
IDE: IntelliJ (STS/Eclipse)
Kotlin: 1.4.x
GraphQL и GraphiQL: 5.xx
Инструмент сборки: Maven
Spring Boot: 2.4.x
База данных: сервер MongoDB (или любая другая база данных — H2 или MySQL)
Spring Boot + MongoDB + Kotlin config
Добавьте ниже зависимости GraphQL Maven
<dependencies> ... <!-- Enable GraphQL servlet-mapping at URI - '/graphql' --> <dependency> <groupId>com.graphql-java-kickstart</groupId> <artifactId>graphql-spring-boot-starter</artifactId> <version>5.7.0</version> </dependency> <!-- GraphQL UI at '/graphiql' by default - GraphQL testing --> <dependency> <groupId>com.graphql-java-kickstart</groupId> <artifactId>graphiql-spring-boot-starter</artifactId> <version>5.5.0</version> </dependency> <dependency> <groupId>com.graphql-java-kickstart</groupId> <artifactId>graphql-java-tools</artifactId> <version>5.4.1</version> </dependency> ... </dependencies>
Конфигурация приложения — application.yml
Здесь мы переопределяем URL-адрес graphiql по умолчанию с «graphiql» на «gadget-ui» и предоставляем конфигурацию MongoDB.
## Server port server: port: 9997 ## Graphiql Mapping graphiql: mapping: gadget-ui ## MongoDB configuration (optional - if not provided spring boot takes default values) spring: data: mongodb: host: localhost port: 27017 database: srsgadgetdb
Репозиторий Mongo — для подключения сервера MongoDB
@Repository interface GadgetRepository : MongoRepository<Gadget?, String?> { }
Давайте посмотрим полную схему GraphQL для приложения галереи гаджетов «gadget.graphqls», помещенного в путь к классам проекта.
schema { query : GadgetQuery mutation: GadgetMutation } ## Root type type GadgetQuery { application : String gadget(gadgetId : String!) : GadgetResponse allGadgets : [GadgetResponse]! } ## Root type type GadgetMutation { persistGadgetData(gadgetInput : GadgetInput) : GadgetResponse } type Gadget { gadgetId: String! gadgetName: String! gadgetCategory: String gadgetAvailability: Boolean! gadgetPrice: Float! } type GadgetResponse { gadgetId: String! gadgetName: String! gadgetCategory: String gadgetAvailability: Boolean! gadgetPrice: Float! } input GadgetInput { gadgetName: String! gadgetCategory: String gadgetAvailability: Boolean! gadgetPrice: Float! }
Коллекция гаджетов и детали документа с набором свойств
@Document(collection = "Gadget") data class Gadget( @Id val gadgetId: String? = null, var gadgetName: String? = null, var gadgetCategory: String? = null, var gadgetAvailability: Boolean? = true, var gadgetPrice: Double? = null )
GadgetQueryResolver:
В этом классе мы предоставляем реализации для операций, определенных в файле схемы для корневого типа запроса.
@Component class GadgetQueryResolver : GraphQLQueryResolver { @Autowired var gadgetRepository: GadgetRepository? = null fun application() : String { return "Welcome to GraphQL with Kotlin and MongoDB...!" } fun getGadget(gadgetId: String): GadgetResponse? { var gadget = gadgetRepository?.findById(gadgetId)?.get() return mapGadgetToGadgetResponse(gadget) } fun getAllGadgets(): List<GadgetResponse?>? { return getGadgetResponse(gadgetRepository?.findAll() as List<Gadget>) } private fun getGadgetResponse(gadgetList: List<Gadget>): List<GadgetResponse>? { val gadgetResponseList: MutableList<GadgetResponse> = ArrayList() gadgetList.stream().forEach { gadget: Gadget -> gadgetResponseList.add(mapGadgetToGadgetResponse(gadget)) } return gadgetResponseList } private fun mapGadgetToGadgetResponse (gadget : Gadget?) : GadgetResponse { var gadgetResponse = GadgetResponse() gadgetResponse.gadgetId = gadget?.gadgetId gadgetResponse.gadgetName = gadget?.gadgetName gadgetResponse.gadgetCategory = gadget?.gadgetCategory gadgetResponse.gadgetPrice = gadget?.gadgetPrice gadgetResponse.gadgetAvailability = gadget?.gadgetAvailability return gadgetResponse; } }
GadgetMutationResolver:
В этом классе мы предоставляем реализации для операций, определенных в файле схемы для типа Mutation.
@Component class GadgetMutationResolver : GraphQLMutationResolver { @Autowired var gadgetRepository: GadgetRepository? = null fun persistGadgetData(persistGadget: GadgetInput): GadgetResponse { val saveGadgetData = Gadget() saveGadgetData.gadgetName = persistGadget.gadgetName saveGadgetData.gadgetCategory = persistGadget.gadgetCategory saveGadgetData.gadgetPrice = persistGadget.gadgetPrice saveGadgetData.gadgetAvailability = persistGadget.gadgetAvailability val persistedGadget: Gadget? = gadgetRepository?.save(saveGadgetData) return mapGadgetToGadgetResponse(persistedGadget) } private fun mapGadgetToGadgetResponse (gadget : Gadget?) : GadgetResponse { var gadgetResponse = GadgetResponse() gadgetResponse.gadgetId = gadget?.gadgetId gadgetResponse.gadgetName = gadget?.gadgetName gadgetResponse.gadgetCategory = gadget?.gadgetCategory gadgetResponse.gadgetPrice = gadget?.gadgetPrice gadgetResponse.gadgetAvailability = gadget?.gadgetAvailability return gadgetResponse; } }
GraphQL — тестирование приложения-гаджета:
По умолчанию сопоставление сервлета GraphQL будет следующим:
http://localhost:9997/graphiql
Пользовательский URL-адрес на основе конфигурации, предоставленной в файле application.yml: http://localhost:9997/gadget-ui
Тестирование изменения гаджета:
Тестирование запросов гаджета:
Проверьте базу данных MongoDB для коллекции гаджетов, где мы можем найти 3 документа, как показано ниже:
Вот и все. Надеюсь, эта статья помогла вам начать работу с GraphQL. В этой статье мы начали с основ GraphQL и того, как GraphQL можно использовать для реализации запросов и мутаций, на примере сохранения и чтения данных из MongoDB.
Полный код приведенного выше примера можно найти на GitHub.
Официальная документация GraphQL: