GraphQL
优缺点
-
优点
- 微服务架构下的接口聚合
- 根据 schema 自动生成接口文档
- 前端查询结果可控,灵活性
-
缺点
- 权限控制粒度
- 对于复杂查询存在性能瓶颈 - 虽然可以减少前端请求,但是数据库查询会成为性能瓶颈
- 对于前端来说,增加了上手难度,与传统 restfull api 使用习惯相差很大
- 有一些业务场景实现不了
前端使用
- 安装 graphql 依赖
pnpm i @apollo/client graphql
- 安装 graphql vite 插件
pnpm i -D @rollup/plugin-graphql
- 在 vite.config.ts 中引入插件
// vite.config.ts
import { URL, fileURLToPath } from "node:url";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import graphql from "@rollup/plugin-graphql";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [graphql()],
});
- 定义 API client
如果有多个服务,可以定义多个 client ,每个 client 相当于一个 gql 请求实例
// src/api/client/index.ts
import { ApolloClient, HttpLink, InMemoryCache } from "@apollo/client/core";
import { setContext } from "@apollo/client/link/context";
import { onError } from "@apollo/client/link/error";
const httpLink = new HttpLink({
uri: "/api/graphql",
});
const link = onError((error) => {
if (error.graphQLErrors && error.graphQLErrors.length) {
error.graphQLErrors.forEach((e) => { console.log(e) });
}
});
const authLink = setContext((_, { headers }) => {
const token = localStorage.getItem("token");
const _headers = {
...headers,
};
if (token) {
_headers["Authorization"] = `${token}`;
}
_headers["x-requested-with"] = "XMLHttpRequest";
return {
headers: {
..._headers,
},
};
});
const client = new ApolloClient({
uri: "/api/graphql",
link: errorLink.concat(authLink.concat(httpLink)),
cache: new InMemoryCache(),
defaultOptions: {
watchQuery: {
// errorPolicy: 'none',
fetchPolicy: "no-cache",
},
query: {
// errorPolicy: 'none',
fetchPolicy: "no-cache",
},
mutate: {
errorPolicy: "none",
fetchPolicy: "no-cache",
},
},
});
export default client;
- 定义接口
// src/api/user/gql/signin.gql
mutation signin($name: String!, $pwd: String!) {
signin(name: $name, pwd: $pwd) {
token
}
}
// src/api/user/index.ts
import Client from "../../client";
import signin from "./gql/signin.gql";
export function login(name: string, pwd: string) {
return portalClient.mutate({
mutation: signin,
variables: {
name,
pwd,
},
});
}
- 在 vite.config.ts 中设置代理 api
// vite.config.ts
export default defineConfig({
server: {
host: true,
open: true,
proxy: {
"/api/graphql": {
target: "http://172.21.44.154:6543/",
changeOrigin: true, //是否允许跨域
rewrite: (path) => {
return path.replace(/^\/api/, "");
},
},
},
},
})
- 使用
import { appAPI } from "@/api";
async function handleLogin() {
const { login } = appAPI.User;
const res = await login(account.value, password.value);
const { token } = res.data.signIn;
if (token) {
localStorage.setItem("token", token);
}
}
- 解决 ts 项目中 gql 文件类型问题
// src/typings/global.d.ts
declare module "*.gql" {
import type { DocumentNode } from "graphql";
const value: DocumentNode;
export default value;
}
// tsconfig.json
{
"files": ["typings/global.d.ts"],
}
注意:遇到启动 GraphQL 内部报错的问题,请检查 GraphQL 相关依赖版本