Express + GraphQL构建简单的cms框架DEMO

栏目: Node.js · 发布时间: 5年前

内容简介:主要包含以下内容 1个schame, 5种基本类型+3中扩展类型+自定义类型, 2种主要操作query&mutation如果使用官方的graphql库,示例操作如下

Express + GraphQL + VUE + mysql

gitHub地址 gitee地址

实现目标

  • 实现创建cms系统及相应业务界面
  • 实现组件关联
  • 实现页面可编辑

插件选择

  • express-graphql - 用于集成graphql到express框架中
  • vue-apollo & vue-apollo - 用于在client端调用graphql的接口
  • graphql-tools - 帮助我们使用js更方便的构建graphql schame

demo运行示意图

Express + GraphQL构建简单的cms框架DEMO
Express + GraphQL构建简单的cms框架DEMO
Express + GraphQL构建简单的cms框架DEMO
Express + GraphQL构建简单的cms框架DEMO
Express + GraphQL构建简单的cms框架DEMO

具体实现分解

首先分析graphql的特点

主要包含以下内容 1个schame, 5种基本类型+3中扩展类型+自定义类型, 2种主要操作query&mutation

如何构建一个可用的schame,详情见第3步

如果使用官方的graphql库,示例操作如下

npm install graphql

构建schame如下

var {
  GraphQLList,
  GraphQLObjectType,
  GraphQLSchema,
  GraphQLString,
  GraphQLInt,
  GraphQLFloat,
  GraphQLEnumType,
  GraphQLNonNull,
  GraphQLInterfaceType,
  GraphQLInputObjectType
} = require('graphql');

const componentsSchema = require('./components');
const themesSchema = require('./themes');

const testSchema = require('./test');

const Query=new GraphQLObjectType({
  name:'CommonQuery',
  description:'通用查询',
  fields:()=>(Object.assign({},
    componentsSchema.query,
    themesSchema.query,
    testSchema.query
  ))
});
const Mutation=new GraphQLObjectType({
  name:'CommonMutation',
  description:'通用编辑',
  fields:()=>(Object.assign({},
    componentsSchema.mutation
  ))
});
const schema = new GraphQLSchema({
  query: Query,
  mutation: Mutation
});

module.exports = schema; 
复制代码

或者

var { graphql, buildSchema } = require('graphql');

var schema = buildSchema(`
  type Query {
    hello: String
  }
`);
 
复制代码

再配合express-graphql

var graphqlHTTP = require('express-graphql');

app.use('/graphql2', graphqlHTTP({
  schema: schemas,
  graphiql: true
}));
复制代码

测试访问 http://localhost:9004/graphql2

Express + GraphQL构建简单的cms框架DEMO

基于业务特点构建通用的schame模板

基于单表的增删改查

我们已经了解到graphql实现的是类似controller/action层的功能, 那单表增删改查操作其实就是普通的数据库操作了,利用 mysql 库,可以 轻松实现

使用第2步介绍的库构建schema

首先定义一张组件表

Express + GraphQL构建简单的cms框架DEMO

定义针对组件表的查询、新增功能

var daoUtil = new BaseDao();
const tableName = "m_components";

const Components = new GraphQLObjectType({
  name:'Components',
  description:"组件对象POJO",
  fields: () => {
    return ({
      id: {type: new GraphQLNonNull(GraphQLInt)},
      name: {type: new GraphQLNonNull(GraphQLString)},
      theme: {type: new GraphQLNonNull(GraphQLInt)},
      frontShow: {type: GraphQLString},
      backShow: {type: GraphQLString},
      createAt: {type: GraphQLString},
      createBy: {type: new GraphQLNonNull(GraphQLInt)},
    });
  }
});

module.exports = {
  query: {
    components_list: {
      type: new GraphQLList(Components),
      description: '查询组件列表',
      resolve: async function(source) {
        return (await daoUtil.queryAll(tableName));
      }
    }
  },
  mutation: {
    components_add: {
      type: Components,
      description: '添加组件',
      args: {
        id: {type: GraphQLInt},
        name: {type: new GraphQLNonNull(GraphQLString)},
        theme: {type: new GraphQLNonNull(GraphQLString)},
      },
      resolve: async function(source, {id, name, theme}) {
        var user = {
          name: name,
          theme: theme,
        };
        return await daoUtil.insert(tableName, user);
      }
    }
  }
}

复制代码

使用自带的graphql编辑器测试

使用方法见:graphiql

使用模板自动构建schame

常见的schame构建如上, 基于此,我们抽取出公共的部分, 使用模板生成对应对象的所有操作

  • 模板分析

    模板中应该具备对象的可操作列表, 入参、返回

type Query {
 {{each $data}}
  {{$value.name}}_all: [{{$value.modal}}]
  {{$value.name}}_page(page: Int!,limit: Int!, where:[where_query]): {{$value.modal}}_page
  {{$value.name}}_byId(id: Int!): {{$value.modal}}
  {{$value.name}}_byField({{each $value.columns}}  {{$value.Field}}:{{$value.fieldType}}, {{/each}}): [{{$value.modal}}]
 {{/each}}
}

type Mutation {
  {{each $data}}
    {{$value.name}}_add( {{each $value.columns}} {{if !$value.unUserInMutation}} {{$value.Field}}:{{$value.Type}},{{/if}} {{/each}} ): {{$value.modal}}
    {{$value.name}}_batch(list: [{{$value.modal}}_mutation]!): batch_result
    {{$value.name}}_delete(id: Int!): batch_result
    {{$value.name}}_updateById({{each $value.columns}}  {{$value.Field}}:{{$value.fieldType}}, {{/each}}): {{$value.modal}}
  {{/each}}
}

复制代码

以上是对外提供的query和Mutation。 $data 为所有对象的list

{{$value.modal}} 对应了创建的每个对象在schame中对应的可操作对象

type {{$value.modal}} {
  {{each $value.columns }}
    {{$value.Field}}:{{$value.Type}}
  {{/each}}
  {{each $value.relations relation}}
    {{relation.modal}}:{{if relation.type == 'o2o'}} {{relation.modal}} {{/if}}{{if relation.type == 'o2m'}} [{{relation.modal}}] {{/if}}
  {{/each}}
}
复制代码

{{$value.modal}}_page 对应了构建的分页对象在schame中对应的对象

type {{$value.modal}}_page {
  page: Int!,
  limit: Int!,
  list: [{{$value.modal}}],
  total: Int!
}
复制代码

最后,通过以下代码封装操作

schema {
  query: Query
  mutation: Mutation
}
复制代码
  • 调用模板方法渲染方法,同时构建schame对象
var gql = template(this.artPath, data);
      // console.log(gql)
      let typeDefs = `${gql}`
      let jsSchema = makeExecutableSchema({
        typeDefs,
        resolvers,
      });
复制代码

其他

如何实现关联查询

通过定义一个配置文件, 管理对象间的关系

m_components": [{
      "type": "o2m",
      "field": "id",
      "targetTable": "m_component_props",
      "targetField": "componentId"
    },{
      "type": "o2o",
      "field": "theme",
      "targetTable": "m_theme",
      "targetField": "id"
    }]
复制代码

通过schame绑定查询关系

{{each $value.relations relation}}
    {{relation.modal}}:{{if relation.type == 'o2o'}} {{relation.modal}} {{/if}}{{if relation.type == 'o2m'}} [{{relation.modal}}] {{/if}}
  {{/each}}

复制代码

如何解决N+1查询问题

由于graphql会根据schame,一层层解析,最终返回结果,导致关联查询时,会出现N+1查询的问题

解决N+1查询的基本方法就是讲查询条件集中到一个 sql

在我们的范例中, 可以利用resolver中context对象在各个resolver间传递, 结合关系查询配置, 在父节点中集成查询,然后传递到子resolver中返回

resolver中接受参数如下

obj 上一级对象,如果字段属于根节点查询类型通常不会被使用。

args 可以提供在 GraphQL 查询中传入的参数。

context 会被提供给所有解析器,并且持有重要的上下文信息比如当前登入的用户或者数据库访问对象。

info 一个保存与当前查询相关的字段特定信息以及 schema 详细信息的值


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

爆品手记

爆品手记

金错刀 / 中国友谊出版公司 / 2016-9-20 / 39.80

互联网时代,一切都被颠覆。 B2B、B2C、O2O等商业模式的建立,对传统企业构成了巨大冲击。人们的生意往来逐渐从线下转移到了线上,传统的定位理论逐渐失效,依靠爆品引爆市场才是王道;传统企业经营多年的渠道营销模式正遭遇前所未有的阻力,网上商城正成为众多商家角逐血拼的主要战场。 在互联网的黑暗森林里,一切传统的商业模式统统失效,一场依靠爆品点燃市场、引爆市场、占据市场的营销革命正悄然兴起......一起来看看 《爆品手记》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具