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

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

内容简介:主要包含以下内容 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 详细信息的值


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

查看所有标签

猜你喜欢:

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

Google's PageRank and Beyond

Google's PageRank and Beyond

Amy N. Langville、Carl D. Meyer / Princeton University Press / 2006-7-23 / USD 57.50

Why doesn't your home page appear on the first page of search results, even when you query your own name? How do other web pages always appear at the top? What creates these powerful rankings? And how......一起来看看 《Google's PageRank and Beyond》 这本书的介绍吧!

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

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

HEX CMYK 互转工具

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

HEX HSV 互换工具