joi-to-json
Converts Joi validation schemas into JSON Schema and OpenAPI documents using Joi's describe() API.
Repository Health
Technical Analysis
joi-to-json bridges the gap between Joi, a widely used runtime validator for Node.js APIs, and the JSON Schema / OpenAPI ecosystem. Rather than reaching into Joi’s internal representation, it works entirely off the stable, public describe() output that Joi schemas expose, converting that baseline representation into one of several target formats: JSON Schema Draft 04, Draft 07, Draft 2019-09, OpenAPI 3.0, or OpenAPI 3.1.
The library grew out of the author’s own joi-route-to-swagger project, which originally depended on an unmaintained package that reached into Joi internals and broke across Joi version bumps. joi-to-json exists specifically to avoid that fragility: each output format is implemented as an independent parser over the same baseline describe() structure, so adding or fixing one target format doesn’t touch the others, and upgrading Joi versions doesn’t require chasing internal API changes.
What You Get
- A single
parse(joiObj, type, definitions, parserOptions)function covering five output formats: JSON Schema Draft 04, Draft 07 (default), Draft 2019-09, OpenAPI 3.0, and OpenAPI 3.1 - Support for Joi’s logical relation operators (
and,nand,or,xor,oxor,with,without) translated into equivalent JSON Schema constructs, with per-operator override or full disable viaparserOptions.logicalOpParser - Named-link (
.link('#id')) support for schema reuse, with automatic extraction of shared#/components/schemasdefinitions for OpenAPI output - Conditional expression handling (
alternatives,when) using nativeif/then/elsewhere the target spec supports it, falling back toallOf/anyOfcomposition for older drafts - TypeScript type definitions (
index.d.ts) shipped alongside the package for typedparse()calls andLogicalOpParserOptscustomization - Meta-annotation passthrough (
deprecated,readOnly,writeOnly, arbitraryx-vendor extensions) via Joi’s.meta({...}), so OpenAPI-specific fields survive the conversion
Common Use Cases
- Generating Swagger/OpenAPI 3.0 or 3.1 documentation for an Express/Koa/Hapi API directly from the same Joi schemas already used to validate incoming requests
- Producing standalone JSON Schema (Draft 07 or 2019-09) files for use with validators like Ajv, or for publishing a public schema alongside an API
- Keeping API documentation in sync with validation logic in TypeScript projects, using the shipped type definitions for compile-time safety around
parse()calls - Migrating away from unmaintained Joi-internals-dependent converters (e.g.
joi-to-json-schema) onto a converter built solely against Joi’s publicdescribe()API
Under The Hood
Architecture
The library is a thin dispatch layer: index.js exports a single parse(joiObj, type, definitions, parserOptions) function that calls joiObj.describe() to get Joi’s baseline schema representation, then hands it off to one of five parser classes registered in a parsers lookup table (lib/parsers/json.js, json-draft-04.js, json-draft-2019-09.js, open-api.js, open-api-3.1.js). json.js (the Draft 07 parser) is the substantial implementation at roughly 800 lines, handling every Joi type (string, number, object, array, alternatives, binary, date, etc.) plus the logical-operator and conditional-expression translation; the other four parsers are comparatively small and largely extend or post-process the Draft 07 output, keeping format-specific quirks isolated from the core conversion logic. This one-parser-per-format design directly reflects the project’s stated goal of not letting a fix for one output format risk breaking another.
Tech Stack
A minimal-dependency Node.js library: lodash for object/array traversal utilities and combinations for generating peer-key subsets used by the oxor logical operator’s JSON Schema translation. Dev dependencies include joi itself (18.0.0, tested against Joi 17.13.3 and 18.0.0), jest for testing, eslint for linting, and typescript for validating the shipped .d.ts definitions. No build step is required for the published package — index.js and lib/ are shipped as plain CommonJS.
Code Quality
The repository has an unusually thorough test suite for its size: a fixtures-baseline/outputs-baseline pair of directories captures expected Joi describe() output across data types, verified by test/baseline.spec.js, while outputs-parsers/<format>/<type> fixtures back per-format parser tests (test/parser/*.spec.js) for all five output types. A further test/unit/ directory holds dozens of targeted specs for logical operators and conditional (alternatives/when) expressions in each supported style. Tests run via Jest and are configurable through TEST_CASE and TEST_UPDATE_PARSER_BASELINE environment variables for isolating and re-baselining individual cases. ESLint is configured via a flat eslint.config.mjs, though there is no CI workflow file in the repository itself.
API Design
The public surface is intentionally tiny: one function, parse(joiObj, type, definitions, parserOptions), with a positional type string selecting the output format and sane defaults (type='json', empty definitions/parserOptions). This keeps the barrier to adoption very low — existing Joi schemas need no changes to be converted. The tradeoff is that format-specific behavior (like which logical operators are supported per draft, or OpenAPI’s separate schemas extraction for named links) is discoverable only through the README and CHANGELOG rather than the API surface itself, which the extensive documentation and CHANGELOG (currently at v5.0.5, with fixes tracked release-by-release) partially compensates for.
Used by 2 apps in this directory
Artillery
Devops · Developer Tools
Cloud-scale load testing and functional testing for APIs, WebSockets, gRPC, and headless browsers, distributed across AWS Lambda or Fargate with zero infrastructure to manage.
Kibana
Analytics · Monitoring
Your open source window into the Elastic Stack — query, visualize, and act on data stored in Elasticsearch with real-time dashboards, AI-assisted search, and automated alerting.