paint-brush
Когда пришло время дать REST отдохнутьк@johnjvester
2,364 чтения
2,364 чтения

Когда пришло время дать REST отдохнуть

к John Vester13m2024/05/13
Read on Terminal Reader

Слишком долго; Читать

В этой статье сравниваются API-интерфейсы GraphQL и REST для извлечения данных, демонстрируя, насколько гибкость и эффективность GraphQL превосходны в сложных сценариях. В нем подробно описывается развертывание Apollo Server с Heroku и анонсируется предстоящий контент по аутентификации и данным в реальном времени в GraphQL.
featured image - Когда пришло время дать REST отдохнуть
John Vester HackerNoon profile picture
0-item
1-item


За годы создания сервисов RESTful API был моим основным выбором. Однако даже несмотря на то, что у REST есть свои преимущества, это не означает, что это лучший подход для каждого варианта использования. За прошедшие годы я понял, что иногда для определенных сценариев могут существовать лучшие альтернативы. Придерживаться REST только потому, что он мне нравится (когда он мне не подходит), приводит только к технологическому долгу и натянутым отношениям с владельцем продукта.


Одна из самых больших болевых точек подхода RESTful — необходимость делать несколько запросов для получения всей необходимой информации для принятия бизнес-решения.


В качестве примера предположим, что мне нужен обзор клиента на 360 градусов. Мне нужно будет сделать следующие запросы:


  • GET /customers/{some_token} предоставляет базовую информацию о клиенте.
  • GET /addresses/{some_token} предоставляет необходимый адрес.
  • GET /contacts/{some_token} возвращает контактную информацию.
  • GET /credit/{some_token} возвращает ключевую финансовую информацию.


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


В этой статье я покажу, почему GraphQL является предпочтительным подходом по сравнению с RESTful API, демонстрируя, как развернуть сервер Apollo (и Apollo Explorer), чтобы быстро приступить к работе с GraphQL.


Я планирую создать свое решение с помощью Node.js и развернуть его в Heroku.

Когда использовать GraphQL вместо REST

Существует несколько распространенных случаев использования, когда GraphQL является лучшим подходом, чем REST:


  • Когда вам нужна гибкость в способе получения данных: вы можете получать сложные данные из различных ресурсов, но все в одном запросе . (Я расскажу об этом пути в этой статье.)
  • Когда команде внешнего интерфейса необходимо часто совершенствовать пользовательский интерфейс: быстрое изменение требований к данным не потребует от серверной части корректировки конечных точек и возникновения блокировок.
  • Если вы хотите свести к минимуму избыточную или недостаточную выборку : иногда REST требует, чтобы вы обратились к нескольким конечным точкам, чтобы собрать все необходимые вам данные (недостаточная выборка), или попадание в одну конечную точку возвращает гораздо больше данных, чем вам действительно нужно (чрезмерная выборка). выборка).
  • Когда вы работаете со сложными системами и микросервисами: иногда нескольким источникам просто нужно использовать один уровень API для своих данных. GraphQL может обеспечить такую гибкость посредством одного вызова API .
  • Если вам нужны данные в реальном времени: GraphQL предлагает подписки , которые обеспечивают обновления в реальном времени. Это полезно в случае приложений чата или потоков данных в реальном времени. (Я расскажу об этом преимуществе более подробно в следующей статье.)

Что такое сервер Apollo?

Поскольку мои навыки работы с GraphQL еще не отточены, для этой статьи я решил использовать Apollo Server .


Apollo Server — это сервер GraphQL, который работает с любой схемой GraphQL. Цель — упростить процесс создания API GraphQL. Базовый дизайн хорошо интегрируется с такими платформами, как Express или Koa. В моей следующей статье я рассмотрю возможность использования подписок (через библиотекуgraphql-ws ) для получения данных в реальном времени.


В чем Apollo Server действительно хорош, так это в Apollo Explorer, встроенном веб-интерфейсе, который разработчики могут использовать для изучения и тестирования своих API-интерфейсов GraphQL. Студия мне подойдет идеально, так как позволяет легко создавать запросы и просматривать схему API в графическом формате.

Вариант использования «Мой клиент 360»

В этом примере предположим, что нам нужна следующая схема, чтобы обеспечить обзор клиента на 360 градусов:


 type Customer { token: String name: String sic_code: String } type Address { token: String customer_token: String address_line1: String address_line2: String city: String state: String postal_code: String } type Contact { token: String customer_token: String first_name: String last_name: String email: String phone: String } type Credit { token: String customer_token: String credit_limit: Float balance: Float credit_score: Int }


Я планирую сосредоточиться на следующих запросах GraphQL:


 type Query { addresses: [Address] address(customer_token: String): Address contacts: [Contact] contact(customer_token: String): Contact customers: [Customer] customer(token: String): Customer credits: [Credit] credit(customer_token: String): Credit }


Потребители предоставят токен Клиенту, которого они хотят просмотреть. Мы ожидаем также получить соответствующие объекты Address, Contact и Credit. Цель состоит в том, чтобы избежать четырех разных вызовов API для всей этой информации, а не делать один вызов API.

Начало работы с сервером Apollo

Я начал с создания новой папки под graphql-server-customer на моей локальной рабочей станции. Затем, используя раздел «Начало работы» документации Apollo Server, я выполнил первый и второй шаги, используя машинописный подход.


Затем я определил свою схему, а также включил некоторые статические данные для тестирования. Обычно мы подключаемся к базе данных, но для этой демонстрации вполне подойдут статические данные.


Ниже мой обновленный файл index.ts :


 import { ApolloServer } from '@apollo/server'; import { startStandaloneServer } from '@apollo/server/standalone'; const typeDefs = `#graphql type Customer { token: String name: String sic_code: String } type Address { token: String customer_token: String address_line1: String address_line2: String city: String state: String postal_code: String } type Contact { token: String customer_token: String first_name: String last_name: String email: String phone: String } type Credit { token: String customer_token: String credit_limit: Float balance: Float credit_score: Int } type Query { addresses: [Address] address(customer_token: String): Address contacts: [Contact] contact(customer_token: String): Contact customers: [Customer] customer(token: String): Customer credits: [Credit] credit(customer_token: String): Credit } `; const resolvers = { Query: { addresses: () => addresses, address: (parent, args, context) => { const customer_token = args.customer_token; return addresses.find(address => address.customer_token === customer_token); }, contacts: () => contacts, contact: (parent, args, context) => { const customer_token = args.customer_token; return contacts.find(contact => contact.customer_token === customer_token); }, customers: () => customers, customer: (parent, args, context) => { const token = args.token; return customers.find(customer => customer.token === token); }, credits: () => credits, credit: (parent, args, context) => { const customer_token = args.customer_token; return credits.find(credit => credit.customer_token === customer_token); } }, }; const server = new ApolloServer({ typeDefs, resolvers, }); const { url } = await startStandaloneServer(server, { listen: { port: 4000 }, }); console.log(`Apollo Server ready at: ${url}`); const customers = [ { token: 'customer-token-1', name: 'Acme Inc.', sic_code: '1234' }, { token: 'customer-token-2', name: 'Widget Co.', sic_code: '5678' } ]; const addresses = [ { token: 'address-token-1', customer_token: 'customer-token-1', address_line1: '123 Main St.', address_line2: '', city: 'Anytown', state: 'CA', postal_code: '12345' }, { token: 'address-token-22', customer_token: 'customer-token-2', address_line1: '456 Elm St.', address_line2: '', city: 'Othertown', state: 'NY', postal_code: '67890' } ]; const contacts = [ { token: 'contact-token-1', customer_token: 'customer-token-1', first_name: 'John', last_name: 'Doe', email: '[email protected]', phone: '123-456-7890' } ]; const credits = [ { token: 'credit-token-1', customer_token: 'customer-token-1', credit_limit: 10000.00, balance: 2500.00, credit_score: 750 } ];


Когда все настроено как положено, мы запускаем следующую команду для запуска сервера:


 $ npm start


Поскольку сервер Apollo работал на порту 4000, я использовал URL-адрес http://localhost:4000/ для доступа к Apollo Explorer. Затем я создал следующий пример запроса:


 query ExampleQuery { addresses { token } contacts { token } customers { token } }


Вот как это выглядит в Apollo Explorer:


Нажав кнопку «Пример запроса» , я убедился, что полезная нагрузка ответа соответствует статическим данным, которые я предоставил в index.ts :


 { "data": { "addresses": [ { "token": "address-token-1" }, { "token": "address-token-22" } ], "contacts": [ { "token": "contact-token-1" } ], "customers": [ { "token": "customer-token-1" }, { "token": "customer-token-2" } ] } }


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

Развертывание сервера Apollo в Heroku

Поскольку эта статья посвящена чему-то новому, я хотел посмотреть, насколько сложно будет развернуть мой сервер Apollo на Heroku.


Я знал, что мне нужно устранить различия в номерах портов при локальной работе и работе где-то в облаке. Я обновил свой код для запуска сервера, как показано ниже:


 const { url } = await startStandaloneServer(server, { listen: { port: Number.parseInt(process.env.PORT) || 4000 }, });


В этом обновлении мы будем использовать порт 4000, если в переменной среды не указано значение PORT.


Используя Gitlab, я создал новый проект для этих файлов и вошел в свою учетную запись Heroku, используя интерфейс командной строки (CLI):


 $ heroku login


Вы можете создать новое приложение в Heroku с помощью интерфейса командной строки или веб-интерфейса панели управления Heroku. В этой статье мы будем использовать CLI:


 $ heroku create jvc-graphql-server-customer


Команда CLI вернула следующий ответ:


 Creating ⬢ jvc-graphql-server-customer... done https://jvc-graphql-server-customer-b62b17a2c949.herokuapp.com/ | https://git.heroku.com/jvc-graphql-server-customer.git


Команда также автоматически добавила репозиторий, используемый Heroku в качестве удаленного:


 $ git remote heroku origin


По умолчанию Apollo Server отключает Apollo Explorer в производственных средах. Для моей демо-версии я хочу оставить ее работающей на Heroku. Для этого мне нужно установить переменную среды NODE_ENV для разработки. Я могу установить это с помощью следующей команды CLI:


 $ heroku config:set NODE_ENV=development


Команда CLI вернула следующий ответ:


 Setting NODE_ENV and restarting ⬢ jvc-graphql-server-customer... done, v3 NODE_ENV: development


Теперь мы можем развернуть наш код в Heroku:


 $ git commit --allow-empty -m 'Deploy to Heroku' $ git push heroku


Быстрый просмотр панели управления Heroku показывает, что мой сервер Apollo работает без каких-либо проблем:


Если вы новичок в Heroku, это руководство покажет вам, как создать новую учетную запись и установить Heroku CLI.

Критерии приемки соблюдены: пример «Мой клиент 360»

С помощью GraphQL я могу удовлетворить критериям приемлемости для моего варианта использования Customer 360 с помощью следующего запроса:


 query CustomerData($token: String) { customer(token: $token) { name sic_code token }, address(customer_token: $token) { token customer_token address_line1 address_line2 city state postal_code }, contact(customer_token: $token) { token, customer_token, first_name, last_name, email, phone }, credit(customer_token: $token) { token, customer_token, credit_limit, balance, credit_score } }


Все, что мне нужно сделать, это передать одну переменную token клиента со значением customer-token-1 :


 { "token": "customer-token-1" }


Мы можем получить все данные, используя один вызов API GraphQL:


 { "data": { "customer": { "name": "Acme Inc.", "sic_code": "1234", "token": "customer-token-1" }, "address": { "token": "address-token-1", "customer_token": "customer-token-1", "address_line1": "123 Main St.", "address_line2": "", "city": "Anytown", "state": "CA", "postal_code": "12345" }, "contact": { "token": "contact-token-1", "customer_token": "customer-token-1", "first_name": "John", "last_name": "Doe", "email": "[email protected]", "phone": "123-456-7890" }, "credit": { "token": "credit-token-1", "customer_token": "customer-token-1", "credit_limit": 10000, "balance": 2500, "credit_score": 750 } } }


Ниже приведен снимок экрана Apollo Explorer, запущенного из моего приложения Heroku:


Заключение

Я вспоминаю, как в начале своей карьеры Java и C# конкурировали друг с другом за принятие разработчиками. Сторонники каждой стороны дебатов были готовы доказать, что выбранная ими технология была лучшим выбором… даже если это было не так.


В этом примере мы могли бы реализовать мой вариант использования Customer 360 несколькими способами. Использование проверенного RESTful API могло бы сработать, но для получения всех необходимых данных потребовалось бы несколько вызовов API. Использование Apollo Server и GraphQL позволило мне достичь своих целей с помощью одного вызова API.


Мне также нравится, как легко развернуть мой сервер GraphQL в Heroku с помощью всего лишь нескольких команд в моем терминале. Это позволяет мне сосредоточиться на реализации — разгрузить инфраструктуру и передать свой код доверенному стороннему поставщику. Самое главное, это полностью соответствует моей личной миссии:


«Сосредоточьте свое время на предоставлении функций/функциональность, которые увеличивают ценность вашей интеллектуальной собственности. Используйте платформы, продукты и услуги для всего остального».

– Дж. Вестер


Если вас интересует исходный код этой статьи, он доступен на GitLab .


Но подождите… это еще не все!


В моем следующем посте мы продолжим дорабатывать наш сервер GraphQL, чтобы реализовать аутентификацию и получение данных в реальном времени с помощью подписок.


Хорошего дня!