Начать работу с Apollo, Express и MongoDB
В этой статье мы будем настраивать сервер Apollo GraphQL с помощью Express и сохранять данные с помощью MongoDB.
Создайте экземпляр MongoDB
Наша первая задача - установить соединение с экземпляром MongoDB. Если у вас нет готовой к использованию MongoDB, вы можете создать экземпляр одним из трех следующих методов.
- Установите MongoDB на свой компьютер
- Используйте Докер
- Используйте Атлас
После настройки убедитесь, что вы записали строку подключения - мы будем использовать ее позже.
Инициализировать проект
Нам нужна среда для разработки сервера. Я предполагаю, что вы используете Node.js версии 12 или новее. Мы будем использовать Babel для транскомпиляции кода. Старые версии могут работать, но я их не тестировал.
Создайте новый каталог для проекта. Войдите в каталог и инициализируйте новое приложение.
$ mkdir ~/graphql-server $ cd ~/graphql-server $ npm init -y
Теперь нам нужно установить наши зависимости.
$ npm i -D nodemon @babel/cli @babel/core @babel/node @babel/preset-env $ npm i apollo-server-express express mongoose
Создайте несколько базовых моделей и схем
Мы будем использовать Mongoose для моделирования наших данных и взаимодействия с MongoDB. А пока мы создадим две модели: одну для Author
и одну для Book
.
./models/Author.js
import mongoose from ‘mongoose’ export const Author = mongoose.model(‘Author’, { name: String })
./models/Book.js
import mongoose from 'mongoose' export const Book = mongoose.model('Book', { name: String, pages: Number })
Нам нужна схема Apollo, чтобы указать запросы, которые будут доступны для выполнения клиентами.
Эта схема описана в приведенном ниже файле как typeDefs
, определяя набор типов и их взаимосвязей, и как resolvers
, которые подключаются к данным, соответствующим типам схемы (typeDefs
) при обработке клиентских запросов. На данный момент, пока мы просто пытаемся заставить все работать, мы определим запрос, который возвращает статическое сообщение. Вскоре мы разберемся с моделями.
./schema/index.js
import { gql } from 'apollo-server-express' const typeDefs = gql` type Query { message: String! } ` const resolvers = { Query: { message: () => 'hello world', }, } export { typeDefs, resolvers }
Создайте и запустите сервер
Сервер Express довольно стандартный. Единственное, что здесь следует отметить, это то, что мы хотим убедиться, что соединение Mongoose было установлено, прежде чем принимать какие-либо соединения.
Для этого я оборачиваю выражение ожидания в асинхронную функцию. Замените mongodb://localhost:27017/test
строкой подключения MongoDB, которую вы сохранили ранее.
./index.js
import { ApolloServer } from 'apollo-server-express' import express from 'express' import mongoose from 'mongoose' import { typeDefs, resolvers } from './schema' const start= async () => { const app = express() const server = new ApolloServer({ typeDefs, resolvers }) server.applyMiddleware({ app }) await mongoose.connect('mongodb://localhost:27017/test', { useNewUrlParser: true }) app.listen({ port: 4000 }, () => console.log( `listening: http://localhost:4000${server.graphqlPath}` ) ) } start()
Мы добавим сценарий запуска в package.json
файл.
... "scripts": { "start": "nodemon --exec babel-node index.js" }, ...
Для запуска сервера нам также понадобится .babelrc
файл, иначе он будет жаловаться на то, что мы импортируем модули.
./.babelrc
{ "presets": ["@babel/preset-env"] }
Теперь мы готовы запустить сервер.
$ npm start
Протестируйте конечную точку
Пока для переменной среды NODE_ENV
не задано значение production, у вас будет GraphQL Playground (графическая интерактивная IDE GraphQL в браузере), автоматически обслуживающая графический интерфейс для веб-браузеров.
Откройте в браузере http://localhost:4000/graphql
.
Вы можете вводить запросы (с автозаполнением) на левой панели. Нажмите кнопку воспроизведения, и результат отобразится на правой панели.
Добавить мутации
Теперь мы подключим наш преобразователь к базовым моделям, предоставив доступ к ним через сервер. Мы используем тип Query
для реализации read
операций.
Для реализации операций записи нам нужно использовать тип Mutation
. Первым аргументом функции Mutation
является родительский элемент, и он не используется в этом примере.
./schema/index.js (обновлено)
import { gql } from 'apollo-server-express' import { Author } from '../models/Author' import { Book } from '../models/Book' const typeDefs = gql` type Query { message: String! authors: [Author!]! books: [Book!]! } type Author { id: ID! name: String! } type Book { id: ID! name: String! pages: Int } type Mutation { createAuthor(name: String!): Author! createBook(name: String!, pages: Int): Book! } ` const resolvers = { Query: { message: () => 'hello world', authors: () => Author.find(), books: () => Book.find() }, Mutation: { createAuthor: async (_, { name }) => { const author = new Author({ name }); await author.save(); return author; }, createBook: async (_, { name, pages }) => { const book = new Book({ name, pages }); await book.save(); return book; } } } export { typeDefs, resolvers }
После сохранения файла сервер автоматически перезагружается (благодаря nodemon), и изменения можно наблюдать в браузере (для автозаполнения требуется обновление).
Это базовая настройка сервера GraphQL, готовая для экспериментов и дальнейшей разработки. Я поставил ссылку на весь код, используемый ниже.
Я буду использовать этот пример в других статьях, чтобы обсудить
- Добавление отношений
- Аутентификация, авторизация и охрана