前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于 egg.js 构建 graphql api 服务

基于 egg.js 构建 graphql api 服务

作者头像
4O4
发布2022-04-25 16:59:49
1.8K0
发布2022-04-25 16:59:49
举报
文章被收录于专栏:404404

基于 egg.js 构建 graphql api 服务

登录快速注册

基于 egg.js 构建 graphql api 服务

Egg.js 简介:https://eggjs.org/zh-cn/index.html

生成项目

通过骨架快速初始化,该操作会生成一个极简版的示例,完整示例参见:eggjs/examples/hackernews-async-ts

代码语言:javascript
复制
$ mkdir egg && cd egg
$ npm init egg --type=ts
$ npm i

启动项目

代码语言:javascript
复制
$ npm run dev
$ open http://localhost:7001

安装插件

@switchdog/egg-graphql

插件机制是egg的一大特色,由于我们基于 TypeScript ,所以选择了支持 TS 的包。

代码语言:javascript
复制
npm i -s @switchdog/egg-graphql

开启插件

config/plugin.ts 下告诉 egg 开启哪些插件:

代码语言:javascript
复制
graphql: {
    enable: true,
    package: '@switchdog/egg-graphql',
},

配置插件

通常插件都会有一些配置项,在/config/config.default.ts中配置即可:

代码语言:javascript
复制
config.graphql = {
    router: '/graphql',
    // 是否加载到 app 上,默认开启
    app: true,
    // 是否加载到 agent 上,默认关闭
    agent: false,
    // 是否加载开发者工具 graphiql, 默认开启。路由同 router 字段。使用浏览器打开该可见。
    graphiql: true,
    apolloServerOptions: {
      tracing: true, // 设置为true时,以Apollo跟踪格式收集和公开跟踪数据
      debug: true, // 一个布尔值,如果发生执行错误,它将打印其他调试日志记录
    },
  };

在中间件中开启 graphql

代码语言:javascript
复制
config.middleware = [ 'graphql' ];

配置完成之后,每个落到 /graphql的请求都会触发 GraphQL Schema 的查询。

代码结构

graphql 目录下有 4 种代码,分别是:

common 全局类型定义

query 查询代码

mutation 更新操作代码

resolver业务实现代码

代码语言:javascript
复制
.
├── graphql                       | graphql 代码
│   ├── common                    | 通用类型定义
│   │   ├── resolver.js           | 合并所有全局类型定义
│   │   ├── scalars               | 自定义类型定义
│   │   │   └── date.js           | 日期类型实现
│   │   └── schema.graphql        | schema 定义
│   ├── mutation                  | 所有的更新
│   │   └── schema.graphql        | schema 定义
│   ├── query                     | 所有的查询
│   │   └── schema.graphql        | schema 定义
│   └── user                      | 用户业务
│       ├── connector.js          | 连接数据服务
│       ├── resolver.js           | 类型实现
│       └── schema.graphql        | schema 定义

CORS

CORS,常被大家称之为跨域问题,准确的叫法是跨域资源共享**(CORS,Cross-origin resource sharing)**,是W3C标准,是一种机制,它使用额外的HTTP头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。

安装 egg-cors

代码语言:javascript
复制
npm i egg-cors --save

开启 /config/plugin.ts

代码语言:javascript
复制
cors: {
    enable: true,
    package: 'egg-cors',
},

配置 /config/config.default.ts

代码语言:javascript
复制
config.cors = {
    origin: '*', 
    allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH',
};

CSRF

CSRF(Cross-site request forgery)跨站请求伪造,也被称为 One Click Attack 或者 Session Riding,通常缩写为 CSRF 或者 XSRF,是一种对网站的恶意利用。

使用 graphqlrest 端点时,实际上不必担心使用 CSRF 保护。对服务的请求应该是无状态的,并且不真正依赖Cookie或会话数据。

关闭 /config/config.default.ts

代码语言:javascript
复制
config.security = {
    csrf: {
      ignore: () => true,
    },
};

实现一个简单的 GraphQL API

编写 hello 业务

schema.graphql

graphql 自带一组默认标量类型,包括 IntFloatStringBooleanID。在定义字段时需要注明类型,这也是 graphql 的特点之一,是支持强类型的。如果非空,就在类型后面跟上一个!号。graphql 还包括枚举类型,列表和自定义类型。

代码语言:javascript
复制
type Hello {
  id: ID!
  name: String!
}
connector

编写完 schema 之后,graphql 知道有哪些数据了,但他还需要知道 “如何去取”connector 的角色就在于此。 connector 的职责就是 “取数”, 他既可以调用 rpc 接口取数,又可以调用内置的 orm 插件去取数,还可以直接调用 egg 的 service

代码语言:javascript
复制
export default class HelloConnector {
  hellos() {
    return [
      {
        id: 1,
        name: 'Jack',
      },
      {
        id: 2,
        name: 'Lucy',
      },
    ];
  }
}
resolver

resolve.js是数据类型的具体实现,依赖connector.js完成。其实 resolver 非常简单,就是针对你暴露的查询接口,调用相应的connector去取数即可,如下:

代码语言:javascript
复制
export default {
  Query: {
    hellos(_root: any, {}, { connector }) {
      return connector.hello.hellos();
    },
  },
};

定义 Query

新建一个 query 目录创建 schema.graphql 文件,也可以直接在各个模块下的 schema.graphql 文件中定义

代码语言:javascript
复制
type Query {
  hellos: [Hello!]
}

[Hello!] 可以理解为 [{id: 1, name: 'jack'}, {id: 2, name: 'praise'}] Hello! 可以理解为 {id: 1, name: 'jack'}

项目启动

代码语言:javascript
复制
npm run dev

在浏览器中输入 http://127.0.0.1:7001/graphql 出现如下界面说明已经 graphql 服务已经成功运行。

完成一次查询

代码语言:javascript
复制
# Write your query or mutation here
{
	hellos {
  	id
    name
	}
}

执行得到

代码语言:javascript
复制
{
  "data": {
    "hellos": [
      {
        "id": "1",
        "name": "Jack"
      },
      {
        "id": "2",
        "name": "Lucy"
      }
    ]
  }
}

设置别名

代码语言:javascript
复制
# Write your query or mutation here
{
	users: hellos {
  	id
    name
	}
}

得到

代码语言:javascript
复制
{
  "data": {
    "users": [
      {
        "id": "1",
        "name": "Jack"
      },
      {
        "id": "2",
        "name": "Lucy"
      }
    ]
  }
}

请求流程

通过上方的例子我们可以看出客户端发送请求会被 graphql 解析,根据映射关系找到对应的 resolver。路由将数据传递到对应的 resolverresolver 去调用对应的 connector 进行处理,connector 再调用 service 进行数据库处理。

从MongoDB查询数据

安装 egg-mongoose

代码语言:javascript
复制
yarn add egg-mongoose

配置

代码语言:javascript
复制
// config/plugin.ts
exports.mongoose = {
  enable: true,
  package: 'egg-mongoose',
};

// config/config.default.ts
exports.mongoose = {
  client: {
    url: 'mongodb://127.0.0.1/example',
    options: {},
    // mongoose global plugins, expected a function or an array of function and options
    plugins: [createdPlugin, [updatedPlugin, pluginOptions]],
  },
};

Schema

代码语言:javascript
复制
// app/model/user.ts
module.exports = (app: any) => {
  const mongoose = app.mongoose;
  const Schema = mongoose.Schema;

  const UserSchema = new Schema({
    open_id: String!,
    info: {
      nick: String!,
      name: String!,
      gender: Number!,
      city: String!,
      province: String!,
      country: String!,
      avatar: String!,
      phone: String!
    },
    address: [
      {
        name: String!,
        phone: String!,
        addr: String!,
        default: Boolean,
        sign: String!
      }
    ],
    carts: [
      {
        gid: Number!,
        num: Number!
      }
    ],
    favorite: {
      goods: [String],
      content: [String]
    },
    browse: [String],
    createdAt: Number,
    updatedAt: Number
  });

  return mongoose.model('User', UserSchema);
}

Controller

代码语言:javascript
复制
// app/model/user.ts
import { Controller } from 'egg';

export default class UserController extends Controller {
  public async index() {
    const { ctx } = this;
    ctx.body = await ctx.model.User.find({});
  }
}

Router

代码语言:javascript
复制
// app/router.ts
import { Application } from 'egg';

export default (app: Application) => {
  const { controller, router } = app;
  router.get('/user', controller.user.index);
};

结果

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-06-14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基于 egg.js 构建 graphql api 服务
    • 生成项目
      • 启动项目
        • 安装插件
          • 开启插件
            • 配置插件
              • 代码结构
                • CORS
                  • CSRF
                    • 实现一个简单的 GraphQL API
                      • 编写 hello 业务
                      • 定义 Query
                      • 项目启动
                      • 完成一次查询
                      • 设置别名
                      • 请求流程
                    • 从MongoDB查询数据
                      • 安装 egg-mongoose
                      • 配置
                      • Schema
                      • Controller
                      • Router
                      • 结果
                  相关产品与服务
                  云数据库 MongoDB
                  腾讯云数据库 MongoDB(TencentDB for MongoDB)是腾讯云基于全球广受欢迎的 MongoDB 打造的高性能 NoSQL 数据库,100%完全兼容 MongoDB 协议,支持跨文档事务,提供稳定丰富的监控管理,弹性可扩展、自动容灾,适用于文档型数据库场景,您无需自建灾备体系及控制管理系统。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档