Skip to content

Inspect traffic

Generate types from JSON

Since 0.2.0 Requires Cloak Proxy 0.2.0 or later.

Turn a captured JSON response or request body into TypeScript, Swift Codable, Python dataclass, Go or Kotlin types, named from the URL and ready to copy.

Generate Types reads a JSON body your app really sent or received and writes matching type definitions in TypeScript, Swift, Python, Go or Kotlin. Use it to model an API you don’t have a schema for, to start the client code for a new endpoint, or to check what a response actually contains against the types you already have.

  1. Right-click a request in the traffic list and choose Generate Types from Response….

    For a request that sent JSON, such as a POST, choose Generate Types from Request Body… instead. Each item only appears when that body is JSON. Compressed bodies are decompressed first.

  2. Choose a Language.

  3. Check the name of the top-level type. It’s taken from the URL; type another one in Root type name to change it.

  4. Click Copy (or press ↩) and paste the code into your project. The button reads Copied until you change the language or name.

TypeScript generated from a users response. Nested objects become their own types.

  1. Language: TypeScript, Swift, Python, Go or Kotlin.
  2. Root type name. Empty: named from the URL.
  3. An empty array (or one with mixed items): the item type is unknown.
  4. An optional field: null in this body or missing in some items.
  5. Copy the code to the clipboard.
The Generate Types sheet with TypeScript selected and three interfaces, User, Address and Geo, generated from a JSON response
Control What it does
Language TypeScript, Swift (Codable), Python (dataclass), Go or Kotlin (data class). Cloak Proxy remembers your choice.
Root type name The name of the top-level type. Leave it empty to use the name suggested from the URL. Whatever you type is turned into a type name, so user profile becomes UserProfile.
Code The generated types. You can select and copy part of it.
Copy Copies all the code.
Close Closes the sheet (Esc).

Under the code, the sheet reminds you that types are inferred from this one body. If the body can’t be read as JSON, the sheet says This body isn’t JSON.

The same body in each language. This response comes from GET https://api.example.com/v1/users/42:

Response body
{
"id": 42,
"name": "Ada Park",
"email": "ada@example.com",
"score": 9.5,
"created_at": "2026-01-15T10:00:00Z",
"tags": ["admin"],
"teams": [
{ "id": 1, "name": "Mobile" },
{ "id": 2, "name": "Web", "lead": "Ada Park" }
],
"manager": null
}
export interface User {
id: number;
name: string;
email: string;
score: number;
created_at: string;
tags: string[];
teams: Team[];
manager?: null;
}
export interface Team {
id: number;
name: string;
lead?: string;
}
Language Each object becomes Optional fields Field names
TypeScript An export interface field?: type The JSON keys as they are. Keys that aren’t valid identifiers, such as 2fa or user-id, are quoted.
Swift (Codable) A struct … : Codable, after import Foundation let field: Type? camelCase. When any name differs from its key, a CodingKeys enum maps every property to its key. Swift keywords such as default and class are wrapped in backticks.
Python (dataclass) A @dataclass class, after the dataclasses and typing imports field: Optional[type] = None, placed after the required fields, because a dataclass can’t have a field with a default before one without snake_case. There’s no mapping back to the original keys, so convert camelCase keys when you load the data.
Go A type … struct A pointer with omitempty: *string and json:"lead,omitempty" PascalCase, with the original key in the json tag. id becomes Id.
Kotlin (data class) A @Serializable data class for kotlinx.serialization Type? = null camelCase, with the original key in @SerialName.

The Go output has no package line and isn’t aligned; run gofmt on it. The Kotlin output has no imports; add the kotlinx.serialization imports for Serializable, SerialName and, if it’s used, JsonElement. Only Swift output escapes keywords: if a key is a keyword in another language, such as class in Python, rename that field yourself.

JSON value TypeScript Swift Python Go Kotlin
String string String str string String
Whole number, such as 42 number Int int int64 Long
Number with a decimal point or exponent, such as 9.5 number Double float float64 Double
true or false boolean Bool bool bool Boolean
Object A named type A named type A named type A named type A named type
Array Item[] [Item] List[Item] []Item List<Item>
null only, or mixed types null or unknown String Any interface{} JsonElement

Cloak Proxy works only from the one body you picked, so the result is as good as the example:

  • Objects become named types. Each nested object gets its own type, named from its key: address becomes Address, geo becomes Geo. If two different objects would get the same name, the second gets a number: Address2.
  • Array items are merged. All the items in an array are combined into one item type, named from the singular of the key: teams gives Team, categories gives Category, addresses gives Address.
  • Missing and null fields are optional. A field that’s missing from some items in an array, or that’s null, becomes optional.
  • Whole and decimal numbers. A number without a decimal point or exponent is an integer type. If some items have 1 and others 1.5 for the same field, it becomes a decimal type.
  • Conflicting types fall back to a catch-all. A field that’s a string in one item and a number in another, or that’s only ever null, gets the catch-all type in the last row of the table above.
  • Empty arrays have an unknown item type, such as unknown[] in TypeScript.
  • Top-level arrays and values. A body that’s an array of objects produces the item type. A body that’s an array of strings or numbers, or a single value, becomes a type alias, such as export type Tag = string[]; in TypeScript.
  • Names come from keys. Keys are split into words at punctuation and lowercase-to-uppercase changes, then joined in each language’s style. A name that would start with a digit gets a prefix: T for type names and Go fields, and _ for Swift, Python and Kotlin fields. TypeScript quotes the key instead.

When Root type name is empty, the top-level type is named after the last meaningful part of the URL’s path, in singular:

Request Suggested name
GET /v1/users User
GET /v1/users/42 User
GET /v1/users/3f2a9c1e-7b4d-4e8a-9c1f-0a2b3c4d5e6f User
GET /api/categories Category
GET /v2/user-profiles UserProfile
POST /v1/orders (request body) OrderRequest
GET / Root

Numbers, long hexadecimal IDs and UUIDs, and version segments such as v1 are skipped. Types generated from a request body get Request added to the name.

The MCP server has a read-only generate_types tool. It takes a captured request’s id, and optionally side (response, the default, or request), language (typescript, swift, python, go or kotlin) and root_name. See the MCP tools reference.