Graphql的使用

Graphql是一种查询语言,用于API的设计和查询。它的主要特点是提供了一种灵活、高效、类型安全的数据查询方式,可以减少API的请求次数,提高数据传输的效率。

它与Restful API对比

  1. 数据获取

RESTful API是面向资源的,每个资源都有一个独立的URL,通过HTTP方法(GET、POST、PUT、DELETE等)对资源进行操作。GraphQL是面向数据的,使用查询语言来描述需要获取的数据结构。

  1. 数据结构

RESTful API返回的数据结构是固定的,通常是JSON或XML格式。GraphQL允许客户端精确地指定需要返回的数据结构,避免了不必要的数据传输。

  1. 性能

RESTful API的性能通常受到请求和响应的大小和数量的限制。GraphQL通过在单个请求中获取多个数据点来提高性能,从而减少了请求次数和响应大小。

  1. 缓存

RESTful API使用HTTP缓存来提高性能,因为每个资源都有一个独立的URL。GraphQL可以使用相同的查询来获取不同的数据,这意味着客户端可以缓存查询并重复使用它们。

  1. 安全性

RESTful API使用HTTP方法来操作资源,因此需要对每个方法进行身份验证和授权。GraphQL使用单个HTTP方法(POST)来处理所有请求,因此需要在查询语言中定义安全性。

js搭建一个Graphql服务

import Koa from 'koa';
import mount from 'koa-mount';
import { createHandler } from 'graphql-http/lib/use/koa';
import { user_schema } from './lib/user_schema';

const app = new Koa();


// 定义数据源
const users = [
    { id: '1', name: 'Alice', age: 25, email: 'alice@example.com', posts: [{ id: '1', title: 'First Post', content: 'Hello world!' }] },
    { id: '2', name: 'Bob', age: 30, email: 'bob@example.com', posts: [{ id: '2', title: 'Second Post', content: 'What a wonderful day!' }] },
  ];
// 定义resolvers
const root = {
    hello: () => 'Hello, world!',
    user: ({ id }) => users.find(user => user.id === id),
  };

// 将GraphQL服务挂载到'/graphql'路径下
app.use(mount('/graphql', createHandler({
    schema: user_schema,
    rootValue: root,
    graphiql: true // 开启GraphQL的可视化界面
  })));

// 启动服务器
app.listen(3000, () => {
  console.log('Server started on http://localhost:3000');
});

user_schemal.js

import { buildSchema } from 'graphql';


const user_schema = buildSchema(`
  type Query {
    hello: String
    user(id: ID!): User
  }
  type User {
    id: ID
    name: String
    age: Int
    email: String
    posts: [Post]
  }
  type Post {
    id: ID
    title: String
    content: String
  }
`);
export default {user_schema}

通过GraphQL查询,这个需要支持GraphQL的客户端,发送查询语句

{
  hello,
  user(id:1){
      id,
      name,
      age,
      posts{
          id,
          title,
          content
      }
  }
}

返回的数据

{
    "data": {
        "hello": "Hello, world!",
        "user": {
            "id": "1",
            "name": "Alice",
            "age": 25,
            "posts": [
                {
                    "id": "1",
                    "title": "First Post",
                    "content": "Hello world!"
                }
            ]
        }
    }
}

创建schema

schema文件定义了需要的数据结构,graphQL有自己的类型系统
graphql.cn/learn/schema/#type-syst...

定义resolvers

对每个查询字段,需要生成对应的函数

本作品采用《CC 协议》,转载必须注明作者和本文链接
用过哪些工具?为啥用这个工具(速度快,支持高并发...)?底层如何实现的?
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 7

我也有在用

1年前 评论

我已经把这个东西已经全部删除了,就在今天. 看起来很好用,实际逻辑稀碎

1年前 评论
Runtoweb3 (楼主) 1年前
sanders

graphql 已经不算新技术了,但这么长时间里,应用始终还是占少数,是有其原因的。

我提几点使用过程中的问题,看看大家有没有较好的解决方案:

1.查询复杂度如何控制?

graphql 的查询复杂度是一个很大的问题,如果没有控制,很容易就会出现恶意查询,导致服务器崩溃。
举一个例子:

query {
  user(id: 1) {
      friends (first: 1000) {
          id
          friends (first: 1000) {
              id
              __typename
          }
      }
  }
}

这样的查询,会导致服务器查询 1000 * 1000 = 1000000 条数据,这是不可接受的。

2.查询缓冲如何实现?

graphql 的查询是非常灵活的,如果没有缓冲,每次查询都会导致数据库查询,这是不可接受的。
举一个例子:

query {
    me {
        id
        name
        joinedTeams(first: 20) {
            id
            name
            owner {
                id
                name
            }
        }
    }
}

以上查询中当前用户和所加入的团队所有者中都有相同的用户ID,如果没有缓冲,将导致多次查询。
更不用说我在使用中采用一些服务端指令,类似 @can 这类会在执行中进行数据库查询,而其中的结果难以在上下文中使用。
这种灵活的结构同时也让关系型数据库的 SQL 的组装变得非常困难,很难做到按需组装查询。

这么看,所有看起来是优势的特性都是有代价的。这让我想起我最近在使用 lighthouse 在介绍资源处置风险时提到的那句蜘蛛侠的台词“With great power there must also come great responsibility”
这就变得矛盾,从服务端看:越是灵活的 API 维护成本就变的越高,我们越需要限制它的作用,直到达到某个平衡状态。

要说起我认为 graphql 真正的价值其实还是在沟通方面,无论前端还是后端工程师都基于其 schema 暴露出数据的结构来构建程序。 schema 即充当了程序沟通的标准,也成为了前后端工程师(只不过我同时为两者,比较精分)沟通的桥梁。

1年前 评论
小李世界 1年前
sanders

上面这帖子有部分是使用 github copilot 插件在 markdown 文档中写的,大家能看出来是哪部分吗?

1年前 评论
Runtoweb3 (楼主) 1年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!