В этом блоге мы обсудим, как внедрить Graphql в существующий экспресс-сервер node js с минимальными изменениями.
Часто мы хотели бы интегрировать новую технологию с существующим REST API. Однако в большинстве случаев мы проводим исследования и создаем новый репозиторий, а не повторно используем существующий код и инфраструктуру.
Рассмотрим приведенный ниже пример с простым сервером Express
В этом примере микросервис сохраняет данные в Redis и извлекает информацию о пользователях.
import * as express from 'express' import * as swaggerUi from 'swagger-ui-express' import * as swaggerDocument from './swagger.json' import * as Redis from './utils/redis' import AppRouter from './routes/app.route' const app = express() app.use(express.json()) app.use(Redis.attachRedisClient) app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)) app.use('/api/', AppRouter) app.listen(3000, () => { console.log(`server started on 3000!`) })
У нас есть контроллеры REST, которые добавляют информацию о пользователе в экземпляр Redis. Маршрут / add — это метод POST, позволяющий создать пользователя.
import * as express from 'express' import * as appController from '../controller/app.controller' let router = express.Router() router.post('/add', appController.addUser) router.post('/fetch', appController.getUser) router.get('/health', appController.health) export default router
Добавьте нового пользователя в базу данных, как показано ниже.
Теперь мы хотим использовать GraphQL для получения информации о пользователе. Для этого выполните следующие шаги, чтобы добавить apollo-server в существующий код.
Установите зависимости
Добавьте следующее, чтобы включить промежуточное ПО graphql.
npm install @apollo/server graphql
Сервер apollo имеет промежуточное программное обеспечение Express, которое помогает представить существующий сервис в graphql.
Добавьте expressMiddleware в index.js.
// Graphql Imports import { ApolloServer } from '@apollo/server'; import { expressMiddleware } from '@apollo/server/express4';
Инициализировать сервер apollo, который принимает два параметра
- Определения типов
- Резольверы
Создайте точку входа, чтобы открыть файл graphql.
app.use( '/graphql', cors(), express.json(), expressMiddleware(server, { context: async ({ request, response }) => ({ // Add optional configuration options request: request, response: response, }), }) )
Резолверы и определения типов
Добавьте queryUserDetails и schemaDetails в определения типов; запрос примет один входной объект и вернет ответ пользователя, как показано ниже.
const typeDefs = ` input QueryUserRequest{ id: String! } type UserResponse { id: Int name: String role: String org: String } type QueryUserResponse{ success: Boolean errors: ErrorInfo user: UserResponse } type ErrorInfo{ code:String message:String } type Query { queryUserDetails(request:QueryUserRequest): QueryUserResponse } ` export default typeDefs
Определите преобразователь, ответственный за манипулирование данными.
import { getUser } from '../controller/app.controller' async function queryUserDetails(obj, args, context) { let { request, response } = context request.body = args['request'] return await getUser(request, response) } const resolvers = { Query: { queryUserDetails: queryUserDetails, }, } export default resolvers
Определите интерфейс Typescript следующим образом.
interface UserResponse { success: Boolean user: User errors: Error } interface User { id: String name: String role: String org: String } interface Error { code: String message: String }
Функция getUser будет содержать логику контроллера, которая извлекает информацию о пользователе из базы данных Redis, используя идентификатор пользователя. В приведенном ниже коде объясняется, как обрабатывать все случаи успеха и ошибки.
export async function getUser(request, response) { let result: UserResponse = { success: false, user: null, errors: null, } try { let userResult = await request.redisClient.get(request.body.id) if (userResult == null) { result.errors = { code: '200', message: 'No result', } result.success = true } else { result.user = JSON.parse(userResult) result.success = true } } catch (error) { result.success = true result.errors = { code: '500', message: error.message, } } return result }
Запустите сервер с помощью команды `npm run dev` и перейдите к URL-адресу graphql.
Выполните приведенный ниже запрос, чтобы получить данные пользователя.
query queryUserDetails{ queryUserDetails(request: { id:"1" }) { success errors { code message } user { name org role } } }
Одновременно перейдите на http://localhost:3000/api-docs, где на том же порту работает существующий экспресс-рестарт. Здесь мы можем добавить пользователя, используя оставшийся ресурс, который уже есть.
Это упрощает добавление graphql в текущий код без переделки ресурсов.
Репозиторий кода, используемый в этом блоге, доступен здесь
https://github.com/ganny26/express-apollo-graphql
Преимущества
- Мы можем серверировать как REST, так и GraphQL в одном и том же коде, используя Express.
- Он также поддерживает существующую инфраструктуру и аутентификацию.
Лучшие практики для рассмотрения
Некоторые рекомендации, которым следует следовать, включают плагин `ApolloServerPluginDrainHttpServer`, чтобы обеспечить корректное завершение работы экспресс-сервера.
import { expressMiddleware } from '@apollo/server/express4' import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer' import resolvers from './resolvers/user.resolvers' import typeDefs from './typedefs/typeDefs' import * as http from 'http' const app = express() async function startServer() { const httpServer = http.createServer(app) const server = new ApolloServer({ typeDefs, resolvers, introspection: process.env.NODE_ENV !== 'production', plugins: [ApolloServerPluginDrainHttpServer({ httpServer })], }) await server.start() }
Заключение:
В заключение, этот блог посвящен плавной интеграции GraphQL в установленный сервер Node.js Express с минимальными изменениями. Пожалуйста, дайте мне знать в комментариях, если вы используете другое промежуточное ПО, и я напишу статью об этом.