@uni2c/graphqlapi4mp
v1.0.9
Published
Lightweight GraphQL SDL parser and query builder for TypeScript, Node.js, browsers, and mini programs.
Maintainers
Readme
@uni2c/graphqlapi4mp
一个轻量、零运行时依赖的 GraphQL SDL 解析与查询文本生成工具。它可以从 SDL 中提取 Query、Mutation、对象类型、标量和枚举,并根据配置生成 selection set 与完整的 GraphQL operation。
适合需要在小程序、Node.js 或前端项目中根据既有 GraphQL Schema 动态构造查询,同时希望控制运行时代码体积的场景。
特性
- 解析 GraphQL SDL 中的
type、scalar和enum - 提取
Query、Mutation根字段及参数类型 - 自动选择标量和枚举字段
- 按配置递归展开对象字段
- 生成 Query 或 Mutation 文本
- 变量格式化与空值过滤:按 SDL 参数类型自动类型转换(
Int、Float、Boolean、String、JsonString、[Type]等),支持开启/关闭空值('',[],undefined,null)过滤 - 安全加解密与签名:内置 AES-128-CBC 对称加解密、RSA 非对称公钥加密、MD5 签名与 Base64 编解码,开箱即用兼容微信小程序、uni-app 与 Web 环境
- 请求参数统一预处理:提供
paramProcess,一键完成变量签名、生产环境数据 AES+RSA 混合加密封装 - 同时支持 ESM 和 CommonJS
- 内置 TypeScript 类型声明
- 零额外网络层包依赖,针对小程序轻量优化
安装
npm install @uni2c/graphqlapi4mp也可以使用 pnpm 或 yarn:
pnpm add @uni2c/graphqlapi4mp
# 或
yarn add @uni2c/graphqlapi4mp模块导入
ESM / TypeScript:
import {
parseSDL,
buildGraphQLQuery,
buildSelectionFields,
formatVariables,
paramProcess,
setEnv,
getSign,
encodeData,
decodeData,
initPassword,
md5,
base64encode,
base64decode,
} from '@uni2c/graphqlapi4mp';CommonJS:
const {
parseSDL,
buildGraphQLQuery,
buildSelectionFields,
formatVariables,
paramProcess,
setEnv,
getSign,
encodeData,
decodeData,
initPassword,
md5,
base64encode,
base64decode,
} = require('@uni2c/graphqlapi4mp');完整示例
假设有以下 SDL:
scalar DateTime
enum UserStatus {
ACTIVE
DISABLED
}
type Query {
user(id: ID!, includeDisabled: Boolean = false): User
}
type User {
id: ID!
name: String!
status: UserStatus!
createdAt: DateTime!
profile: Profile
}
type Profile {
bio: String
website: String
}解析 SDL、选择返回字段并生成查询:
import {
buildGraphQLQuery,
buildSelectionFields,
parseSDL,
type GraphQLOperation,
} from '@uni2c/graphqlapi4mp';
const sdl = `
scalar DateTime
enum UserStatus { ACTIVE DISABLED }
type Query {
user(id: ID!, includeDisabled: Boolean = false): User
}
type User {
id: ID!
name: String!
status: UserStatus!
createdAt: DateTime!
profile: Profile
}
type Profile {
bio: String
website: String
}
`;
const schema = parseSDL(sdl);
const sourceOperation = schema.query.user;
if (!sourceOperation) {
throw new Error('Query.user 不存在');
}
const operation: GraphQLOperation = {
...sourceOperation,
fields: buildSelectionFields(schema, sourceOperation, {
profile: {
website: false,
},
}),
};
const query = buildGraphQLQuery(operation, 'query');
console.log(query);输出:
query user($id: ID!, $includeDisabled: Boolean) {
user(
id: $id
includeDisabled: $includeDisabled
) {
id
name
status
createdAt
profile {
bio
}
}
}请求时将变量单独传给 GraphQL 客户端:
const variables = {
id: 'user-1',
includeDisabled: false,
};
await fetch('/graphql', {
method: 'POST',
headers: {
'content-type': 'application/json',
},
body: JSON.stringify({ query, variables }),
});API
parseSDL(sdl)
解析 SDL 字符串并返回 Schema 元数据。
const schema = parseSDL(sdl);
schema.query; // Query 根字段
schema.mutation; // Mutation 根字段
schema.types; // 所有已解析的对象类型
schema.scalars; // 内置标量和自定义标量
schema.enums; // 枚举名称返回类型:
interface SchemaMeta {
query: Record<string, SchemaField>;
mutation: Record<string, SchemaField>;
types: Record<string, SchemaType>;
scalars: Set<string>;
enums: Set<string>;
}字段的 type 会保留 GraphQL 类型修饰符,例如 ID!、[User!]!。
buildSelectionFields(schema, operation, config?)
根据 operation 返回类型构造 selection set 字段树。
规则:
- 标量和枚举字段默认包含
- 对象字段默认不展开
- 对象字段配置为
true时展开,并包含其直接标量/枚举字段 - 对象字段配置为对象时,按该配置递归展开
- 任意字段配置为
false时排除
const fields = buildSelectionFields(schema, schema.query.user, {
name: false,
profile: {
bio: true,
website: false,
},
});返回值类似:
[
'id',
'status',
'createdAt',
{
name: 'profile',
fields: ['bio'],
},
]注意:对标量字段设置 true 不会改变行为,因为标量字段本来就会默认包含。
buildGraphQLQuery(operation, operationType?)
将 operation 转换为完整 GraphQL 文本。
const query = buildGraphQLQuery(operation); // 默认为 query
const mutation = buildGraphQLQuery(operation, 'mutation');operation 的参数定义来自 SDL,生成器会同时生成变量声明和字段参数引用。它只生成查询文本,不负责提供实际变量值或发送网络请求。
buildQuery(operation, operationType?)
buildGraphQLQuery 的兼容别名。新代码建议使用 buildGraphQLQuery。
unwrapType(type)
移除 GraphQL 列表和非空修饰符,返回基础类型名称。
unwrapType('User'); // User
unwrapType('User!'); // User
unwrapType('[User!]!'); // UserformatVariables(variables, args, filterEmpty?)
根据 SDL 定义的参数类型(如 Int, Float, Boolean, String, JsonString, [Type] 等)格式化查询变量,并支持过滤无效空值。
- 参数:
variables(Record<string, any>): 传入的业务变量对象args(Record<string, string>): 对应 operation 在 SDL 中解析出的 args 参数映射(例如{ user_id: 'Int', user_ids: '[Int]' })filterEmpty(boolean,可选,默认为true): 是否开启无效空值过滤(过滤'',[],undefined,null)
- 类型转换规则:
Int: 转换为整数(parseInt(value, 10))Float: 转换为浮点数(parseFloat(value))Boolean:'false'/'0'转换成false,其余按布尔真值String/ID: 转换为字符串JsonString: 对象自动JSON.stringify转换[Type]: 支持数组或逗号分隔字符串转数组,并递归转换每个元素- 自动忽略未在
args中定义的冗余变量字段
const args = {
user_id: 'Int',
user_ids: '[Int]',
keyword: 'String',
isVip: 'Boolean',
};
// 开启空值过滤(默认)
formatVariables(
{
user_id: '123',
user_ids: '1,2,3',
keyword: '',
isVip: 'false',
extra: 'ignored',
},
args,
);
// => { user_id: 123, user_ids: [1, 2, 3], isVip: false }
// 关闭空值过滤
formatVariables({ keyword: '' }, args, false);
// => { keyword: '' }setEnv(options)
初始化运行环境变量与加密密钥配置。
setEnv({
PROD: true, // 为 true 时,paramProcess 会对数据进行 AES+RSA 加密
VITE_SALT_KEY: 'salt_key_string', // 参与 MD5 签名的加盐密钥
VITE_PUBLIC_KEY: '-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----', // RSA 公钥
});paramProcess(config, password)
对发起请求的配置对象进行统一预处理:
- 自动提取
config.data.variables进行字典序升序并追加盐值计算 MD5 签名,附加到variables.sign; - 若
env.PROD === true,则使用password(32 位混合密钥)将config.data进行 AES-128-CBC 加密,并将password经 RSA 公钥加密存入key。
const pwd = initPassword(); // 生成 32 位随机密钥
const config = {
url: 'https://api.example.com/graphql',
data: {
query,
variables: formatVariables({ user_id: '1' }, operation.args),
},
};
const processed = paramProcess(config, pwd);数据加解密与工具函数
encrypt(text, key, iv)/decrypt(cipherText, key, iv):基于@noble/ciphers/aes实现的 AES-128-CBC 加解密,输出/输入 Base64 格式,key 与 iv 必须为 16 字节。encodeData(data, password)/decodeData(res, password):encodeData: 传入对象与 32 位字符串密钥(前 16 位为 key,后 16 位为 iv),返回{ value: 'AES加密Base64', key: 'RSA加密密码' }。decodeData: 传入{ data: 'AES密文' }和密钥进行 AES 解密,若内容为 JSON 会自动反序列化。
getSign(params):将对象或参数字符串按 key 升序拼接,拼接盐值后生成 32 位小写 MD5 签名。initPassword():生成 32 位基于时间戳和随机字符的 MD5 散列密码。md5(text):轻量级纯 JS MD5 算法实现。base64encode(str)/base64decode(str):跨平台 Base64 编解码,兼容微信小程序(wx.arrayBufferToBase64)、uni-app(uni.arrayBufferToBase64)和标准浏览器。
Mutation 示例
type Mutation {
updateUser(id: ID!, name: String!): User
}const sourceOperation = schema.mutation.updateUser;
const mutation = buildGraphQLQuery(
{
...sourceOperation,
fields: buildSelectionFields(schema, sourceOperation),
},
'mutation',
);输出:
mutation updateUser($id: ID!, $name: String!) {
updateUser(
id: $id
name: $name
) {
id
name
status
createdAt
}
}手动指定 selection set
不使用 buildSelectionFields 时,也可以自行构造字段树:
const query = buildGraphQLQuery({
name: 'user',
type: 'User',
args: { id: 'ID!' },
fields: [
'id',
'name',
{
name: 'profile',
fields: ['bio'],
},
],
});当前解析范围
该库面向查询生成所需的轻量 SDL 元数据提取,并不是完整的 GraphQL 规范验证器。目前应注意:
- 根类型按常规名称
Query和Mutation识别 - 解析对象
type、scalar和enum - 支持字段参数、列表类型、非空类型、默认值与指令的跳过处理
- 不解析
input、interface、union、fragment 或 directive 定义为可查询对象 - 不验证字段值,也不执行 GraphQL operation
需要完整 Schema 校验、执行或 introspection 时,应配合标准 GraphQL 实现使用。
发布产物
包通过条件导出自动选择模块格式:
- ESM:
dist/index.mjs - CommonJS:
dist/index.cjs - TypeScript 声明:
dist/index.d.ts
项目构建时会自动检查产物体积;超过预算或出现未登记文件时构建失败。
开发
npm install
npm run typecheck
npm test其他命令:
npm run build # 构建 CJS、ESM 和类型声明,并检查体积
npm run size # 检查 dist 文件及体积预算
npm run test:demo # 使用项目内大型 SDL 运行演示脚本License
ISC
