Module-schema
A Nix library that converts option declarations of the [Nixpkgs module system][module-system] into JSON Schema (draft 2020-12).
Given the options of a module, it produces a schema describing which JSON
values are valid configurations for that module. The intent is that a value
which validates against the schema, read into Nix with builtins.fromJSON,
yields a configuration that passes the checks of the option types involved.
The schema also carries what an interface needs to present the options:
descriptions, defaults, examples, bounds and which properties are required.
Why
NixOS modules are a great way to configure software, however, they come with
one big caveat, they require interacting with Nix. This puts them out of reach
of many non-technical users. A common idea is to create a graphical UI that
generates a configuration.nix.
This comes with many challenges. NixOS modules evolve over time, options are
added, removed and renamed, and it is more user-friendly to show the options set
in a previous run. This means a static set of known options does not work. So
the options need to be parsed from the modules. And to show current settings
the generated configuration needs to be parsed too, though this can be made
easier by generating a simple configuration.nix that loads most of the
configuration from a structured format like JSON.
Simply having option names and string settings for them is enough to generate a configuration. A UI could generate a configuration, then attempt to build the configuration and report errors. Users could then work their way backwards from those errors to what settings they need to change. This is a laborious workflow and it invalidates the promise of being suitable for non-technical users.
The Nixpkgs module system uses lib.types to validate configurations against
the expectations of a module. Nix is an untyped language; "type" here means an
attrset with various attributes, one of which is check, doing the type
checking. This means enough information is available for a UI to indicate
"services.something.port needs to be a number between 0 and 65535," detecting
many errors right when a user enters a value. But the constraints of these
types are not accessible outside of Nix, nor can they be introspected from Nix.
What we want to do is data specification and validation. We want a schema with
enough information to display available options to a user and validate the
resulting configuration. This library generates such a schema. It opts for JSON
Schema as defined in draft 2020-12. JSON is a simple format
and can be easily processed in many programming languages. This should make it
easy to develop new tools making use of the schema. The validation vocabulary is
expressive enough to cover most of the constraints encoded in Nixpkgs'
lib.types.
An interface that uses the schema does not need to convert its input to Nix, run a Nix evaluation, collect potential error messages and somehow translate them back to what the user sees. Instead the interface composes a JSON value, that value is validated against the schema, and it is eventually read into Nix. One caveat is that JSON Schema specifies a schema for JSON data, not an arbitrary data format.
Where it fits
Nix-module-form composes an HTML form based on a JSON Schema. Together these libraries can turn a module into a web form with useful validation.
Both libraries are developed in the Fediversity project.
Where to go next
- Usage -- getting the library, worked examples, and how to author modules that convert well.
- Related projects -- what else exists in this space and how the goals differ.
- Coverage -- which types and module system features convert.
lib.module-schema-- the API reference:optionToSchema,optionsToSchemaand the internals.lib.interval-- the interval arithmetic backing numeric bounds.
[module-system]: https://nixos.org/manual/nixpkgs/stable/#module-system