a small rodent that digs through your JSON
infer types from
sample JSON.
A tiny Rust CLI that reads JSON — from a file or a pipe — and emits a
JSON Schema,
a TypeScript interface, or a
Zod schema. Merge several samples and it figures out which fields are optional.
what it does
Pipe in JSON.
Get real types.
degu parses one or more sample JSON documents, walks the tree, and merges every observation into a single shape. Fields present in some samples but missing in others become optional. A field that's sometimes null becomes nullable. An integer stays an integer.
Then it emits your format of choice — JSON Schema Draft 7, a TypeScript interface, or a Zod schema — straight to stdout.
$ curl -s https://api.example.com/users/1 \
| degu -f typescript --name User
export interface User {
id: number;
name: string;
email?: string;
tags: string[];
profile: {
age: number;
city: string;
};
}
what degu sees
Three things degu
figures out for you.
001 / merge semantics
Optional fields, detected automatically.
Feed degu several samples of the same resource. A field that shows up in some samples but not others gets the ? treatment. No more shipping interfaces where every property is required because you only looked at one response.
$ cat a.json b.json
{"id":1,"name":"Ada","email":"ada@x.com"}
{"id":2,"name":"Grace"}
$ degu -f typescript --name User a.json b.json
export interface User {
id: number;
name: string;
email?: string;
}
$ echo '{"id":42,"tags":["rust","cli"]}' \
| degu -f zod --name Post
import { z } from "zod";
export const Post = z.object({
id: z.number().int(),
tags: z.array(z.string()),
});
export type Post = z.infer<typeof Post>;
002 / three formats
JSON Schema, TypeScript, or Zod.
Pick your target with -f. JSON Schema Draft 7 for validators, a plain export interface for a TS codebase, or a full Zod schema with .int(), .nullable(), and a matching z.infer type alias.
003 / pipeable
From curl to types in one line.
degu reads stdin. Point curl at any undocumented endpoint, pipe it through degu, and paste the result into your editor. It never writes files and never asks for config.
$ curl -s https://api.github.com/users/octocat \
| degu -f json-schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"login": { "type": "string" },
"id": { "type": "integer" },
...
}
}
quick start
Install and infer
in under a minute.
Install from crates.io
$ cargo install degu
Requires Rust 1.70+. Single binary, no runtime.
Or build from source
$ git clone https://github.com/iamkorun/degu.git
$ cd degu
$ cargo install --path .
Run it
# infer a TypeScript interface from a file
$ degu -f typescript --name User user.json
# read from stdin
$ curl -s https://api.example.com/users/1 | degu -f typescript --name User
# merge multiple samples for optional fields
$ degu -f zod --name User sample1.json sample2.json
real usage
Wire it into
your workflow.
Strict mode
Treat every observed field as required and lock the shape down with additionalProperties: false. Useful when you want the schema to reject any field degu didn't see.
$ degu --strict -f json-schema user.json
Drop into your project
Save a Zod schema straight into your source tree — now you have runtime validation and a TypeScript type from one command.
$ curl -s $API/users/1 \
| degu -f zod --name User \
> src/schemas/user.ts
→ full flag reference in the README