news 2026/9/10 11:18:50

Directus 沙箱 sandbox() 函数全解析:为测试与开发一键拉起可编程的 API 实例

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Directus 沙箱 sandbox() 函数全解析:为测试与开发一键拉起可编程的 API 实例

Directus 沙箱 sandbox() 函数全解析:为测试与开发一键拉起可编程的 API 实例

【免费下载链接】directusThe flexible backend for all your projects 🐰 Turn your DB into a headless CMS, admin panels, or apps with a custom UI, instant APIs, auth & more.项目地址: https://gitcode.com/GitHub_Trending/di/directus

在 Directus 的 tests/sandbox/readme.md 中,官方提供了一套名为@directus/sandbox的工具包:它把“准备数据库、引导 schema、以指定环境变量启动 API”这一整套繁琐流程封装成可复用的函数与 CLI,用于黑盒测试、开发调试与 CI 场景。本文以 TypeDoc 自动生成的 API 参考文档 tests/sandbox/docs/_media/sandbox.md 为核心骨架,结合 sandbox() 的源码实现 与配套的dockercompose 文件、环境变量生成逻辑,系统讲解sandbox()函数的全部参数、返回对象与底层工作流,帮助你掌握如何用几行 TypeScript 代码按需拉起/销毁一套隔离的 Directus 运行环境。

sandbox()是什么:函数签名与定位

@directus/sandbox是 Directus 仓库内用于测试与开发的沙箱工具,提供两种交互方式:CLI 命令行JS/TS API。其中 JS API 的入口就是本文主角sandbox()

sandbox(database, options?): Promise<Sandbox>

在代码层面,它定义于 tests/sandbox/src/sandbox.ts:258,完整的类型约束为:

export type Database = Exclude<DatabaseClient, 'redshift'> | 'maria';

即第一个参数必须取自 tests/sandbox/src/sandbox.ts:26 声明的类型;运行时函数还会做一次白名单校验,传入非受支持的值会直接抛出Invalid database provided

export const databases: Database[] = ['maria', 'cockroachdb', 'mssql', 'mysql', 'oracle', 'postgres', 'sqlite'] as const;

从源码结构(tests/sandbox/src/sandbox.ts:258-347)可以推断,sandbox()内部遵循一条顺序固定的启动流水线:build → license → dockerUp → bootstrap → loadSchema → startApi → startApp,任一步骤抛出异常都会触发stop()做全量清理后再向上抛出,保证失败场景下不留残留进程。

参数 database:支持哪些数据库引擎

database为必填参数,可选项与 tests/sandbox/src/index.ts 导出、并在 tests/sandbox/src/cli.ts:8 中作为 CLI 的choices保持一致:

database 值底层连接默认镜像/版本(见 config.ts)
mariamysqlMariaDB(DB_VERSION: 11
mysqlmysqlMySQL8.4
postgrespgPostgreSQL18-3.6-alpine
cockroachdbcockroachdblatest-v25.3
mssqlmssqlSQL Server2022-latest
oracleoracledbOracle21-slim-faststart
sqlitesqlite3无需 Docker(文件型./test.db

各 Docker 化数据库的启动编排定义在 tests/sandbox/src/docker/ 目录下的 compose 文件里,例如postgres.ymlmysql.ymloracle.ymlcockroachdb.yml等,沙箱启动时会按需读取并执行。

options 详解:从buildhooks的全部开关

options是可选的深度部分覆盖对象(类型上为DeepPartial<Options>Options完整定义见 tests/sandbox/src/sandbox.ts:28-90)。其默认值由getOptions()使用lodash-esmerge合并生成(tests/sandbox/src/sandbox.ts:112-152)。下面按官方 API 文档 tests/sandbox/docs/_media/sandbox.md 的参数顺序逐项展开。

构建与运行模式:build/dev/watch

  • build?: boolean:是否每次启动沙箱前从源码重新构建 Directus。默认false
  • dev?: boolean:以开发模式启动 Directus。build互斥,源码中通过if (opts.build && !opts.dev)条件保证二者不会同时生效;对应NODE_ENV会被设为development
  • watch?: boolean:监听源码改动并自动重启 API,适合快速迭代。构建流程会随之联动(buildApi(opts, logger, restartApis)把重启回调传入构建进程)。

API 端口与实例:port/instances/killPorts

  • port?: string:API 启动端口。默认取8055process.env.PORT存在时优先,见 tests/sandbox/src/sandbox.ts:115)。getPort()会自动寻找空闲端口。
  • instances?: string:水平扩展的 API 实例数量,默认'1'。当实例数 > 1 时redis会被强制开启(用于缓存同步)。
  • killPorts?: boolean:强制杀掉占用 API 所需端口的所有进程后再启动。

Docker 行为:docker

docker是一个子对象(默认见 tests/sandbox/src/sandbox.ts:42-51):

  • docker.keep?: boolean:调用stop()时是否保留容器运行。默认false,即停止沙箱时容器也会被回收;置为true可在下次启动时复用已有容器,大幅缩短启动耗时。
  • docker.name?: string:覆盖 Docker 项目名。
  • docker.suffix?: string:为 Docker 项目名追加后缀,可保证多套沙箱互不冲突;该选项存在于源码Options类型中(见 sandbox.ts:49),CLI 侧对应--docker.suffix
  • docker.basePort?: string:Docker 容器端口分配的下限。CLI 默认使用8100–8200区间(见 tests/sandbox/src/cli.ts:46),端口内存在$PORT$PORT_LICENSE之类的占位符会被动态替换。

环境变量注入:env

env?: Record<string, string>:以键值对形式追加 API 启动所需的环境变量。在getEnv()的合并顺序中处于较高优先级(见 tests/sandbox/src/config.ts:148-177),可覆盖数据库连接、认证、缓存等配置。

日志辅助:prefix

prefix?: string:为日志加前缀。当同时启动多个沙箱时非常有用,可区分不同实例的输出。

Schema 快照:schema

schema?: string:启动时额外加载一份 schema snapshot(JSON 快照文件路径)。注意一处便捷行为:当传入schema: true时,源码会自动将其改写为'snapshot.json'(tests/sandbox/src/sandbox.ts:113)。其加载发生在bootstrap之后、API 启动之前。

调试与诊断:inspect

inspect?: boolean:是否以调试器模式(--inspect)启动 API,默认true。CLI 中该选项同样默认开启(tests/sandbox/src/cli.ts:14)。

周期导出:export

export?: boolean:每 2 秒导出一份 schema snapshot 与类型定义。源码通过saveSchema(env)返回的setInterval句柄实现,在stop()中会被clearInterval清理(见 sandbox.ts:289 与 sandbox.ts:321)。适合在开发过程中持续观察 schema 变化产物。

附加服务:extras

extras子对象用于开启可选的“周边”容器(默认全部false,定义见 tests/sandbox/src/sandbox.ts:66-78):

字段类型作用对应 docker 编排
extras.redisboolean缓存用 Redis;实例数 > 1 时被强制置为truetests/sandbox/src/docker/redis.yml
extras.maildevbooleanSMTP 邮件服务器(开发时拦截邮件)tests/sandbox/src/docker/maildev.yml
extras.miniobooleanS3 兼容对象存储(文件上传测试用)tests/sandbox/src/docker/minio.yml
extras.samlbooleanSAML 认证服务tests/sandbox/src/docker/saml.yml

extras对应的环境变量注入在 config.ts 中集中定义:例如开启minio会注入STORAGE_LOCATIONS: 'minio,local'及完整的 S3 驱动参数;开启saml会注入AUTH_PROVIDERS: 'saml'与 SP/IdP 两段 metadata 证书。

缓存开关:cache

cache?: boolean:是否启用缓存,默认false。该值会映射为环境变量CACHE_ENABLEDREDIS_ENABLED(见 config.ts:154-155)。

其他可用选项(源码补充)

API 文档未逐条列出、但在Options类型与 CLI 中存在的补充选项还包括:

  • app?: boolean | Port:是否同时以开发模式拉起前端 app 并连接 API(sandbox()中默认在opts.app !== false时启动,见 sandbox.ts:287)。CLI 对应-a, --app [port]
  • dbVersion?: string:覆盖数据库镜像版本(CLI--db-version),设置后覆盖DB_VERSION(见 config.ts:179-181)。
  • silent?: boolean:除错误外静默全部日志(CLI--silent)。
  • skipSetup?: boolean:跳过初始 admin/owner 的创建;否则默认注入admin@example.com/ 密码pw/ tokenadmin(见 config.ts:157-164)。
  • knex?: boolean:额外打开一条 Knex 连接,通过sandbox.knex直接访问数据库,便于断言库内数据。
  • hooks.beforeApi?:在 bootstrap(与 schema 加载)之后、API 启动之前执行的生命周期钩子,回调上下文携带{ env, logger, knex? }

返回值:Sandbox对象结构

sandbox()返回Promise<Sandbox>Sandbox类型别名(见 tests/sandbox/docs/type-aliases/Sandbox.md 与 sandbox.ts:103-110)包含以下成员:

成员类型说明
envEnv沙箱实际使用的完整环境变量(含数据库连接、PORTPUBLIC_URL、admin 凭据等)
loggerLogger当前沙箱的日志器实例
apis[Api, ...Api[]]已启动的 API 进程/端口列表,测试代码通过apis[0].port拼接请求地址
knexKnex \| undefined开启knex选项时的数据库直连句柄
restartApi()() => Promise<void>杀死当前 API 进程并重启。注意实现细节(sandbox.ts:296-316):重启前会重新解析端口——被杀的 API 可能让旧端口短暂处于TIME_WAIT,此时getPort会自动回退到空闲端口,并把新端口同步回opts.portenv.PORTenv.PUBLIC_URL
stop()() => Promise<void>停止整个沙箱:清理导出定时器、杀掉 build/API/app/license 子进程、销毁 knex 连接,并打印耗时统计

apis通过 getter 暴露(sandbox.ts:343-345),保证restartApi()重新赋值后调用方始终拿到最新实例。

最小可运行示例

参照 tests/sandbox/readme.md 中给出的用法,一个完整的起停流程如下:

import { sandbox } from '@directus/sandbox'; const sb = await sandbox('postgres', { dev: true }); // 通过 REST / GraphQL / WebSocket 与实例交互 const result = await fetch(`http://localhost:${sb.apis[0].port}/items/articles`); console.log(await result.json()); // 结束时清理全部资源 await sb.close();

若需要直接断言数据库状态,可叠加knexhooks

const sb = await sandbox('postgres', { knex: true, hooks: { beforeApi: async ({ env, logger }) => { logger.info(`API 即将监听 ${env.PORT}`); }, }, }); // 直连数据库做数据校验 const rows = await sb.knex('articles').select('*'); await sb.stop();

多实例场景:sandboxes()与 CLI

并行拉起多套沙箱

如需同时对多个数据库运行同一套测试,使用sandboxes()(签名见 tests/sandbox/docs/_media/sandboxes.md,实现见 sandbox.ts:173-256)。它接收一个由{ database, options }组成的数组,内部通过Promise.all并发启动,并提供统一的stop()restartApis()

const multi = await sandboxes([ { database: 'sqlite', options: { schema: 'snapshot.json' } }, { database: 'postgres', options: { env: { DB_PASSWORD: 'secret' } } }, ], { dev: true });

值得注意的是,其公共 options 只允许覆盖builddevwatch三项,各沙箱自身的差异化配置须放在各自的options中(类型定义见 sandbox.ts:168-171)。

与 CLI 的参数映射

CLI(入口 tests/sandbox/src/cli.ts)本质上是对sandbox()的一层薄封装,两者参数一一对应:

sandbox postgres \ --dev \ --port 8055 \ --instances 2 \ --extras redis,minio,maildev \ --env KEY=VALUE \ --schema snapshot.json \ --docker.port 8100 \ --docker.keep

CLI 解析后调用sandbox(database, options),其中extrasa,b,c逗号串会被转换为{ a: true, b: true, c: true }(cli.ts:51-57)。CLI 进程会监听SIGINT/SIGTERM,在退出前调用sb.stop()做资源回收(cli.ts:60-69)——因此通过编程方式使用sandbox()时,同样记得在测试收尾或进程退出处显式调用stop()

底层工作流:一次sandbox()调用做了什么

根据 tests/sandbox/readme.md 的 "Inner workings" 章节并结合源码,一次调用会按序执行以下步骤(依配置不同部分步骤会被跳过):

  1. 构建 API(可选):开启build时每次启动都会重新构建 Directus;配合watch可快速迭代。
  2. 启动 Docker 容器:拉起所需数据库与extras(redis/minio/saml/maildev 等)容器并等待其健康。若容器仍在运行则直接复用,不重复创建——这正是docker.keep存在的意义。
  3. 引导数据库(bootstrap):若库尚未引导,补齐 Directus 所需的全部系统表。
  4. 加载 schema 快照(可选):设置了schema选项时,在启动前将快照应用到数据库。
  5. 启动 API:以正确的环境变量启动一个或多个 API 实例。
  6. 启动 app(可选):开启app时以开发模式拉起前端并连接 API。

沙箱运行所需的整套环境变量由getEnv()生成(tests/sandbox/src/config.ts:148-201),它内置了一批贴近真实的默认值:SECRET: 'directus-test'TELEMETRY: 'false'RATE_LIMITER_ENABLED: 'false'WEBSOCKETS_ENABLED: 'true'ACCESS_TOKEN_TTL: '25d'等,并把env参数、PORT/PUBLIC_URL作为最终权威值合入,保证进程实际绑定端口与测试可访问端口始终一致。

何时使用sandbox():适用场景小结

综合官方定位("quickly spinning up and down instances of directus for usage such as testing or development")与仓库内实现,sandbox()最典型的落地场景包括:

  • 黑盒 API 测试:在测试套件beforeAll中拉起sqlite/postgres沙箱,通过真实 HTTP 请求断言/items、认证、GraphQL 与 WebSocket 行为;
  • 多数据库兼容性验证:利用sandboxes()mariamssqloracle等不同引擎上重复执行同一套用例(仓库的tests/blackboxtests/e2e即遵循此思路);
  • 扩展开发与调试:用dev+watch+inspect快速验证扩展代码,用app同时预览前端;
  • schema 演进观察:开启export周期导出快照,或借助schema加载既有快照还原特定库结构。

需要提醒的是,使用本工具依赖 Docker 环境与仓库内预置的镜像编排文件,sqlite是唯一不依赖 Docker 的数据库选项,适合无容器环境下的快速验证。

【免费下载链接】directusThe flexible backend for all your projects 🐰 Turn your DB into a headless CMS, admin panels, or apps with a custom UI, instant APIs, auth & more.项目地址: https://gitcode.com/GitHub_Trending/di/directus

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 11:11:56

毕业论文AI写作软件平台排行榜:选择要点与实用选择要点

摘要速览当前学术写作需求持续增长&#xff0c;AI写作工具成为学生、科研人员提升效率的重要辅助。本文围绕毕业论文AI写作软件的选型需求&#xff0c;梳理统一判断标准&#xff0c;盘点公开可核验的工具信息&#xff0c;明确适用边界与决策注意事项。e稿AI智能写作平台作为垂直…

作者头像 李华