IVY DOM


 

人生就像一副复杂拼图
每个人总有属於自己的记忆碎片
优质美国空间-老薛主机|IVY DOM|Flowline|

联系我

RSS




九月 11, 2017

使用Node.js+Docker+GraphQL+MongoDB构建服务

用了GraphQL之后,就不想再用RESTful了。

本文将使用Node.js+Docker+GraphQL+MongoDB构建一个具有CRUD功能的完整微服务。

运行代码,需要安装docker和docker-compose。

完整代码见:leinue/node-mongodb-graphql-docker

注:阅读本文需要有GraphQL基础。

Docker

dockerfile

<code class="language-text">FROM node

WORKDIR /app

EXPOSE 5555
</code>

从node构建,将工作目录设置为/app,暴露5555端口

docker-compose

<code class="language-text">version: "3"
services:
  user_service:
    build: .
    links: 
      - user_db
    command: ["node", "index.js", ' &amp;&amp; /bin/bash']
    hostname: user_service_in_container
    volumes:
      - ./:/app
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure
    ports:
      - "5555:5555"
  user_db:
    image: mongo
    volumes:
      - "/tmp/db:/data/db"
    restart: always
</code>

声明了以下任务:

  1. 声明user_service服务和user_db服务
  2. user_service:
    1. 从当前目录的dockerfile构建
    2. 与user_db连接
    3. 在启动时执行node index.js和/bin/bash
    4. 挂载当前目录到/app目录下
    5. 复制一份
    6. 在失败时重启
    7. 暴露容器内的5555端口到宿主机的5555端口
  3. user_db
    1. 从mongo构建
    2. 将容器内的/data/db挂载到宿主机上的/tmp/db上(数据持久化)
    3. 总是重启

运行命令

<code class="language-powershell"><span class="n">docker-compose</span> <span class="n">up</span> <span class="n">-d</span>
</code>

实现代码

使用babel编译为ES6代码

事实上现在的node v8已经支持大部分ES6代码了,但是async仍不支持,为了使用async不得不使用babel编译。

.babelrc

<code class="language-js"><span class="p">{</span>
    <span class="s2">"presets"</span><span class="o">:</span> <span class="p">[</span><span class="s2">"es2015"</span><span class="p">],</span>
    <span class="s2">"plugins"</span><span class="o">:</span> <span class="p">[</span><span class="s2">"syntax-async-generators"</span><span class="p">,</span> <span class="s2">"transform-async-generator-functions"</span><span class="p">,</span> <span class="s2">"transform-regenerator"</span><span class="p">]</span>
<span class="p">}</span>
</code>

需要的babel包

<code class="language-text">{
    "babel-plugin-syntax-async-generators": "^6.13.0",
    "babel-plugin-transform-async-generator-functions": "^6.24.1",
    "babel-plugin-transform-regenerator": "^6.26.0"
    "babel-core": "^6.26.0",
    "babel-polyfill": "^6.26.0",
    "babel-preset-es2015": "^6.24.1",
}
</code>

安装之后创建index.js

<code class="language-js"><span class="nx">require</span><span class="p">(</span><span class="s1">'babel-core/register'</span><span class="p">);</span>
<span class="nx">require</span><span class="p">(</span><span class="s2">"babel-polyfill"</span><span class="p">);</span>
<span class="nx">require</span><span class="p">(</span><span class="s1">'./server.js'</span><span class="p">);</span>
</code>

这样就可以在server.js中使用es6的代码了。

server.js

server.js用来初始化graphql服务器、路由和连接mongodb。这里使用koa和graphql服务端的插件来初始化。

<code class="language-js"><span class="kr">import</span> <span class="nx">koa</span> <span class="nx">from</span> <span class="s1">'koa'</span><span class="p">;</span> <span class="c1">// koa@2</span>
<span class="kr">import</span> <span class="nx">koaRouter</span> <span class="nx">from</span> <span class="s1">'koa-router'</span><span class="p">;</span> <span class="c1">// koa-router@next</span>
<span class="kr">import</span> <span class="nx">koaBody</span> <span class="nx">from</span> <span class="s1">'koa-bodyparser'</span><span class="p">;</span> <span class="c1">// koa-bodyparser@next</span>
<span class="kr">import</span> <span class="p">{</span> <span class="nx">graphqlKoa</span><span class="p">,</span> <span class="nx">graphiqlKoa</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">'apollo-server-koa'</span><span class="p">;</span>
<span class="kr">import</span> <span class="nx">cors</span> <span class="nx">from</span> <span class="s1">'koa-cors'</span><span class="p">;</span>
<span class="kr">import</span> <span class="nx">convert</span> <span class="nx">from</span> <span class="s1">'koa-convert'</span><span class="p">;</span>
<span class="kr">import</span> <span class="nx">configs</span> <span class="nx">from</span> <span class="s1">'./configs'</span><span class="p">;</span>

<span class="kr">import</span> <span class="nx">mongoose</span> <span class="nx">from</span> <span class="s1">'mongoose'</span><span class="p">;</span>

<span class="kr">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">koa</span><span class="p">();</span>
<span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">koaRouter</span><span class="p">();</span>

<span class="kr">const</span> <span class="nx">db</span> <span class="o">=</span> <span class="nx">mongoose</span><span class="p">.</span><span class="nx">createConnection</span><span class="p">([</span><span class="s1">'mongodb://'</span><span class="p">,</span> <span class="nx">configs</span><span class="p">.</span><span class="nx">mongodb</span><span class="p">.</span><span class="nx">ip</span><span class="p">,</span> <span class="s1">'/'</span><span class="p">,</span> <span class="nx">configs</span><span class="p">.</span><span class="nx">mongodb</span><span class="p">.</span><span class="nx">dbname</span><span class="p">].</span><span class="nx">join</span><span class="p">(</span><span class="s1">''</span><span class="p">));</span>

<span class="k">if</span><span class="p">(</span><span class="nx">db</span><span class="p">)</span> <span class="p">{</span>
	<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'mongodb connected successfully'</span><span class="p">);</span>
	<span class="nx">global</span><span class="p">.</span><span class="nx">db</span> <span class="o">=</span> <span class="nx">db</span><span class="p">;</span>
<span class="p">}</span><span class="k">else</span> <span class="p">{</span>
	<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'mongodb connected failed'</span><span class="p">);</span>
<span class="p">}</span>

<span class="kr">import</span> <span class="nx">schemaRouters</span> <span class="nx">from</span> <span class="s1">'./routers/schemaRouters'</span><span class="p">;</span>

<span class="kr">const</span> <span class="nx">schemas</span> <span class="o">=</span> <span class="nx">schemaRouters</span><span class="p">().</span><span class="k">default</span><span class="p">;</span>

<span class="nx">router</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s1">'/graphql'</span><span class="p">,</span> <span class="nx">koaBody</span><span class="p">(),</span> <span class="nx">graphqlKoa</span><span class="p">({</span> <span class="nx">schema</span><span class="o">:</span> <span class="nx">schemas</span><span class="p">.</span><span class="nx">HelloSchema</span> <span class="p">}));</span>
<span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">'/graphql'</span><span class="p">,</span> <span class="nx">graphqlKoa</span><span class="p">({</span> <span class="nx">schema</span><span class="o">:</span> <span class="nx">schemas</span><span class="p">.</span><span class="nx">HelloSchema</span> <span class="p">}));</span>

<span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">'/graphiql'</span><span class="p">,</span> <span class="nx">graphiqlKoa</span><span class="p">({</span> <span class="nx">endpointURL</span><span class="o">:</span> <span class="s1">'/graphql'</span> <span class="p">}));</span>

<span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">convert</span><span class="p">(</span><span class="nx">cors</span><span class="p">(</span><span class="nx">configs</span><span class="p">.</span><span class="nx">cors</span><span class="p">)));</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">router</span><span class="p">.</span><span class="nx">routes</span><span class="p">());</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">router</span><span class="p">.</span><span class="nx">allowedMethods</span><span class="p">());</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="nx">configs</span><span class="p">.</span><span class="nx">port</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
	<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'app started successfully, listening on port '</span> <span class="o">+</span> <span class="nx">configs</span><span class="p">.</span><span class="nx">port</span><span class="p">);</span>
<span class="p">});</span>
</code>

这段初始化代码将/graphql作为graphql数据收发的路由地址,服务将启动在5555端口。

构建MongoDB数据类型

<code class="language-js"><span class="kr">import</span> <span class="p">{</span> <span class="nx">Schema</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">'mongoose'</span><span class="p">;</span>

<span class="kd">var</span> <span class="nx">helloSchema</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Schema</span><span class="p">({</span>
  <span class="nx">email</span><span class="o">:</span>  <span class="nb">String</span><span class="p">,</span>
  <span class="nx">lastIP</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span>
<span class="p">});</span>

<span class="kr">export</span> <span class="k">default</span> <span class="nx">global</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nx">model</span><span class="p">(</span><span class="s1">'Hello'</span><span class="p">,</span> <span class="nx">helloSchema</span><span class="p">);</span>
</code>

初始化一个helloSchema,并将这个model命名为hello

还需要一个index.js将数据类型全部引入:

<code class="language-js"><span class="kr">import</span> <span class="nx">HelloModel</span> <span class="nx">from</span> <span class="s1">'./HelloModel'</span>

<span class="kr">export</span> <span class="k">default</span> <span class="p">{</span>
	<span class="nx">HelloModel</span><span class="p">,</span>
<span class="p">}</span>
</code>

构建GraphQL Schema

一个schema需要分成三部分:

  1. mutations
    1. 修改/删除/增加操作
  2. queries
    1. 查询操作
  3. types
    1. 数据类型定义(输入/输出)

以HelloSchema为例,其文件结构如下:

<code class="language-powershell"><span class="p">.</span>
<span class="err">├──</span> <span class="n">index</span><span class="p">.</span><span class="n">js</span>
<span class="err">├──</span> <span class="n">mutations</span>
<span class="err">│</span>   <span class="err">├──</span> <span class="n">add</span><span class="p">.</span><span class="n">js</span>
<span class="err">│</span>   <span class="err">├──</span> <span class="n">index</span><span class="p">.</span><span class="n">js</span>
<span class="err">│</span>   <span class="err">├──</span> <span class="n">remove</span><span class="p">.</span><span class="n">js</span>
<span class="err">│</span>   <span class="err">└──</span> <span class="n">update</span><span class="p">.</span><span class="n">js</span>
<span class="err">├──</span> <span class="n">queries</span>
<span class="err">│</span>   <span class="err">├──</span> <span class="n">hello</span><span class="p">.</span><span class="n">js</span>
<span class="err">│</span>   <span class="err">└──</span> <span class="n">index</span><span class="p">.</span><span class="n">js</span>
<span class="err">└──</span> <span class="n">types</span>
    <span class="err">├──</span> <span class="n">Hello</span><span class="p">.</span><span class="n">js</span>
    <span class="err">├──</span> <span class="n">HelloAddInput</span><span class="p">.</span><span class="n">js</span>
    <span class="err">├──</span> <span class="n">HelloFields</span><span class="p">.</span><span class="n">js</span>
    <span class="err">└──</span> <span class="n">HelloUpdateInput</span><span class="p">.</span><span class="n">js</span>
</code>

各文件作用如下:

  • index.js
    • 初始化query和mutation
  • mutations
    • add.js
      • 执行增加操作
    • index.js
      • 将增加/修改/删除操作引用到一起
    • remove.js
      • 执行删除操作
    • update.js
      • 执行更新操作
  • queries
    • hello.js
      • 执行查询操作
    • index.js
      • 将查询操作引用到一起
  • types
    • Hello.js
      • 定义返回结果的数据类型
    • HelloAddInput.js
      • 定义增加操作时输入结构的数据类型
    • HelloUpdateInput.js
      • 定义更新操作时输入结构的数据类型
    • HelloFields.js
      • 定义HelloSchema的通用数据结构(和HelloModel内容相同)

index.js

初始化query和mutation

<code class="language-js"><span class="kr">import</span> <span class="p">{</span>
  <span class="nx">GraphQLObjectType</span><span class="p">,</span>
  <span class="nx">GraphQLSchema</span><span class="p">,</span>
  <span class="nx">GraphQLList</span>
<span class="p">}</span> <span class="nx">from</span> <span class="s1">'graphql'</span><span class="p">;</span>

<span class="kr">import</span> <span class="nx">mutations</span> <span class="nx">from</span> <span class="s1">'./mutations'</span><span class="p">;</span>
<span class="kr">import</span> <span class="nx">queries</span> <span class="nx">from</span> <span class="s1">'./queries'</span><span class="p">;</span>

<span class="kd">let</span> <span class="nx">schema</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GraphQLSchema</span><span class="p">({</span>
  <span class="nx">query</span><span class="o">:</span> <span class="k">new</span> <span class="nx">GraphQLObjectType</span><span class="p">({</span>
    <span class="nx">name</span><span class="o">:</span> <span class="s1">'Query'</span><span class="p">,</span>
    <span class="nx">fields</span><span class="o">:</span> <span class="nx">queries</span>
  <span class="p">}),</span>

  <span class="nx">mutation</span><span class="o">:</span> <span class="k">new</span> <span class="nx">GraphQLObjectType</span><span class="p">({</span>
    <span class="nx">name</span><span class="o">:</span> <span class="s1">'Mutation'</span><span class="p">,</span>
    <span class="nx">fields</span><span class="o">:</span> <span class="nx">mutations</span>
  <span class="p">})</span>
<span class="p">});</span>

<span class="kr">export</span> <span class="k">default</span> <span class="nx">schema</span><span class="p">;</span>
</code>

queries/hello.js

执行查询操作

<code class="language-js"><span class="kr">import</span> <span class="p">{</span> <span class="nx">GraphQLList</span><span class="p">,</span> <span class="nx">GraphQLString</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">'graphql'</span><span class="p">;</span>

<span class="kr">import</span> <span class="nx">HelloType</span> <span class="nx">from</span> <span class="s1">'../types/Hello.js'</span><span class="p">;</span>
<span class="kr">import</span> <span class="nx">HelloModel</span> <span class="nx">from</span> <span class="s1">'../../../models/HelloModel'</span><span class="p">;</span>

<span class="kr">const</span> <span class="nx">hello</span> <span class="o">=</span> <span class="p">{</span>
	<span class="nx">type</span><span class="o">:</span> <span class="k">new</span> <span class="nx">GraphQLList</span><span class="p">(</span><span class="nx">HelloType</span><span class="p">),</span>
	<span class="nx">async</span> <span class="nx">resolve</span> <span class="p">(</span><span class="nx">root</span><span class="p">,</span> <span class="nx">params</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="p">{</span>
  		<span class="kd">var</span> <span class="nx">hello</span> <span class="o">=</span> <span class="nx">await</span> <span class="nx">HelloModel</span><span class="p">.</span><span class="nx">find</span><span class="p">({});</span>
  		<span class="k">return</span> <span class="nx">hello</span><span class="p">;</span>
	<span class="p">}</span>
<span class="p">}</span>

<span class="kr">export</span> <span class="k">default</span> <span class="nx">hello</span><span class="p">;</span>
</code>

定义了返回结果是一个HelloType的数组列表 ,resolve中使用了async函数进行mongodb异步查询。

mutations/add.js

执行增加操作

<code class="language-js"><span class="kr">import</span> <span class="p">{</span> <span class="nx">GraphQLNonNull</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">'graphql'</span><span class="p">;</span>

<span class="kr">import</span> <span class="nx">HelloType</span> <span class="nx">from</span> <span class="s1">'../types/Hello.js'</span><span class="p">;</span>
<span class="kr">import</span> <span class="nx">HelloAddInput</span> <span class="nx">from</span> <span class="s1">'../types/HelloAddInput.js'</span><span class="p">;</span>
<span class="kr">import</span> <span class="nx">HelloModel</span> <span class="nx">from</span> <span class="s1">'../../../models/HelloModel'</span><span class="p">;</span>

<span class="kr">const</span> <span class="nx">add</span> <span class="o">=</span> <span class="p">{</span>
  <span class="nx">type</span><span class="o">:</span> <span class="nx">HelloType</span><span class="p">,</span>
  <span class="nx">args</span><span class="o">:</span> <span class="p">{</span>
    <span class="nx">info</span><span class="o">:</span> <span class="p">{</span>
      <span class="nx">name</span><span class="o">:</span> <span class="s1">'info'</span><span class="p">,</span>
      <span class="nx">type</span><span class="o">:</span> <span class="k">new</span> <span class="nx">GraphQLNonNull</span><span class="p">(</span><span class="nx">HelloAddInput</span><span class="p">)</span>
    <span class="p">}</span>
  <span class="p">},</span>
  <span class="nx">async</span> <span class="nx">resolve</span> <span class="p">(</span><span class="nx">root</span><span class="p">,</span> <span class="nx">params</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="p">{</span>

    <span class="kr">const</span> <span class="nx">HelloModel</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">HelloModel</span><span class="p">(</span><span class="nx">params</span><span class="p">.</span><span class="nx">info</span><span class="p">);</span>
    <span class="kr">const</span> <span class="nx">newHello</span> <span class="o">=</span> <span class="nx">await</span> <span class="nx">HelloModel</span><span class="p">.</span><span class="nx">save</span><span class="p">();</span>

    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">newHello</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="nx">newHello</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">};</span>

<span class="kr">export</span> <span class="k">default</span> <span class="nx">add</span><span class="p">;</span>
</code>

注意其中args,其类型是HelloAddInput

HelloAddInput定义如下:

<code class="language-js"><span class="kr">import</span> <span class="p">{</span>
  <span class="nx">GraphQLInputObjectType</span><span class="p">,</span>
  <span class="nx">GraphQLString</span><span class="p">,</span>
  <span class="nx">GraphQLID</span><span class="p">,</span>
  <span class="nx">GraphQLNonNull</span>
<span class="p">}</span> <span class="nx">from</span> <span class="s1">'graphql'</span><span class="p">;</span>

<span class="kr">export</span> <span class="k">default</span> <span class="k">new</span> <span class="nx">GraphQLInputObjectType</span><span class="p">({</span>
  <span class="nx">name</span><span class="o">:</span> <span class="s1">'HelloAddInput'</span><span class="p">,</span>
  <span class="nx">fields</span><span class="o">:</span> <span class="p">{</span>
    <span class="nx">email</span><span class="o">:</span> <span class="p">{</span>
      <span class="nx">type</span><span class="o">:</span> <span class="nx">GraphQLString</span>
    <span class="p">},</span>
    <span class="nx">lastIP</span><span class="o">:</span> <span class="p">{</span>
      <span class="nx">type</span><span class="o">:</span> <span class="nx">GraphQLString</span>
    <span class="p">}</span>
  <span class="p">}</span>
<span class="p">});</span>
</code>

声明了在执行添加操作时需要输入email和lastIP参数。

mutations/update.js

执行更新操作

<code class="language-js"><span class="kr">import</span> <span class="p">{</span> <span class="nx">GraphQLNonNull</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">'graphql'</span><span class="p">;</span>

<span class="kr">import</span> <span class="nx">HelloType</span> <span class="nx">from</span> <span class="s1">'../types/Hello.js'</span><span class="p">;</span>
<span class="kr">import</span> <span class="nx">HelloModel</span> <span class="nx">from</span> <span class="s1">'../../../models/HelloModel'</span><span class="p">;</span>
<span class="kr">import</span> <span class="nx">HelloUpdateInput</span> <span class="nx">from</span> <span class="s1">'../types/HelloUpdateInput.js'</span><span class="p">;</span>

<span class="kr">const</span> <span class="nx">update</span> <span class="o">=</span> <span class="p">{</span>
  <span class="nx">type</span><span class="o">:</span> <span class="nx">HelloType</span><span class="p">,</span>
  <span class="nx">args</span><span class="o">:</span> <span class="p">{</span>
    <span class="nx">options</span><span class="o">:</span> <span class="p">{</span>
      <span class="nx">name</span><span class="o">:</span> <span class="s1">'options'</span><span class="p">,</span>
      <span class="nx">type</span><span class="o">:</span> <span class="k">new</span> <span class="nx">GraphQLNonNull</span><span class="p">(</span><span class="nx">HelloUpdateInput</span><span class="p">)</span>
    <span class="p">}</span>
  <span class="p">},</span>
  <span class="nx">async</span> <span class="nx">resolve</span> <span class="p">(</span><span class="nx">root</span><span class="p">,</span> <span class="nx">params</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="p">{</span>

    <span class="kr">const</span> <span class="nx">updated</span> <span class="o">=</span> <span class="nx">await</span> <span class="nx">HelloModel</span><span class="p">.</span><span class="nx">findOneAndUpdate</span><span class="p">({</span>
      <span class="nx">_id</span><span class="o">:</span> <span class="nx">params</span><span class="p">.</span><span class="nx">options</span><span class="p">.</span><span class="nx">_id</span>
    <span class="p">},</span> <span class="nx">params</span><span class="p">.</span><span class="nx">options</span><span class="p">);</span>

    <span class="kr">const</span> <span class="nx">hello</span> <span class="o">=</span> <span class="nx">await</span> <span class="nx">HelloModel</span><span class="p">.</span><span class="nx">findOne</span><span class="p">({</span>
      <span class="nx">_id</span><span class="o">:</span> <span class="nx">params</span><span class="p">.</span><span class="nx">options</span><span class="p">.</span><span class="nx">_id</span>
    <span class="p">});</span>

    <span class="k">return</span> <span class="nx">hello</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">};</span>

<span class="kr">export</span> <span class="k">default</span> <span class="nx">update</span>
</code>

注意其中的参数options,其数据类型为HelloUpdateInput。

HelloUpdateInput定义如下:

<code class="language-js"><span class="kr">import</span> <span class="p">{</span>
  <span class="nx">GraphQLObjectType</span><span class="p">,</span>
  <span class="nx">GraphQLInputObjectType</span><span class="p">,</span>
  <span class="nx">GraphQLNonNull</span><span class="p">,</span>
  <span class="nx">GraphQLString</span><span class="p">,</span>
  <span class="nx">GraphQLID</span><span class="p">,</span>
  <span class="nx">GraphQLInt</span><span class="p">,</span>
  <span class="nx">GraphQLBoolean</span>
<span class="p">}</span> <span class="nx">from</span> <span class="s1">'graphql'</span><span class="p">;</span>

<span class="kr">import</span> <span class="nx">HelloFields</span> <span class="nx">from</span> <span class="s1">'./HelloFields'</span><span class="p">;</span>

<span class="kr">export</span> <span class="k">default</span> <span class="k">new</span> <span class="nx">GraphQLInputObjectType</span><span class="p">({</span>
  <span class="nx">name</span><span class="o">:</span> <span class="s1">'HelloUpdateInput'</span><span class="p">,</span>
  <span class="nx">fields</span><span class="o">:</span> <span class="nx">HelloFields</span>
<span class="p">});</span>
</code>

定义了在更新字段时可以使用HelloFields内的任意字段,HelloFields定义如下:

<code class="language-js"><span class="kr">import</span> <span class="p">{</span>
  <span class="nx">GraphQLString</span><span class="p">,</span>
  <span class="nx">GraphQLInt</span><span class="p">,</span>
  <span class="nx">GraphQLBoolean</span>
<span class="p">}</span> <span class="nx">from</span> <span class="s1">'graphql'</span><span class="p">;</span>

<span class="kr">export</span> <span class="k">default</span> <span class="p">{</span>
  <span class="nx">_id</span><span class="o">:</span> <span class="p">{</span>
    <span class="nx">type</span><span class="o">:</span> <span class="nx">GraphQLString</span>
  <span class="p">},</span>
  <span class="nx">email</span><span class="o">:</span> <span class="p">{</span>
    <span class="nx">type</span><span class="o">:</span> <span class="nx">GraphQLString</span>
  <span class="p">},</span>
  <span class="nx">lastIP</span><span class="o">:</span> <span class="p">{</span>
    <span class="nx">type</span><span class="o">:</span> <span class="nx">GraphQLString</span>
  <span class="p">}</span>
<span class="p">}</span>
</code>

其和model是一样的

mutations/remove.js

执行删除操作

<code class="language-js"><span class="kr">import</span> <span class="p">{</span> <span class="nx">GraphQLList</span><span class="p">,</span> <span class="nx">GraphQLString</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">'graphql'</span><span class="p">;</span>

<span class="kr">import</span> <span class="nx">HelloType</span> <span class="nx">from</span> <span class="s1">'../types/Hello.js'</span><span class="p">;</span>
<span class="kr">import</span> <span class="nx">HelloModel</span> <span class="nx">from</span> <span class="s1">'../../../models/HelloModel'</span><span class="p">;</span>

<span class="kr">const</span> <span class="nx">remove</span> <span class="o">=</span> <span class="p">{</span>
  <span class="nx">type</span><span class="o">:</span> <span class="k">new</span> <span class="nx">GraphQLList</span><span class="p">(</span><span class="nx">HelloType</span><span class="p">),</span>
  <span class="nx">args</span><span class="o">:</span> <span class="p">{</span>
    <span class="nx">ids</span><span class="o">:</span> <span class="p">{</span>
      <span class="nx">name</span><span class="o">:</span> <span class="s1">'ids'</span><span class="p">,</span>
      <span class="nx">type</span><span class="o">:</span> <span class="k">new</span> <span class="nx">GraphQLList</span><span class="p">(</span><span class="nx">GraphQLString</span><span class="p">)</span>
    <span class="p">}</span>
  <span class="p">},</span>
  <span class="nx">async</span> <span class="nx">resolve</span> <span class="p">(</span><span class="nx">root</span><span class="p">,</span> <span class="nx">params</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="p">{</span>

    <span class="kd">let</span> <span class="nx">removedList</span> <span class="o">=</span> <span class="p">[];</span>

    <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">params</span><span class="p">.</span><span class="nx">ids</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
      <span class="kr">const</span> <span class="nx">_id</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">ids</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
      <span class="kr">const</span> <span class="nx">removed</span> <span class="o">=</span> <span class="nx">await</span> <span class="nx">HelloModel</span><span class="p">.</span><span class="nx">findOneAndRemove</span><span class="p">({</span>
        <span class="nx">_id</span>
      <span class="p">});</span>

      <span class="k">if</span><span class="p">(</span><span class="nx">removed</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">removedList</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">removed</span><span class="p">)</span>
      <span class="p">}</span>
    <span class="p">};</span>

    <span class="k">return</span> <span class="nx">removedList</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="kr">export</span> <span class="k">default</span> <span class="nx">remove</span>
</code>

注意其中的ids是一个GraphQLList字符串数组,返回结果是HelloType对象。

执行GraphQL查询

启动程序

<code class="language-text">docker-compose up -d
</code>

打开GraphQL测试界面:localhost:5555/graphiql

先来执行一个查询:

可以看到结果返回空。

再执行一个增加操作:

可以看到右侧返回了新增的数据及其id

我们再将emai修改为“fuck_shit”:

右侧成功返回了修改之后的数据。

最后,我们删除这条数据:

返回了被删除的id。

再最后执行一次查询:

可以看到结果又变为空了。

至此,整个GraphQL+MongoDB的CRUD操作测试成功。

小Tips

graphql的测试器右侧可以查看数据类型:

完整代码见:leinue/node-mongodb-graphql-docker

相关文章

返回
  1. 暂无评论。

  1. 暂无 Trackback

You must be logged in to post a comment.