Введение:
Все чаще слышу об использовании GraphQL, но так как последнее время все рабочее время уходило на Xamarin + GRPC + ASP.NET Core, технология казалась для меня загадочно манящей и очень не известной, потому решил опробовать ее на нескольких языках, чтобы увидеть какие плюсы и минусы в разных подходах. Начать решил с родного и любимого C# + Hot Chocolate, но планирую так же попробовать Typescript + Prisma, Kotlin + graphql-kotlin, и возможно что-то другое.
Что будем делать:
Посмотрев несколько обзорных видео и почитав доклады, очень заинтересовала федерация схем и единый шлюз для сервисов, потому в статье я опишу создание вымышленного сервиса, который будет предоставлять доступ к информации о какой-нибудь киновселенной, и создам шлюз на Hot Chocolate, из которого будет доступен этот сервис. В следующих статьях, сервисы на других языках будут подключаться к этому шлюзу, если не найдется лучшей альтернативы, на языке из статьи “спойлер”(найдется, Hot Chocolate хорош, но в других языках поддержка graphQL реализована интереснее)
Подготовка проекта:
Я буду использовать для проекта Rider + .Net Core 6 + Postgres в Docker, и первой киновселенной у нас будет вселенная Джеймса Бонда, создаем свежий солюшен и добавляем туда первый проект.
Добавляем проект
Требуемые nuget-пакеты
Теперь создадим 3 сущности:
- Бонд
- Режиссер
- Фильм
Сущности
Настроим DbContext, понимаю, что это будет выглядеть не эстетично с точки зрения нейминга, стараюсь настраивать модели правильно, но сейчас статья не совсем об этом:)
DbContext
Прописываем строку для подключения, создаем и выполняем миграцию
Так выглядит структура нашей базы
Hot Chocolate:
Возможно вам уже известно, но на всякий случай расскажу еще раз, в GraphQL есть 3 основных блока:
- Queries(запросы) — используются непосредственно для получения данных, и могут быть ассоциированы с буквой R из всем известного CRUD
- Mutations(мутации) — используются для создания, изменения и удаления данных остальные буквы из всем известного CRUD
- Subscriptions(подписки) — это можно сказать события, при изменении, каких-то данных вы можете сообщить об этом своим подписчикам
Начнем с Query:
В Program.cs добавляем сервис “GraphQLServer” и добавляем созданный нами Query-класс.
Также давайте сразу “замаппим” GraphQL, по умолчанию в Hot Chocolate маппинг происходит на адрес “/graphql”, но мне больше нравится путь “/api”.
Добавляем поддержку Query
Теперь давайте перейдем в класс Query, и добавим щепотку магии:)
Мы добавляем сущности которые мы хотим получить, а также добавим комментарии, и включим их генерации в проекте.
Это самая простая реализация запросов для GraphQL
Если сейчас запустить наш сервис, и перейти, по данному url, мы увидим, что у нас появились все наши запросы, а также документация, которая была взята из комментариев в коде.
Так выглядят наши запросы GraphQL
Но если сейчас выполнить запрос, то он будет максимально скучный, мы можем выбрать только всех обитателей одной из таблиц, но не можем фильтровать или еще как-то ограничивать данные, но Hot Chocolate позволяет нам также добавить и это достаточно простым способом, в волшебном пакете HotChocolate.Data, есть несколько атрибутов которые позволяют нам не писать вручную фильтрации, сортировки и прочее, а просто пометив запрос одним из атрибутов, добавить эти возможности, атрибутов множество, но я добавлю и расскажу только о нескольких из них.
Вешаем атрибуты на требуемый метод:
Говорим GraphQL, что мы используем эти возможности
Что же делают эти атрибуты:
-
[UseFiltering]
Добавляет возможность благодаря where фильтровать запрос практически как душе угодно. -
[UseSorting]
Добавляет возможность сортировки данных в вашем запросе. -
[UseProjection]
Добавляет оптимизацию запроса, чтобы сгенерированный SQL не тащил из базы данных все подряд, а только требуемые данные.
Если сейчас открыть запустить наш API, то мы увидим, что появились новые возможности:
И для примера такой запрос GraphQL преобразуется в такой запрос SQL
На этом закончим с Query и перейдем к Mutation
Mutation:
добавляем и регистрируем класс Mutation, как мы делали с Query
C мутациями к сожалению, в hot chocolate чуть посложнее, чем с запросами, потому придется написать чуть больше кода, код будет минимально возможный для операций, потому сильно не пинайте если не понравится, мне он тоже не нравится:) Но сейчас мы говорим не о EF
Базовый код для Mutation
Если теперь запустить наш проект, мы увидим добавленные нами мутации:
А теперь последнее в нашем списке, это подписки. С подписками все так же просто как и с остальным:)
Subscriptions:
С подписками повторяем наш путь из прошлых реализаций, добавляем класс Subscription, регистрируем его, и для нашего примера добавим операции с подписками в памяти, также нам нужно указать использование WebSockets:
Обновления в Program.cs
Теперь давайте добавим подписку на добавление нового Джеймса Бонда,
для этого нам нужен атрибут Subscribe, который как раз говорит нам о том, что это подписка, и в параметрах нам нужен атрибут EventMessage, который сообщает нам о типе сообщения из события.
Наша новая подписка
Ну и осталось самое малое, в методе, который должен нам сообщать о событии, нужно добавить его отправку.
Для этого добавим в параметры этого метода
ITopicEventSender sender
, пометив его атрибутом [Service]
, и вызовем в нем отправку, передав имя нашего события, и требуемый параметр:
Наша новая подписка
Давайте запустим, и убедимся что подписка появилась:
Gateway:
Tеперь давайте добавим шлюз, чтобы можно было из одной точки получить доступ ко всем нашим сервисам, добавляем новый проект, c такими же параметрами как и у прошлого:
Создаем новый проект в том же решении
В этот проект добавляем пару nuget-пакетов
И написать совсем немного кода, на данном этапе будет вообще одностраничник, мы добавляем новый HttpClient, указываем его имя (вынес в константы) и адрес, и потом после добавления GraphQLServer добавляем удаленную схему также указывая ее:
Изменения в Program.cs
Понимаю, что данная статья к сожалению не интерактивна, потому тем кому интересно оставляю ссылку на свой GitHub, где буду публиковать улучшения этого проекта, а так же GraphQL примеры на других языках: