跳到主要内容
Huiboxes

GraphQL快速入门

GraphQL是Facebook开发的一种数据查询语言,很多人希望它能代替REST Api(REST ful:Representational State Transfer表属性状态转移。

后端1分钟阅读

GraphQL是Facebook开发的一种数据查询语言,很多人希望它能代替REST Api(REST ful:Representational State Transfer表属性状态转移。定义URI,通过API来取得资源。一种接口风格,所有语言都可以遵循这种风格。)。

GraphQL即是一种用于API的查询语言也是一个满足数据查询的运行时。GraphQL可以通过自定义对象按需获取需要的数据。

特点:

  • 请求需要的数据,不多不少(一张表中多个字段,只请求一个字段)。
  • 获取多个资源,自用一个请求。
  • 描述所有可能类型的系统。便于维护,根据需求平滑演进,添加或者隐藏字段。

Graph QL使用类型区分资源,下面是示例代码:

var express = require('express')
var graphqlHTTP = require('express-graphql')
var { buildSchema } = require('graphql')
// 定义schema,查询和类型(查询规则)。
var schema = buildSchema(`
type Account{     # 自定义参数类型,对应Query中account的类型
       name: String
       age: Int,
       gender: String,
       department: String
   }
type Query{
hello: String,
       accountName: String,
       age: Int,
       account: Account
   }
`)
// 定义查询所对应的resolver,也就是查询对应的处理器
var root = {
   hello: () => { // 与schema中的字段对应
       return 'Hello world!'
},
   accountName: () => {
       return '张三丰'
  },
   age: () => {
       return 18
  },
   account: () => {
       return {
           name: '李四',
           age: '18', // 类型与上面声明的不同,如果可以转换,GraphQL会自动转换。无法转换时会报错。
           gender: 'male',
           department: 'IT部',
      }
  },
}
var app = express()
app.use('/graphql',graphqlHTTP({
   schema: schema,
   rootValue: root,
   graphiql: true // 是否开启graphiql调试工具,项目上线时应该关掉
}))
app.listen(4000)

浏览器中使用graphiql调试截图: image-20210923102926471.png

  • 基本类型(再shema声明的时候直接使用)

    • String
    • Int
    • Float
    • Boolean
    • ID
  • 数组

    • [int] 整数型数组,其它类型也有对应的类型([type])。

与TS的函数类似,可以传递参数,需要声明类型。

// !表示该参数必传
type Query{
   rollDice(numDice: Int!,numSides: Int): [Int]
}

示例代码:

var schema = buildSchema(`
type Query {
   getClassMates(classNo: Int!): [String]
 }
`)
// 定义查询对应的处理器
var root = {
 getClassMates({ classNo }) {  // 对象方法,JS的语法糖。
   const obj = {
     // 模拟数据库
     31: ['张三', '李四', '王五'],
     61: ['赵六', '陈七', '老八'],
  }
   return obj[classNo]
},
}

第一段示例代码中有自定义类型:

var schema = buildSchema(`
type Account{
       name: String
       age: Int,
       gender: String,
       department: String,
salary(city: String): Int
   }
type Query{
getAccount(name: String): Account
   }
`)
var root = {
 getAccount({ name }) {
     return {
         name: '李四',
         age: '18',
         gender: 'male',
         department: 'IT部',
         salary({ city }) {
         if (city === '北京' || city === '上海') {
               return 10000
        } else {
             return 3000
        }
    }
  }
}

浏览器中使用graphiql调试截图:

image.png

如果schema中没有query,那么将会如下报错:Query root type must be provided

查询使用query,对数据的修改使用mutation。下面是示例代码:

// 定义schema,查询和类型
var schema = buildSchema(`
 input AccountInput{
   name: String
   age: Int
   gender: String
   department: String
 }
 type Account{
   name: String
   age: Int
   gender: String
   department: String
 }
 type Mutation{
   createAccount(input: AccountInput): Account
   updateAccount(id: ID!,input: AccountInput): Account
 }
 type Query{
   accounts: [Account]
 }
`)
const fakeDB = {}
// 定义查询对应的处理器
var root = {
 accounts() {
   return Object.values(fakeDB)
},
 createAccount({ input }) {
   // 相当于数据库的保存
   fakeDB[input.name] = input
   // 返回保存结果
   return fakeDB[input.name]
},
 updateAccount({ id, input }) {
   // 相当于数据库的更新
   const updateAccount = Object.assign({}, fakeDB[id], input)
   fakeDB[id] = updateAccount
   // 返回保存结果
   return updateAccount
},
}

graphiql中调试的语句:

// 一段一段的运行代码,运行前将其它代码注释,在graphiql中的注释为 #
mutation{ # 新增操作
 createAccount(input:{
   name: "李四",
   age: 19,
   gender: "女",
   department: "IT"
})
{     # 第二个对象表示返回类型
   name
   age
   gender
   department
}
}
query{ # 查询所有account
 accounts {
   name
   age
   gender
   department
}
}
mutation{   # 修改操作
 updateAccount(id: "张三",input:{
   age: 18
}){   # 第二个对象表示返回类型
   age
}
}

以上是graphql的增、改、查的用法,删除操作也可以根据上面的例子推出来。

对包含/graphql的url加以限制。

const middleware = (req, res, next) => {
 if (
   req.url.indexOf('/graphql') !== -1 &&
   ...
) {
   res.json({
     error: '没有权限访问这个接口',
  })
   return
}
 next()
}
app.use(middleware)

var schema = buildSchema(`
 input AccountInput{
   name: String
   age: Int
   gender: String
   department: String
 }
`)
// 使用GraphQLObjectType定义type,好处是可以更加准确的知道是哪儿出的错
var AccountType = new graphql.GraphQLOBjectType({
 name: 'Account',
 fields: {
   name: { type: graphql.GraphQLString },
   age: { type: graphql.GraphQLInt },
   gender: { type: graphql.GraphQLString },
   department: { type: graphql.GraphQLString },
},
})

var schema = buildSchema(`
 type Query{
   accounts: [Account]
 }
`)
// 使用GraphQLObjectType定义query
var queryType = new graphql.GraphQLObjectType({
 name: 'Query',
 fields: {
   account: {
     type: AccountType,
     args: {
       username: { type: graphql.GraphQLString }
    },
     resolve(_,{username}){
       return{
         name: username,
         gender: 'man',
         age: 18,
         department: 'IT'
      }
    }
  }
}
})

var schema = new graphql.GraphQLSchema({ query: queryType });

使用Constructing Types可以明显感觉代码变多了, 但是这样的好处是代码的可维护性更高。

上面的代码中,将mutation对应处理器中对对象的操作改为对数据库的操作即可。

评论