
Node.js + Angular: лучшие практики для бесшовной интеграции API GraphQL
20 июня 2025 г.Современные приложения для полного стека часто используют фронта JavaScript, такие как Angular, и бэкэнд, построенный с Node.js. Эти слои общаются через API, и GraphQL является популярным выбором для того, чтобы сделать эти API более гибкими.
С GraphQL угловой клиент запрашивает именно те данные, которые ему нужны, в то время как сервер Node.js извлекает эти данные из баз данных или других сервисов. Поскольку схема GraphQL разделяется между фронталом и бэкэнд, фронт может развиваться независимо. Клиент отправляет на сервер запросы graphQL или мутации, и сервер обрабатывает их с помощью функций резолей. Этот подход избегает создания многочисленных фиксированных конечных точек REST и позволяет Frontend извлекать только конкретные поля, которые в нем нуждаются.
Аутентификация
Общим методом для обеспечения запросов является использование JWT (JSON Web Token). После входа пользователя бэкэнд выпускает JWT. Angular App должно сохранить этот токен и включать его с каждым запросом GraphQL. Например, это можно сделать с помощью Apollo Angular'ssetContext
промежуточное программное обеспечение:
const auth = setContext((_, { headers }) => {
const token = localStorage.getItem('token');
return token ? { headers: { Authorization: `Bearer ${token}` } } : {};
});
const httpLink = new HttpLink({ uri: 'http://localhost:4000/graphql' });
apollo.create({ link: auth.concat(httpLink), cache: new InMemoryCache() });
Этот код прикрепляет авторизацию: носитель <token> к каждому запросу, когда пользователь входит в систему. На стороне Node.js функция контекста Apollo Server может читать и проверять этот токен по каждому запросу. Например:
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => {
const token = req.headers.authorization || '';
const user = verifyJwt(token); // your function to verify the JWT
return { user };
}
});
Затем резолюры могут проверить Context.user. Если Context.user отсутствует или недействителен, вы должны отклонить запрос. Лучшая практика - бросить GraphQlerror с четким кодом. Например:
if (!context.user) {
throw new GraphQLError('Not authenticated', {
extensions: { code: 'UNAUTHENTICATED' }
});
}
Использование конкретных кодов, таких как несаутентированные или запрещенные, помогает угловому клиенту. Вы также можете проверить Context.user на роли или разрешения и бросить GraphQlerror с кодом.
CORS (перекрестный обмен ресурсами)
Если Angular App и Node Server работают на разных доменах или портах, браузеры блокируют запросы по умолчанию. Чтобы разрешить запросы, включите COR на сервере. В экспресс -настройке вы можете использовать промежуточное программное обеспечение CORS:
const cors = require('cors');
app.use(cors()); // Allow all origins (for development only)
Эта строка позволяет любому происхождению доступ к API. В производстве вы должны ограничить это своим фактическим доменом фронт-энда. Например:
app.use(
'/graphql',
cors({ origin: 'http://localhost:4200', credentials: true }),
express.json(),
expressMiddleware(server)
);
Эта конфигурация только позволяет запросам отhttp: // localhost: 4200Достигните конечную точку /graphql. Учетные данные: True Option означает, что файлы cookie или автозаголов разрешены. С точки зрения угловой стороны, если бы вы использовали файлы cookie для аутентификации, вы бы установили с Credentials: True в ссылке HTTP. Однако, поскольку мы посылаем JWT в заголовках, как показано выше, вам обычно не нужны файлы cookie или credentials.
Обработка ошибок в GraphQL
GraphQL отличается от отдыха: он всегда возвращает200 ОКСтатус http, даже если есть ошибки. Ошибки появляются в полезной нагрузке. Лучшая практика - использовать структурированные объекты ошибки с кодами. Apollo Server автоматически присваивает коды, но вы также можете бросить пользовательские ошибки.
Например:
const { GraphQLError } = require('graphql');
if (args.value < 0) {
throw new GraphQLError('Value must be non-negative', {
extensions: { code: 'BAD_USER_INPUT', argumentName: 'value' }
});
}
Это даст ответ с ошибкой, такой как:
"errors": [
{
"message": "Value must be non-negative",
"extensions": {
"code": "BAD_USER_INPUT",
"argumentName": "value"
}
}
]
Включение расширений. Код помогает угловому клиенту точно знать, что пошло не так, например, показ проверки сообщения. На стороне клиента вы обрабатываете ошибки GraphQL в своих вызовах Apollo.
Например:
this.apollo.watchQuery({ query: GET_DATA }).valueChanges.subscribe({
next: ({ data, errors }) => {
// data contains the result; errors contains any GraphQL errors
},
error: (networkError) => {
console.error('Network error:', networkError);
}
});
В этом коде ошибки возникают в следующем обратном вызове, а сетевые или другие низкоуровневые ошибки возникают в обратном вызове ошибки. Использование чистых кодов ошибок, таких как несаутентированные для проблем с аудиторией или BAD_USER_INPUT для плохого ввода, помогает правильно обрабатывать каждый случай.
Оптимизация производительности
Одной из общих неэффективности в GraphQL является проблема «n+1 запросов», когда резольвер может сделать вызов базы данных для каждого элемента в списке. FacebookDataLoaderБиблиотека является популярным решением для партии и кэширования этих вызовов.
Например:
const DataLoader = require('dataloader');
const userLoader = new DataLoader(async (ids) => {
return await UserModel.find({ id: { $in: ids } });
});
const server = new ApolloServer({
typeDefs,
resolvers,
context: () => ({ loaders: { user: userLoader } })
});
В ваших резолюрах используйте context.loaders.user.load (userId) вместо того, чтобы напрямую запросить базу данных. DataLoader будет разыграть несколько вызовов (...) для разных идентификаторов в один запрос находки. Это сокращает избыточные запросы базы данных и повышает производительность.
Другие советы по производительности включают:
- Кэширование ответа:Apollo Server может кэш -запрос приводит к памяти или внешнему хранилищу, чтобы ускорить повторные запросы.
- Автоматические сохраняемые запросы:Эта функция отправляет только идентификатор запроса вместо полного текста GraphQL, уменьшая полезную нагрузку сети.
- Ограничения сложности запроса:Используйте библиотеки, такие как график-глубины или график, чтобы предотвратить очень глубокие или дорогие запросы.
- Кэширование на стороне клиента:Кэш в памяти Apollo в угловой кости сохраняет извлеченные данные, поэтому компоненты могут повторно использовать его без переиздания.
Комбинирование партии (с DataLoader), кэширование и ограничение запросов делают ваше приложение быстрее и масштабируемым.
Заключение
Все вместе, Node.js, Angular и GraphQL создают чистое, но мощное решение для полного стека. Server Node.js GraphQL - это всего лишь одна конечная точка, которая скрывает сложность бэкэнд. Сервер может ограничить доступ с помощью аутентификации, политик CORS и обработки структурированных ошибок. Угловой клиент с клиентом Apollo делает запросы и обновления простыми, используя преимущества кэширования и обновления в реальном времени из коробки. Разработчики фронта пишут богатые запросы и мутации, не беспокоясь о конечных точках отдыха или чрезмерной поглощении.
Ключевые лучшие практики:
- Jwt аутентификация: Поместите JWT в заголовок авторизации по всем запросам.
- Включить CORS с умом: Позвольте только исходным приложениям вашего углового приложения получить доступ к API.
- Структурированные ошибки:Бросьте GraphQlerror с четкими расширениями, значениями кода.
- Оптимизированная загрузка данных:Используйте DataLoader и Apollo Caching для пакетных запросов и данных кэша.
Следуя этой практике, ваш код будет более безопасным, оптимизированным и обслуживаемым.
Оригинал