В этом блоге мы обсудим, как внедрить 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.

http://localhost:3000/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 с минимальными изменениями. Пожалуйста, дайте мне знать в комментариях, если вы используете другое промежуточное ПО, и я напишу статью об этом.