10月23, 2017

GraphQL简单入门篇之Query

GraphQL,似乎已经出来很久了,但之前一直未曾有过接触。

我个人最近尝试了一下,觉得还不错,所以做个笔记先。

它是一个类似SQL的查询器,前端可以通过query语法来快速查询某张表的指定字段或者某几张表的联合字段。当然它也不仅限于查询,同时也支持mutation(即各种增删改查)。

后端Koa写法

const koa =  require('koa'); // koa@2
const koaRouter = require('koa-router'); 
const koaBody = require('koa-body'); 
const { graphqlKoa, graphiqlKoa } = require('graphql-server-koa');

const schema = require("./graphql/schema");

const app = new koa();
const router = new koaRouter();
const PORT = 3000;

// koaBody is needed just for POST.
 app.use(koaBody({ multipart: true }));

router.get('/graphiql', async function(ctx, next) {
    await graphiqlKoa({endpointURL: '/graphql'})(ctx, next)
});
router.post('/graphql', graphqlKoa({ schema }));
router.get('/graphql', graphqlKoa({ schema }));

app.use(router.routes());
app.use(router.allowedMethods());
app.listen(PORT);

graphiql这个路由就是一个GraphQL可视器,类似github GraphQL,效果截图如下:

alt

koa-body

graphql需要body-parser来解析body,所以在过程中需要使用中间件。

我之前的项目中使用了koa-better-body,但这个不兼容graphql,所以只得放弃。

koa-bodyparser有一定的局限性,它只支持到了:form/json,在文件上传这一块无能为力。

alt

所以建议使用koa-body来做解析的中间件,然后option加上multipart。

router.post('/test', async function(ctx, next) {
    console.log(ctx.request.body);
    ctx.body = 123
})
  • 场景1

alt

打印结果:

alt

  • 场景2

alt

打印结果:

alt

结论:虽然不像koa-better-body好用,但还是可以使用,无非是自己需要知道场景,就可以做出相关处理。

schema

const { GraphQLObjectType, GraphQLSchema } = require("graphql");

const CategoryQueries = require("./category/query");

module.exports = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'Queries',
    fields: Object.assign(
        CategoryQueries
    )
  })
})

上面是表示定义一个Schema的查询:

alt

两个文件,一个定义查询,一个定义模型(即数据表的映射)

表模型

const { GraphQLString, GraphQLID, GraphQLObjectType } = require("graphql");

module.exports = new GraphQLObjectType({
    name: 'Category',
    fields: {
        id: {
            type: GraphQLID
        },
        zh_name: {
            type: GraphQLString
        },
        en_name: {
            type: GraphQLString
        }
    }
});

一般和数据表结构相同即可,也可以少字段。

定义查询

const { GraphQLID, GraphQLList, GraphQLNonNull } = require("graphql");

const CategoryType = require("./model");

const Category = {
    type: CategoryType,
    args: {
        id: {
            name: 'id',
            type: new GraphQLNonNull(GraphQLID)
        }
    },
    async resolve (root, params, options) {
        // 通过params.id可以得到传递的ID
        let data = /* 这里可以通过ORM查询表,或者request api */
        return data
    }
}

const Categorys = {
    type: new GraphQLList(CategoryType),
    args: {},
    async resolve (root, params, options) {
        let data =  /* 这里可以通过ORM查询表,或者request api */
        return data;
    }
}

module.exports = {
    Category,
    Categorys
}

这里关键的方法就在于resolve,我们可以在里面查询数据表,或者第三方服务都可以,关键在于拿到数据,return回去。

前端查询

axios.defaults.headers.post['Content-Type'] = 'application/json';
axios({
  url: "/graphql",
  method: "post",
  data: JSON.stringify({
    query: `{
      items:Categorys {
        zh_name
      }
      Category(id: 2){
        en_name
      }
    }`
  })
})

post格式为"application/json",话说axios不知道是不是改了,默认居然变成form了。

items: xx表示起别名。

一些感受

总体来说,这门语言还是相当不错的,就相当于把要显示哪些字段交给前端人员去做控制。

一些疑惑,如果内部服务器出现了500,能否自定义返回json。另外还有就是一些更复杂的操作了,感觉值得学习一下。

本文链接:www.my-fe.pub/post/graphql-query-get-started.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。