Backendová část s ExpressJS, GraphQL a MongoDB pro základní aplikaci Todo

Zde je živá verze Glitch. (před změnou udělejte remix)

Frontend část

Obsah

  • Obsah
    • Co je graphql?
    • Úvod
    • Předpoklady instalace
    • Typy GraphQL
    • TodoType
    • RootQueryType
    • Typ mutace
    • Kód lepení
    • Spuštění serveru Express GraphQL
    • Testovací dotazy a mutace
    • Závěr

Co je graphql?

Dotazovací jazyk používaný k definování API, který poskytuje úplný a srozumitelný popis dat a umožňuje výkonné vývojářské nástroje.
Více na Graphql.

Úvod

Toto je backendová část základní TodoApp využívající ExpressJS a GraphQL.
Náš Backend bude používat express-graphql v kombinaci s mongoose a pro server budeme používat ExpressJS.
Pro přístup k živé verzi na Glitch.

Předpoklady instalace

Přejděte do adresáře projektů a zkopírujte a vložte následující příkazy:

mkdir todo-express-graphql && cd todo-express-graphql
npm install cors express express-graphql graphql mongoose

Typy GraphQL

cd todo-express-graphql && mkdir schema && cd schema && touch todo_type.js

TodoType

const mongoose = require('mongoose'); 
const graphql = require('graphql'); //package used to build our graphql schema
const {
  GraphQLObjectType,
  GraphQLID,
  GraphQLInt,
  GraphQLString
} = graphql; //necessary types for defining our schema

const TodoType = new GraphQLObjectType({
  name:  'TodoType',
  fields: () => ({
    id: { type: GraphQLID },
    likes: { type: GraphQLInt },
    content: { type: GraphQLString },
  })
}); 

module.exports = TodoType;

Když definujeme typ pro naše schéma GraphQL, musíme vytvořit instanci GraphQLObjectType a předejte objekt s povinnými poli pro náš typ.

name je jediné povinné pole na GraphQLObjectType .
Některé z nejčastěji používaných vlastností, které pokryjeme později v tomto příspěvku, jsou fields , potřebné k definování atributů, které tento typ řeší, a resolve funkce.
Podívejte se prosím na oficiální dokumentaci graphql týkající se GraphQLObjectType

RootQueryType

const mongoose = require('mongoose');
const graphql = require('graphql');
const { 
  GraphQLObjectType,
  GraphQLList,
  GraphQLID,
  GraphQLNonNull
} = graphql;
const Todo = mongoose.model('todo');
const TodoType = require('./todo_type');

const RootQueryType = new GraphQLObjectType({
  name: 'RootQueryType',
  fields: () => ({
    todos: {
      type: new GraphQLList(TodoType),
      resolve() {
        return Todo.find({});
      }
    },
    todo: {
      type: TodoType,
      args: { id: { type: new GraphQLNonNull(GraphQLID) } },
      resolve(parentValue, { id }) {
        return Todo.findById(id);
      }
    }
  })
});

module.exports = RootQueryType;

RootQueryType má všechny kořenové koncové body potřebné ke spotřebě našeho zdroje úkolů. Zde definujeme todos koncový bod jako odpověď, která bude obsahovat seznam TodoType dokumenty pomocí GraphQLList(TodoType) . Další je naše todo koncový bod používaný pro načítání a
jeden úkol z naší databáze.

GraphQLNonNull se používá, protože se potřebujeme ujistit, že naše id přijatý jako parametr dotazu není nedefinovaný.

resolve(parentValue, { id }) první argument, který funkce resolve obdrží, je parentValue nebo root, což je hodnota předaná z jiných typů. Tento argument umožňuje vnořenou povahu dotazů GraphQL.
Druhým argumentem je objekt se skutečnými parametry dotazu.

Na express-graphql je hezké, že vždy očekává, že bude vrácen slib z funkce resolveru a použití mongoose se integruje
opravdu hladce.
Více o resolverech z dokumentace ApolloGraphQL.

MutationType

Mutace se obvykle používají ke změně dat z naší databáze a můžete vidět, že jsou velmi podobné našemu RootQueryType , kromě toho, že nyní měníme data na základě parametrů dotazu.


const graphql = require('graphql');
const { GraphQLObjectType, GraphQLString, GraphQLID } = graphql;
const mongoose = require('mongoose');
const Todo = mongoose.model('todo');
const TodoType = require('./todo_type');

const mutation = new GraphQLObjectType({
  name: 'MutationType',
  fields: {
    addTodo: {
      type: TodoType,
      args: {
        content: { type: GraphQLString }
      },
      resolve(parentValue, { content }) {
        return (new Todo({ content })).save()
      }
    },
    likeTodo: {
      type: TodoType,
      args: { id: { type: GraphQLID } },
      resolve(parentValue, { id }) {
        return Todo.like(id);
      }
    },
    deleteTodo: {
      type: TodoType,
      args: { id: { type: GraphQLID } },
      resolve(parentValue, { id }) {
        return Todo.remove({ _id: id });
      }
    },
    updateTodo: {
      type: TodoType,
      args: { id: { type: GraphQLID }, content: { type: GraphQLString }  },
      resolve(parentValue, { id, content }) {
        return Todo.update({ _id: id }, { content });
      }
    },
  }
});

module.exports = mutation;

Kód lepení

const graphql = require('graphql');
const { GraphQLSchema } = graphql;

const query = require('./root_query_type');
const mutation = require('./mutations');

module.exports = new GraphQLSchema({
  query,
  mutation
});

Ve většině případů, kdy budete psát soubory schématu, budete muset předat objekt se dvěma klíči:query a mutation . Docela jednoduché a přímočaré, stačí importovat potřebné mutace a dotazy
a předat je jako objekt GraphQLSchema .

Více o GraphQLSchema

Spuštění serveru Express GraphQL


const express = require('express');
const expressGraphQL = require('express-graphql');
const mongoose = require('mongoose');

const todoModel = require('./models/todo');
const bodyParser = require('body-parser');
const schema = require('./schema');
const cors = require('cors')
const app = express();
app.use(cors());

const MONGO_URI = 'your mLab link';
if (!MONGO_URI) {
  throw new Error('You must provide a MongoLab URI');
}

mongoose.Promise = global.Promise;
mongoose.connect(MONGO_URI);
mongoose.connection
    .once('open', () => console.log('Connected to MongoLab instance.'))
    .on('error', error => console.log('Error connecting to MongoLab:', error));  

app.use(bodyParser.json());
app.use('/graphql', expressGraphQL({
  schema, //pass the schema to our middleware 
  graphiql: true //enable graphiql interface so we can test our queries and mutations before starting to use it.
}));

app.get('/', (req, res) => {
  res.redirect('/graphql');
});

app.listen(4000, () => {
  console.log('Listening at 4000');
});

Testovací dotazy a mutace

Když musíte vytvořit dotaz a nevíte, jak přesně ho napsat
pak graphiql pomůže https://apollo-graphql-todo.glitch.me/graphql.
Jednou ze schopností GraphQL je okamžitá dokumentace. Poté, co jsme definovali typy, které se budou používat v našem GraphQLSchema máme připravenou dokumentaci. Stačí přejít na https://apollo-graphql-todo.glitch.me/graphql a vpravo nahoře najdete Docs .

Psaní dotazů v graphiql:

query{
  todos{
    id
    likes
    content
  }
}

Tento dotaz bude spuštěn na našem RootQueryType a todos
pole bude převedeno na seznam TodoTypes . TodoType obsahuje
id , likes , content jako vlastnosti a protože máme seznam, dostaneme zpět odpověď, která vypadá takto:

{
  "data": {
    "todos": [
      {
        "id": "5c5c21184c9edc006857c11b",
        "likes": 17,
        "content": ""
      },
      {
        "id": "5c5c26e84c9edc006857c124",
        "likes": 4,
        "content": "asd"
      },
      {
        "id": "5c5c29b296f75b0068f3b9db",
        "likes": 0,
        "content": "asdad"
      },
      {
        "id": "5c5c29c296f75b0068f3b9dc",
        "likes": 0,
        "content": "eq123"
      }
    ]
  }
}

Jako cvičení zkuste upravit Přidat, Upravit a Smazat úkol.

Závěr

Express-graphql je skvělý nástroj pro vývoj backendů, které potřebují podporovat GraphQL, a nyní jsme viděli, jak snadno jej lze integrovat s MongoDB. Nyní máme malý příklad toho, jak byste mohli implementovat některé základní dotazy a mutace.

Doufám, že se vám tento článek líbil.