Создавать API весело! Особенно, когда вы можете использовать современные технологии, такие как Koa, GraphQL и MongoDB.
Koa – это фреймворк Node, точно так же, как и Express является фреймворком Node. Мы заменим Express на Koa, так как Koa использует синтаксис async/await вместо “коллбэков”.
Заметка; Если вы новичок в API, я рекомендую прочитать эту книгу, чтобы начать работу.
Начинаем
Необходимые условия для создания нашего API:
- Node установлен
- Текстовый редактор (я использую код Visual Studio)
- Терминал
- Браузер
Если у вас есть все, что вам нужно, продолжайте – если нет, пожалуйста, установите их.
Откройте свой терминал и создайте проект node, например, такой:

Итак, мы создали папку нашего проекта и инициализировали новый проект Node. Теперь у нас есть доступные пакеты NPM, которые мы можем использовать для установки Koa, Mongo и GraphQL.
Давайте установим коа с NPM.
npm i koa
Запустить новый сервер Koa просто. Все, что нам нужно – это файл server.js со следующим содержимым:
const Koa = require('koa');
const app = new Koa();
app.listen(9000);
app.on('error', err => {
log.error('server error', err)
});Начать проект с Node:

Установка GraphQL
Нам нужны два пакета для настройки GraphQL с Koa: koa-mount и koa-graphql
npm i koa-mount koa-graphql
GraphQL требует, чтобы мы передали нашу исходную схему на сервер GraphQL. Давайте создадим один.
Мы помещаем схему graphQL в graphql/schema.js
const { buildSchema } = require('graphql');
const schema = buildSchema(`
type Query {
hello: String
}
`);
module.exports = schema;Мы передаем наш начальный Query функции buildSchema.
app.use(mount('/graphql', graphqlHTTP({
schema: schema,
graphiql: true
})))Примечание: аргумент для buildSchema является литералом шаблона.
Теперь мы можем передать исходную схему на наш сервер GraphQL:
const mount = require('koa-mount');
const graphqlHTTP = require('koa-graphql');
const schema = require('./graphql/schema')Не забудьте импортировать koa-mount, koa-graphql и, наконец, schema.js.
И затем, если мы перейдем к localhost:9000/graphql:

Вуаля! Начальная настройка завершена. Пока она не очень полезна – в идеале, мы хотели бы запросить GraphQL, чтобы сохранить данные в нашей MongoDB и прочитать их оттуда.
Настройка MongoDB
Чтобы читать и писать с помощью GraphQL, нам нужно место для чтения. Здесь Mongo как раз и пригодится. Мы будем сохранять и читать наши данные оттуда.
Чтобы упростить ситуацию, мы будем использовать облачный экземпляр для Mongo. Зайдите на mlab.com и создайте базу данных пользователей и монго.
Создание базы данных MongoDB



После того, как вы создали базу данных, вам потребуется пользователь для базы данных.
Создание пользователя MongoDB
Нажмите на вкладку пользователей и создайте новое имя пользователя с паролем.

Теперь вы можете использовать mongoDB в паре с Mongoose. Удаленный URL для вашей базы данных будет выглядеть примерно так:
MongoDB: //: @ ds213615.mlab.com: 13615 / КоА-graphql
Установка mongoose
npm i mongoose
Создание файла database.js
Мы создаем специальный файл для подключения к базе данных:
const mongoose = require('mongoose');
const initDB = () => {
mongoose.connect(
'mongodb://indrek:graphql1@ds213615.mlab.com:13615/koa-graphql',
{ useNewUrlParser: true }
);
mongoose.connection.once('open', () => {
console.log('connected to database');
});
}
module.exports = initDB;Примечание. Убедитесь, что вы используете имя пользователя и учетные данные для своей базы данных.
Этот блок кода попытается подключиться к удаленному MongoDB..
Откройте server.js и require и запросите метод initDB.
const initDB = require('./database');
initDB();Если мы все сделали правильно, наша консоль должна сообщить нам, что мы подключились успешно.

Браво!
Заметьте, как досадно постоянно обновлять сервер? Давайте решим это с помощью пакета pm2.
PM2 – это менеджер производственных процессов для приложений Node.js со встроенным балансировщиком нагрузки. Это позволяет вам поддерживать приложения в актуальном состоянии, перезагружать их без простоев и облегчать общие задачи системного администратора.
npm install pm2 -g
Добавьте скрипт с именем start в наш package.json:
"scripts": {
"start": "pm2 start server.js"
},
Pm2 работает в фоновом режиме, что освобождает наш терминал. Если вы когда-нибудь захотите остановить процесс, просто запустите pm2 kill. Теперь нам не нужно постоянно перезагружать наш сервер, pm2 делает это автоматически.
Примечание: pm2 logs возвращает выражения журнала консоли на терминал.
Модели MongoDB
Если вы когда-либо работали с Mongo, вы знаете, что MongoDB позволяет нам создавать модели для наших данных. Это отличный способ структурировать наши данные.
Создайте папку для моделей MongoDB и внутри файла gadgets.js:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
/*
notice there is no ID. That's because Mongoose will assign
an ID by default to all schemas
*/
const GadgetSchema = new Schema({
name: String,
release_date: Date,
by_company: String,
price: Number,
});
module.exports = mongoose.model('Gadget', GadgetSchema);Примечание. В нашей схеме нет поля идентификатора. Это потому, что Mongoose назначит идентификатор по умолчанию для всех схем.
Отлично, теперь давайте добавим коллекцию и несколько фиктивных данных. Название коллекции должно отображать имя нашего гаджета во множественном числе, в данном случае gadgets.

После создания коллекции вставьте документ в формате JSON следующим образом:

Это все для Mongo, теперь давайте получим данные с помощью GraphQL.
Запросы GraphQL
GraphQL также требует от нас создания типов (наподобие инструкций для компьютеров).
graphql/gadgetType.js
const graphql = require('graphql');
const { GraphQLObjectType, GraphQLString } = graphql;
const GadgetType = new GraphQLObjectType({
name: 'Gadget',
fields: () => ({
})
});
module.exports = GadgetType;Обратите внимание, что мы создали тип graphql. Внутри полей мы можем указать свойства данного типа.
const graphql = require('graphql');
const { GraphQLObjectType, GraphQLObjectType } = graphql;
const GadgetType = new GraphQLObjectType({
name: 'Gadget',
fields: () => ({
id: { type: GraphQLString },
name: { type: GraphQLString },
release_date: { type: GraphQLString },
by_company: { type: GraphQLString },
price: { type: GraphQLString }
})
});
module.exports = GadgetType;Обратите внимание на типы GraphQLObjectType и GraphQLObjectType, которые мы деконструируем из graphQL. Это примитивные типы для graphQL.
Создание типов GraphQL также предоставляет подсказки типов, которые мы будем использовать при создании наших запросов.
Последнее, что нам нужно сделать – это рефакторинг нашего schema.js. Мы хотим запросить гаджет по id.
Импортируйте модель Gadget, gadgetGraphQLType graphql типа и GraphQLSchema, GraphQLObjectType, GraphQLString из graphQL в schema.js.
const { GraphQLSchema, GraphQLObjectType, GraphQLString} = require('graphql');
const gadgetGraphQLType = require('./gadgetType');
const Gadget = require('../models/gadget');Далее нам нужен корневой запрос. Каждый запрос GraphQL начинается с фигурных скобок {} – это корневой запрос.
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
}
})Вуаля! Внутри полей мы можем указать gadget запрос.
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
gadget: {
type: gadgetGraphQLType,
args: { id: { type: GraphQLString }},
resolve(parent, args) {
return Gadget.findById(<a href="http://args.id" class="link link-url" target="_blank" rel="external nofollow noopener noreferrer">args.id</a>)
}
}
}
})Обратите внимание на три свойства внутри запроса гаджета:
- тип – это тип запроса, в данном случае gadgetGraphQLType.
- аргументы – мы можем предоставить аргументы для запросов graphql, например: gadgets (id: “1”)
- решение – как мы хотим разрешить запрос? Что должно произойти после выполнения запроса? Здесь мы возвращаем модель гаджета по id.
И наконец, экспортируйте.
module.exports = new GraphQLSchema({
query: RootQuery
});Файл schema.js должен выглядеть следующим образом.
const { GraphQLSchema, GraphQLObjectType, GraphQLString} = require('graphql');
const gadgetGraphQLType = require('./gadgetType');
const Gadget = require('../models/gadget');
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
gadget: {
type: gadgetGraphQLType,
args: { id: { type: GraphQLString }},
resolve(parent, args) {
return Gadget.findById(<a href="http://args.id" class="link link-url" target="_blank" rel="external nofollow noopener noreferrer">args.id</a>)
}
}
}
})
module.exports = new GraphQLSchema({
query: RootQuery
});Теперь зайдите на http://localhost:9000/graphql и сделайте запрос.
{
gadget(id: "5c4e188efb6fc05326ad9264") {
name
price
by_company
release_date
id
}
}Это то, что мы должны в конечном итоге:

Спасибо за чтение! ❤
