Apollo + Koa + GraphQL学习记录

apollo+koa环境搭建

  1. 引入插件 apollo-server--koa
  2. 创建apollo server并传入GraphQL表
  3. 创建koa对象
  4. 将koa对象作为中间件传入apollo server
  5. 监听端口
  6. 定义GraphQL表并传入query对象和Mutation对象

安装插件 apollo-server-koa 和 koa

cnpm install apollo-server-koa koa

创建app.js

const Koa = require('koa');
const {ApolloServer, gql} = require('apollo-server-koa'); // graphql-koa插件
const schema = require('./server/graphql/index.js'); //自定义的GraphQL的表

const server = new ApolloServer({ //创建Graphql server
    schema,
    resolvers: ({ ctx }) => {
        // let token = ctx.
    }
});
server.applyMiddleware({app}); //apollo server使用koa中间件

app.listen(9527, ()=> { //监听端口
    console.log(`server running success at ${server.graphqlPath}`)
})

Schema & Resolvers

ApolloServe接受2个参数schema和context,schema是对查询字段类型的约束,resolvers是对查询到的数据进行过滤返回给前端。

schema官网原文解释:

// A schema is a collection of type definitions (hence "typeDefs")
// that together define the "shape" of queries that are executed against
// your data.

resolver官网原文解释:

// Resolvers define the technique for fetching the types defined in the
// schema. This resolver retrieves books from the "books" array above.
const resolvers = {
  Query: {
    books: () => books,
  },
};

Schema Basics

type Book {
  title: String
  author: Author
}

type Author {
  name: String
  books: [Book]
}
  1. [Book]  值为数组类型
  2. String!  值为string类型,不能返回null
  3. [Book!]!  # This list can't be null AND its list *items* can't be null

Scalar

  • Int: A signed 32‐bit integer
  • Float: A signed double-precision floating-point value
  • String: A UTF‐8 character sequence
  • Booleantrue or false
  • ID (serialized as a String): A unique identifier that's often used to refetch an object or as the key for a cache. Although it's serialized as a String, an ID is not intended to be human‐readable.

其中ID是独一无二序列化后的字符串,通常用于缓存的key。

Object types

type Book {
  title: String
  author: Author
}

type Author {
  name: String
  books: [Book]
}
query UniversalQuery {
  __typename
}

__typename预设属性不需要定义

query GetSearchResults {
  search(contains: "Shakespeare") {
    # Querying for __typename is almost always recommended,
    # but it's even more important when querying a field that
    # might return one of multiple types.
    __typename
    ... on Book {
      title
    }
    ... on Author {
      name
    }
  }
}
{
  "data": {
    "search": [
      {
        "__typename": "Book",
        "title": "The Complete Works of William Shakespeare"
      },
      {
        "__typename": "Author",
        "name": "William Shakespeare"
      }
    ]
  }
}

Query Type

type Query {
  books: [Book]
  authors: [Author]
}

The Query type is a special object type that defines all of the top-level entry points for queries that clients execute against your server.

This Query type defines two fields: books and authors. Each field returns a list of the corresponding type.(e.g., /api/books and /api/authors)

The Mutation Type

query定义读类型,mutation定义写类型。

type Mutation {
  addBook(title: String, author: String): Book
}

定义新增一个book对象,参数和返回值符合Schema Basics中的book type。

Like queries, mutations match the structure of your schema's type definitions. The following mutation creates a new Book and requests certain fields of the created object as a return value:

mutation CreateBook {
  addBook(title: "Fox in Socks", author: "Dr. Seuss") {
    title
    author {
      name
    }
  }
}

查询新增值与response返回结果一致

{
  "data": {
    "addBook": {
      "title": "Fox in Socks",
      "author": {
        "name": "Dr. Seuss"
      }
    }
  }
}

The Subscription type

订阅推送类型。

Input types

 输入类型是一种特殊的对象类型,它允许您将分层数据作为字段的参数提供(而不是仅提供平面标量参数)。

input BlogPostContent {
  title: String
  body: String
}
type Mutation {
  createBlogPost(content: BlogPostContent!): Post
  updateBlogPost(id: ID!, content: BlogPostContent!): Post
}

Enum types

enum AllowedColor {
  RED
  GREEN
  BLUE
}
type Query {
  favoriteColor: AllowedColor # enum return value
  avatar(borderColor: AllowedColor): String # enum argument
}

Union type

union Media = Book | Movie

Descriptions

"Description for the type"
type MyObjectType {
  """
  Description for field
  Supports **multi-line** description for your [API](http://example.com)!
  """
  myField: String!

  otherField(
    "Description for argument"
    arg: Int
  )
}

""" xxx """ 多行注释

" xxx " 单行注释

命名规范(非强制)

  1. Field names - camelCase
  2. Type names - PascalCase
  3. Enum names - PascalCase
  4. Enum values - ALL_CAPS

__resolveType

定义resolver 返回值类型

const resolvers = {
  SearchResult: {
    __resolveType(obj, context, info){
      // Only Author has a name field
      if(obj.name){
        return 'Author';
      }
      // Only Book has a title field
      if(obj.title){
        return 'Book';
      }
      return null; // GraphQLError is thrown
    },
  },
  Query: {
    search: () => { ... }
  },
};

Custom scalars

自定义标量:

const { GraphQLScalarType, Kind } = require('graphql');

const dateScalar = new GraphQLScalarType({
  name: 'Date',
  description: 'Date custom scalar type',
  serialize(value) {
    return value.getTime(); // Convert outgoing Date to integer for JSON
  },
  parseValue(value) {
    return new Date(value); // Convert incoming integer to Date
  },
  parseLiteral(ast) {
    if (ast.kind === Kind.INT) {
      return new Date(parseInt(ast.value, 10)); // Convert hard-coded AST string to integer and then to Date
    }
    return null; // Invalid hard-coded value (not an integer)
  },
});
  • serialize 后端 -> Graphql(转换) -> 前端
  • parseValue 前端 -> Graphql(转换) -> 后端
  • parseLiteral 前端 -> Graphql(转换) -> 后端

parseLiteral

When an incoming query string includes the scalar as a hard-coded argument value, that value is part of the query document's abstract syntax tree (AST). Apollo Server calls the parseLiteral method to convert the value's AST representation to the scalar's back-end representation.

In the example aboveparseLiteral converts the AST value from a string to an integer, and then converts from integer to Date to match the result of parseValue.

Directives

type ExampleType {
  oldField: String @deprecated(reason: "Use `newField`.")  newField: String
}

弃用指令

Default directives

The GraphQL specification defines the following default directives:

DIRECTIVEDESCRIPTION
@deprecated(reason: String)Marks the schema definition of a field or enum value as deprecated with an optional reason.
@skip(if: Boolean!)If true, the decorated field or fragment in an operation is not resolved by the GraphQL server.
@include(if: Boolean!)If false, the decorated field or fragment in an operation is not resolved by the GraphQL server.

Resolvers

解析器被传递4个参数,分别是:

  • parent:上一个解析器的返回值
  • args:查询时传递的参数。
  •  context:数据共享对象,包括身份验证信息、数据加载器实例和任何要跨解析器跟踪的东西。
  • info:包含有关操作执行状态的信息,包括字段名、从根到字段的路径等等。

Context

在构造函数初始化context函数,所有解析器都会调用这个函数。上下文初始化可以是异步函数。

// Constructor
const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: ({ req }) => ({
    authScope: getScope(req.headers.authorization)
  })
}));

// Example resolver
(parent, args, context, info) => {
  if(context.authScope !== ADMIN) throw new AuthenticationError('not admin');
  // Proceed
}

Return values

  • Scalar / object 解析器可以返回单个值或对象
  • Array
  • null / undefined
  • promise 通常解析器需要请求后端接口或者查询数据库

 React 结合 Graphql 学习记录

参考文献 

GraphQL实战(后端篇:apollo-server-koa + koa) - 简书

apollo graphql官网

GraphQL官网

koa官网

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值