API 接口设计原则:RESTful 与 GraphQL

RESTful 接口

REST 的全称是 REpresentational State Transfer,是一种 Web API 的设计风格

RESTful API 设计 6 大原则

一个 RESTful 风格的接口应该满足如下的 6 点原则:

  • 统一接口:For example, the HTTP-based REST APIs make use of the standard HTTP methods (GET, POST, PUT, DELETE, etc.) and the URIs (Uniform Resource Identifiers) to identify resources
  • 使用 client-server 架构解耦
  • 无状态:server 不能保存与 client 的会话状态
  • 可缓存的:响应数据应该声明自己能否被缓存
  • 分层系统:采用反向代理服务器屏蔽 server 和 client
  • 按需返回可执行代码:server 能够向 client 返回一段代码用以执行

RESTful API 最佳实践

  • URL 中不要使用动词,动作交给 HTTP 的不同请求来区分
  • 状态码必须准确,错误信息就要响应对应的错误状态码

下面使用 nodejs 编写了一个简单的 web 服务,提供了查询 user 的 RESTful get 接口:

javascript 复制代码
var express = require('express');
var mysql = require("mysql");
var client = mysql.createConnection({
    host: '192.168.93.12',
    user: 'root',
    password: 'xxx',
    port: '3306',
    database: 'big_event',
});
client.connect();
var app = express();

app.get("/user/:id", (req, res) => {
    let { id } = req.params;
    client.query(`select id, username, password, email from user where id=${id}`, (err, users) => {
        if (err) {
            console.warn(err);
        }
        if (users && users.length == 1) {
            res.send(users[0]);
        } else {
            res.send("wrong result");
        }
    });
})

app.listen(5000, () => console.log('Now browse to localhost:5000/restful'));

对于上面的 API,使用 http://localhost:5000/user/1 即可获取到 id 为 1 的 user 信息

RESTfull API 的缺点

  • 获取数据不够灵活:batch 获取数据时要发送多次请求。也容易过度获取数据:本来只需要2~3个值,结果返回了20个值
  • 弱类型:js 的类型系统薄弱,除了 number、string、array、object 等,不支持自定义类型

针对这些缺点,提出了 GraphQL

GraphQL 接口

GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时

用 GraphQL 将上面的查询接口重写如下:

javascript 复制代码
const { graphqlHTTP } = require('express-graphql');
const { buildSchema } = require('graphql');

// 定义 GraphQL schema
const schema = buildSchema(`
    type User {
        id: Int
        username: String
        password: String
        email: String
    }

    type Query {
        user(id: Int!): User
    }
`);

// 定义 resolver 函数,用于处理查询
const root = {
    user: ({ id }) => {
        return new Promise((resolve, reject) => {
            client.query(`SELECT id, username, password, email FROM user WHERE id = ${id}`, (err, result) => {
                if (err) {
                    reject(err);
                } else {
                    resolve(result[0]);
                }
            });
        });
    }
};

const app = express();

app.use('/graphql', graphqlHTTP({
    schema: schema,
    rootValue: root,
    graphiql: true // 启用 GraphiQL 可视化工具
}));

app.listen(5000, () => {
    console.log('GraphQL Server is running on http://localhost:5000/graphql');
});

启动后,我们在浏览器中能够访问到一个调试界面:

输入查询条件:

javascript 复制代码
{
  user(id: 1) {
    id
    username
    password
  }
}

就可以得到查询结果:

javascript 复制代码
{
  "data": {
    "user": {
      "id": 1,
      "username": "wangba",
      "password": "124bd1296bec0d9d93c7b52a71ad8d5b"
    }
  }
}

GraphQL 的优点

  • 前端变被动为主动,能够决定要获取哪些数据,不再依赖于和后端的 API 接口文档。前端能够专注于 UI 设计
  • 增减字段很容易,易于扩展
  • 批量获取数据只需要发送一次 HTTP 请求,节省了网络带宽

GraphQL 的缺点

  • 缓存实现困难
相关推荐
bobz9655 小时前
5070 Ti CodeLlama 7B > Mistral 7B > Qwen3 8B
后端
麦兜*5 小时前
Spring Boot 集成 Docker 构建与发版完整指南
java·spring boot·后端·spring·docker·系统架构·springcloud
程序视点5 小时前
2025最佳图片无损放大工具推荐:realesrgan-gui评测与下载指南
前端·后端
一个很帅的帅哥6 小时前
《深入浅出 Node.js》分享精简大纲
node.js
fured7 小时前
[调试][实现][原理]用Golang实现建议断点调试器
开发语言·后端·golang
bobz9658 小时前
linux cpu CFS 调度器有使用 令牌桶么?
后端
bobz9658 小时前
linux CGROUP CPU 限制有使用令牌桶么?
后端
David爱编程8 小时前
多核 CPU 下的缓存一致性问题:隐藏的性能陷阱与解决方案
java·后端
追逐时光者9 小时前
一款基于 .NET 开源、功能全面的微信小程序商城系统
后端·.net
绝无仅有9 小时前
Go 并发同步原语:sync.Mutex、sync.RWMutex 和 sync.Once
后端·面试·github