import type { DynamicExpression } from './dynamic-expression'; import type { JsonValue } from './json-value'; /** * RESTful 请求配置 * * 【架构定位】: * * - 低代码平台底层网络 I/O 的通用描述符。 * - 广泛被 QueryConfig 和 MutationConfig 复用。 * * 采用“顶层双模设计”, * 在提供常规的可视化表单配置(fixed)的同时,保留了极客级别的代码逃生舱(code)。 */ export type RestRequest = RestRequestByFixed | RestRequestByCode; /** * 可视化表单请求配置 * * 适用于 90% 的标准 HTTP 请求。 * 引擎会将这些配置项与全局的 DataSource 配置进行深度合并(Merge)。 */ export interface RestRequestByFixed { type: 'fixed'; /** * 关联的全局数据源 ID * * 引擎实现指引: * * 如果指定了 DataSource,引擎应提取该数据源的 baseUrl、params、headers, * 并与当前请求的配置进行合并(当前请求的优先级更高)。 */ dataSourceId?: string; /** * 请求路径 * * 可以是完整的绝对路径(若无 dataSourceId 或需要跨域调用第三方 API), * 也可以是相对路径(如 `/users`,引擎会自动拼接 DataSource 的 baseUrl)。 */ url: string; /** * URL 查询参数 (Query String) * * 引擎防呆设计 (Poka-yoke): * * `params` 最终会被序列化拼接在 URL 后面(如 `?name=A&age=18`)。 * 坚决抵制在此处传入对象或数组!如果传入 `{ a: { b: 1 } }`, * 多数底层客户端(如原生 Fetch 或默认配置的 Axios)会将其序列化为 `?a=[object Object]`, * 这会导致后端网关解析崩溃且极其难以排查。 * 因此,类型被严格锁定为基础数据类型(Primitive Types)。 * * 【核心架构:null 的显式抹除语义 (Explicit Erasure)】 * * 引入 `null` 是为了解决局部请求“抹除”全局 DataSource 继承配置的刚需。 * 如果全局配置了 `params: { tenantId: '123' }`,而当前请求不需要带此参数, * 用户必须在当前配置中显式设置 `params: { tenantId: null }`。 * 引擎在合并配置时,一旦遇到值为 `null` 的键,必须从最终的请求参数中将其物理删除。 */ params?: Record; /** * HTTP 请求头 (Headers) * * 同上理,HTTP Headers 协议本身只接受字符串。 * 如果在 Axios 中传了一个对象(如 `headers: { Authorization: { token: '123' } }`), * Axios 就会直接把这个对象序列化成 `[object Object]` 发给后端! * 必须锁定为基础数据类型。 * * 同样支持 `null` 值的显式抹除语义(常用于抹除全局继承的 Token 以调用第三方开放 API)。 */ headers?: Record; /** * HTTP 请求体 (Payload / Body) * * 引擎实现指引: * 不强制 body 一定是一个对象,用户可以根据需要自定义。 * 当 method 为 GET 时,此字段通常被底层 HTTP 客户端忽略。 * * 必须使用 JsonValue 以守住存入数据库时的序列化底线,防止混入 Function 等非法对象。 */ body?: JsonValue; } /** * 纯代码请求配置 (Code Mode 逃生舱) * * 解决低代码平台“图灵完备性不足”的终极武器。 * * 业务场景: * * 当实施人员面临极度变态的鉴权或加密需求时 * (例如:需要提取当前时间戳、加上全局变量 token,混合后进行 MD5 加密, * 最后生成动态的 Headers、签名 Params 和变异的 URL)。 * 这在可视化的 fixed 模式下是根本无法完成的。 * * 引擎实现指引: * * `code` 是一段纯函数字符串。它接收全局上下文 `context` 作为参数 * (可解构出 `variables`, `queries` 等运行时状态)。 * 它必须 `return` 一个符合 `Omit` 结构的对象。 * 引擎在执行该函数(JIT 编译)后,拿着返回的对象去发真实的 HTTP 请求。 */ export interface RestRequestByCode extends DynamicExpression { /** * 关联的全局数据源 ID * * 即使在使用代码动态生成请求体时,也依然可以继承底层 DataSource 的公共配置(如 baseUrl)。 */ dataSourceId?: string; }