 函数完全指南:一键拉起真实 Directus 实例用于测试与开发)
Directus API Sandbox 的 sandbox() 函数完全指南一键拉起真实 Directus 实例用于测试与开发【免费下载链接】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/sandbox是 Directus 仓库内部提供的一组工具函数用于快速启动与销毁一个带真实数据库、可访问 REST / GraphQL / WebSocket 接口的完整 Directus API 实例。本文以官方 API 文档 tests/sandbox/docs/functions/sandbox.md 为核心逐项拆解sandbox()函数的签名、全部可配置参数与返回对象并结合 tests/sandbox/src/sandbox.ts 等源码剖析其底层执行流程。读完本文你将能够在自己的测试或开发脚本中几秒钟内启动一个跨多种数据库PostgreSQL、MySQL、SQLite、CockroachDB、MSSQL、Oracle、MariaDB的 Directus 环境并优雅地完成 schema 装载、多实例横向扩展与资源清理。一、定位与入口directus/sandbox 是什么directus/sandbox是 Directus 仓库tests/sandbox目录下的一套工具对外暴露为 npm 包名directus/sandbox用途在包文档 tests/sandbox/docs/README.md 中说明得十分直白Utility functions for quickly spinning up and down instances of directus for usage such as testing or development.也就是说它是 Directus 官方测试与开发的基础设施黑盒测试、调试复现、依赖某数据库的回归场景都通过它来开箱即用地拉起一套真实的 Directus。从模块导出结构见 tests/sandbox/docs/globals.md 与入口 tests/sandbox/src/index.ts可以看出该包对外暴露了两类交互方式函数式 APIsandbox()与sandboxes()两个异步函数供在 JS/TS 测试代码中调用命令行 CLIsandbox命令封装在 tests/sandbox/src/cli.ts 中。另外还导出若干类型别名与常量类型别名Database、Options、Sandbox、Env 等常量apiFolder、databases支持的全部数据库名数组见 tests/sandbox/src/sandbox.ts。sandbox()是其中最常用、最核心的单实例启动函数本文聚焦于此。二、函数签名与参数速览sandbox()的定义位于 tests/sandbox/src/sandbox.ts对应官方 API 文档中的签名如下sandbox(database, options?): PromiseSandbox其中项说明database要启动 API 所用的数据库类型必填options?可选的深度部分配置对象DeepPartialOptions控制构建、运行模式、Docker、端口、环境变量等行为返回值PromiseSandbox即运行中的沙箱控制句柄2.1 第一个参数 database七种数据库选择database参数的类型是Database。该类型在 tests/sandbox/src/sandbox.ts 中被定义为export type Database ExcludeDatabaseClient, redshift | maria;官方文档给出可选的取值有七个同时这也是 CLI 中database位置的 choices 校验值maria · cockroachdb · mssql · mysql · oracle · postgres · sqlite这些取值在源码中作为常量数组databases导出tests/sandbox/src/sandbox.ts并且sandbox()入口处会做一次合法性校验——传入不在该列表内的值会直接抛出Invalid database providedif (!databases.includes(database)) throw new Error(Invalid database provided);值得注意的是一个实现细节如果传入的不是真实存在的数据库而是一个新数据库类型需要连同 Docker 编排文件、环境配置一起扩展这一点从 tests/sandbox/src/steps/docker.ts 中按数据库名挑选 compose 文件、以及 tests/sandbox/src/config.ts 中按数据库配置默认连接信息可以佐证。2.2 第二个参数 options完整配置项解析sandbox()的options是DeepPartialOptions允许只传你关心的字段其余会被默认值补全。下面按官方文档列出的字段逐一展开并补充源码中的默认值与额外字段。buildbooleanRebuild directus from source —— 从源码重新构建 Directus。默认值为false见getOptions的 merge 默认值tests/sandbox/src/sandbox.ts。开启后沙箱启动前会执行一次完整的构建流程对应steps/buildApi。官方文档建议需要快速迭代源码改动时配合watch一起使用。devbooleanStart directus in developer mode. Not compatible with build —— 以开发模式启动 Directus且与 build 不兼容。默认false。从getOptions与 tests/sandbox/src/sandbox.ts 的逻辑可见只有在opts.build !opts.dev时才触发构建印证了二者互斥的关系。开启 dev 后环境变量中NODE_ENV会被设为development见 tests/sandbox/src/config.ts。watchbooleanRestart the api when changes are made —— 源码发生变化时自动重启 API。默认false。适合配合dev/build进行源码热迭代。portstringPort to start the api on —— API 监听的端口。默认端口解析链在getOptions中options.port ?? process.env[PORT] ?? 8055即优先用户显式传入的端口其次是进程环境变量PORT兜底为 8055。需要注意sandbox()真正绑定到 API 的端口以最终解析为准可以通过返回对象的env.PORT/env.PUBLIC_URL读取详见第五节。dockerobject容器行为配置docker控制被拉起容器数据库及 extras的行为包含三个子项子项类型默认值说明basePort文档/port源码字段名stringundefinedCLI 默认{min: 8100, max: 8200}Docker 容器使用的最小端口号环境变量中的$PORT占位符会基于此分配真实端口keepbooleanfalse停止沙箱时是否保留容器运行。为 false 时下一次启动前会先执行docker compose down清理旧容器见 tests/sandbox/src/steps/docker.tsnamestringundefined覆盖 Docker compose 项目名。未指定时按sandbox_database[_extra...][_suffix]规则自动生成注意文档中写的是basePort而源码实际字段名为port类型Port | PortRange可传单个端口或端口范围其作用是给 compose 项目内所有需要动态端口的环境变量提供起始值。CLI 层面对应的选项为--docker.port默认范围{ min: 8100, max: 8200 }见 tests/sandbox/src/cli.ts。envRecordstring, string | undefinedAdd environment variables that the api should start with —— 追加传给 API 进程的环境变量。这是 API 启动时变量合并链的最上层覆盖之一。从 tests/sandbox/src/config.ts 的getEnv可以看出合并顺序大致为数据库默认配置 → extras 配置minio/saml/maildev 等→opts.env→ 进程自身环境变量 → 强制覆盖的PORT/PUBLIC_URL。因此你可以用env传任意 Directus 环境变量例如覆盖CACHE_ENABLED、注入第三方服务地址等。CLI 对应参数为--env KEYVALUE可多次指定。exportbooleanExports a snapshot and type definition every 2 seconds —— 每 2 秒导出一次 schema 快照与类型定义。默认false。开启后sandbox()会启动一个定时器调用steps/saveSchema见 tests/sandbox/src/sandbox.ts便于在调试过程中持续观测数据库结构变化。extrasobject按需拉起配套服务extras用于启动数据库之外的可选容器官方文档列出四类子项说明redis缓存用官方注明当 instances 1 时会被强制为 truemaildev邮件服务器SMTP 调试对应maildev这一 extraminio对象存储服务提供方S3 兼容对应minioextrasaml认证提供方SAML IdP对应samlextra源码中 extras 定义见 tests/sandbox/src/sandbox.ts实际还包含一个文档未细化的license模拟 License 服务器。启用某个 extra 后getEnv会把对应的一组环境变量注入 API如 minio 会注入STORAGE_LOCATIONS: minio,local及整套STORAGE_MINIO_*saml 会注入AUTH_PROVIDERS: saml和两套 SP/IdP metadatamaildev 会注入EMAIL_TRANSPORT: smtp等详见 tests/sandbox/src/config.ts。Docker 编排时非 sqlite 场景会把这些 extra 的 compose 文件与数据库 compose 文件一并合并执行tests/sandbox/src/steps/docker.ts。inspectbooleanStart the api with debugger —— 以调试模式启动 API默认 true。源码中inspect默认值是truetests/sandbox/src/sandbox.ts与 CLI 帮助中--inspect ... (default: true)一致。instancesstringHorizontally scale the api to a given number of instances —— 将 API 水平扩展到指定实例数。默认1。实际生效逻辑在 tests/sandbox/src/steps/api.tsconst apiCount Math.max(1, Number(opts.instances))即至少一个实例。当实例数超过 1 时官方建议配合 redis extra用于缓存同步见上文 redis 说明。killPortsbooleanForcefully kills all processes that occupy ports that the api would use —— 强制结束所有占用 API 目标端口的进程。默认关闭该字段并入getOptions默认对象见 tests/sandbox/src/sandbox.ts 之前的默认项具体杀进程逻辑见 tests/sandbox/src/kill.ts。适合在 CI 或本地端口冲突频繁的环境中使用。prefixstringPrefix the logs, useful when starting multiple sandboxes —— 为日志行增加前缀便于同时运行多个沙箱时区分。默认undefined。sandbox()创建 logger 时若提供了 prefix则日志带上该前缀tests/sandbox/src/sandbox.ts。schemastringLoad an additional schema snapshot on startup —— 启动时加载一份额外的 schema 快照。默认undefined。有两个细节值得注意getOptions中对schema true做了特殊处理会把值归一化为snapshot.jsontests/sandbox/src/sandbox.ts因此 CLI 的-s, --schema [schema]可以不跟具体文件名直接使用加载发生在数据库 bootstrap 之后、API 启动之前对应steps/loadSchema确保 API 一启动就能看到快照中的集合结构。2.3 源码中额外存在、但 API 文档单页未展开的选项Options类型tests/sandbox/src/sandbox.ts中还定义了以下字段供深度使用参考app是否同时以开发模式拉起前端 app、dbVersion覆盖数据库镜像版本、docker.suffix给 compose 项目名追加后缀保证唯一、silent除错误外静默日志、cache开关缓存、skipSetup跳过初始 admin 与 owner 创建、knex为直接数据库访问打开 Knex 连接以及hooks.beforeApi在 bootstrap 完成后、API 启动前执行的生命周期钩子。三、返回值Sandbox 对象sandbox()返回PromiseSandboxSandbox 的类型定义见 tests/sandbox/src/sandbox.ts 与 tests/sandbox/docs/type-aliases/Sandbox.mdtype Sandbox { restartApi(): Promisevoid; stop(): Promisevoid; env: Env; apis: [Api, ...Api[]]; // 运行中的 API 进程至少一个 logger: Logger; knex?: Knex; // 开启 knex 选项后可用 };成员说明env沙箱启动时最终生效的完整环境变量对象含PORT、PUBLIC_URL、ADMIN_EMAIL等见 tests/sandbox/docs/type-aliases/Env.mdrestartApi()重启 API 进程。重启前会重新解析端口——若原端口尚处于TIME_WAIT会回退到空闲端口并同步更新opts.port、env.PORT与env.PUBLIC_URLtests/sandbox/src/sandbox.tsstop()停止整个沙箱清理导出定时器、杀掉构建/API/App/License 各进程、销毁 Knex 连接并打印耗时日志apis当前存活的 API 子进程列表。注意它是 getter——重启后自动指向新进程但解构赋值的旧引用不会更新env中值得预先知晓的默认值完整清单见 tests/sandbox/src/config.tsSECRET: directus-test、TELEMETRY: false、LOG_LEVEL: info、HOST: 127.0.0.1并且除非显式skipSetup否则会预置一个管理员账号ADMIN_EMAIL: adminexample.com ADMIN_PASSWORD: pw ADMIN_TOKEN: admin PROJECT_OWNER: adminexample.com也就是说沙箱启动后你就可以用这套默认凭据登录或用ADMIN_TOKEN直接访问受保护接口。四、CLI 交互方式虽然 API 文档单页聚焦sandbox()函数但官方包文档将 CLI 视为平行的第二入口这里一并给出完整对照对应 tests/sandbox/src/cli.tsUsage: sandbox [options] database Arguments: database What database to start the api with (choices: maria, cockroachdb, mssql, mysql, oracle, postgres, sqlite) Options: -b, --build 从源码重新构建 Directus -d, --dev 以开发模式启动与 build 不兼容 -w, --watch 源码变化时自动重启 API -p, --port port API 监听端口CLI 默认 8055 -a, --app [port] 同时以开发模式拉起前端 app --inspect 以调试模式启动默认 true -i, --instances n 水平扩展到 n 个实例默认 1 --db-version version 指定数据库镜像版本 --docker.port port 容器端口分配起始值默认 {min:8100,max:8200} --docker.keep 停止沙箱时保留容器 --docker.name name 覆盖 Docker compose 项目名 --docker.suffix suffix 给 compose 项目名追加后缀 --env KEYVALUE... 追加 API 环境变量可多次指定 --cache 开关缓存 --prefix prefix 日志前缀 -x, --export 每 2 秒导出 schema 快照与类型定义 -s, --schema [schema] 启动时加载额外 schema 快照 -e, --extras extras 启用 redis,maildev,saml,minio 等 extras逗号分隔 --silent 仅输出错误及以上日志 --skip-setup 跳过初始 admin 与 owner 创建 -h, --help 显示帮助一个典型 CLI 调用示例sandbox postgres --dev --watch --extras redis,maildev --schema snapshot.jsonCLI 内部就是直接调用sandbox(database, options)并在收到SIGINT/SIGTERM信号时调用sb.stop()做优雅清理。五、编程调用示例官方包文档 tests/sandbox/docs/README.md 给出了最简示例直接通过返回对象的env.PUBLIC_URL发起 HTTP 请求import { sandbox } from directus/sandbox; const sb await sandbox(postgres, { dev: true }); // 通过 REST / GraphQL / WebSockets 与实例交互 const result await fetch(sb.env.PUBLIC_URL /items/articles); console.log(await result.json()); await sb.close(); // 对应源码里的 sb.stop()注意沙箱返回的句柄方法是stop()。上述示例里的sb.close()是文档行文习惯实际调用请使用stop()。下面给出几个更贴近真实使用场景的扩展示例。5.1 全流程加载快照 配置 Redis 拉取数据 停止import { sandbox } from directus/sandbox; const sb await sandbox(postgres, { dev: true, watch: true, port: 8055, extras: { redis: true, maildev: true }, schema: snapshot.json, // 或直接传 true会自动解析为 snapshot.json env: { CACHE_ENABLED: true }, }); try { // 通过默认管理员 Token 访问受保护接口 const res await fetch(${sb.env.PUBLIC_URL}/items/articles, { headers: { Authorization: Bearer ${sb.env.ADMIN_TOKEN} }, }); const data await res.json(); console.log(data); } finally { await sb.stop(); // 杀掉全部子进程默认也会清理 Docker 容器 }5.2 横向扩展多实例const sb await sandbox(postgres, { instances: 3, // 至少 1 个取 Number(instances) 与 1 的较大值 extras: { redis: true }, // 多实例场景建议启用 redis 保证缓存一致 }); console.log(sb.apis.length); // 3 for (const api of sb.apis) { console.log(API 运行于端口 ${api.port}); } await sb.restartApi(); // 统一重启全部实例 await sb.stop();5.3 进程内直接访问数据库knexconst sb await sandbox(sqlite, { knex: true }); const count await sb.knex?.(directus_users).count({ total: * }); console.log(count); await sb.stop();sqlite 是唯一不需要 Docker 的数据库类型——steps/docker.ts中 sqlite 场景只会在存在 extras 时才拉起容器数据库本体就是一个本地文件默认./test.db。六、sandbox() 内部工作流程五步启动链路官方包文档给出了与配置决定跳过哪些步骤对应的五步流程。结合 tests/sandbox/src/sandbox.ts 与 tests/sandbox/src/steps 目录的源码sandbox()的实际执行顺序如下构建 API可选仅当build: true且非dev时执行steps/buildApi从源码编译 Directus。可用watch快速迭代。启动 Docker 容器steps/dockerUp先校验本机docker ps可执行若未开启docker.keep会先docker compose down清理同项目旧容器再以docker compose -p project up -d --wait合并数据库与各 extra 的 compose 文件启动并等待健康。若容器仍在运行则直接复用tests/sandbox/src/steps/docker.ts。compose 文件位于 tests/sandbox/src/docker。引导数据库steps/bootstrap确保所有必要的 Directus 系统表directus_*已创建必要时写入初始管理员。加载 schema 快照可选若设置了schema在 bootstrap 后调用steps/loadSchema应用快照随后才启动 API。启动 APIsteps/startApi按instances数量拉起一个或多个 API 子进程若开启app选项还会额外启动前端若开启export则启动每 2 秒保存 schema/类型定义的定时器。整个链路被try/catch包裹任何一步失败都会自动调用内部stop()回收已启动的资源后再抛错tests/sandbox/src/sandbox.ts避免测试失败时留下孤儿进程。环境变量中的$PORT、$PORT_MINIO、$PORT_SAML、$PORT_LICENSE等占位符会在getEnv末尾被动态替换成从端口范围中分配的真实端口tests/sandbox/src/config.ts这也是沙箱可以并行启动多套互不冲突实例的基础。若想在同一进程内同时跑多个不同数据库可选用多实例版本函数sandboxes()定义于 tests/sandbox/src/sandbox.tsAPI 文档见 tests/sandbox/docs/functions/sandboxes.md它会以Promise.all并行处理各数据库的启动并统一提供restartApis()/stop()控制。七、常见用法与注意事项小结结合参数语义与源码实现汇总以下实践要点区分build与devbuild针对验证已修改源码能否成功构建dev适合日常调试开发二者不可同时使用源码层面build !dev才会触发构建。默认凭据开箱可用未设置skipSetup时沙箱内置adminexample.com/pwToken 为admin可直接用于接口鉴权。端口冲突处理API 端口默认取port参数 → 环境变量PORT→8055容器端口默认从8100–8200范围分配。若 API 端口被占可开killPorts强制清理。清理语义由docker.keep决定默认keep: falsestop()会连带执行docker compose down希望容器常驻复用加速二次启动则设docker.keep: true。快照驱动测试数据schema支持加载仓库内任意 schema 快照路径tests/sandbox/snapshot.json是一个现成示例是启动即有数据模型的推荐做法。多实例一定配 Redisinstances 1时缓存需要共享官方注解 Redis extra 会被强制启用编码时应显式带上extras.redis: true以免缓存行为不一致。返回值是 Promisesandbox()是异步函数务必await后再访问env、apis结束时记得stop()回收进程与容器。如需查看这些 API 背后更完整的类型定义与姊妹函数可继续阅读仓库内生成的 API 文档Options、Sandbox、sandboxes()或直接阅读包主页 tests/sandbox/docs/README.md。【免费下载链接】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),仅供参考