Types in Fern Definition

Types describe the data model of your API.

Built-in types

  • string
  • integer
  • long
  • double
  • boolean
  • datetime An RFC 3339, section 5.6 datetime. For example, 2017-07-21T17:32:28Z.
  • date An RFC 3339, section 5.6 date (YYYY-MM-DD). For example, 2017-07-21.
  • uuid
  • base64
  • list e.g., list<string>
  • set e.g., set<string>
  • map e.g., map<string, integer>
  • optional e.g., optional<string>
  • literal e.g., literal<“Plants”>
  • unknown Represents arbitrary JSON.

Custom types

Creating your own types is easy in Fern!

Objects

The most common custom types are objects.

In Fern, you use the "properties" key to create an object:

1types:
2 Person:
3 properties:
4 name: string
5 address: Address
6
7 Address:
8 properties:
9 line1: string
10 line2: optional<string>
11 city: string
12 state: string
13 zip: string
14 country: literal<"USA">

These represent JSON objects:

1{
2 "name": "Alice",
3 "address": {
4 "line1": "123 Happy Lane",
5 "city": "New York",
6 "state": "NY",
7 "zip": "10001",
8 "country": "USA"
9 }
10}

You can also use extends to compose objects:

1types:
2 Pet:
3 properties:
4 name: string
5 Dog:
6 extends: Pet
7 properties:
8 breed: string

You can extend multiple objects:

1types:
2 GoldenRetriever:
3 extends:
4 - Dog
5 - Pet
6 properties:
7 isGoodBoy: boolean

Aliases

An Alias type is a renaming of an existing type. This is usually done for clarity.

1types:
2 # UserId is an alias of string
3 UserId: string
4
5 User:
6 properties:
7 id: UserId
8 name: string

Enums

An enum represents a string with a set of allowed values.

In Fern, you use the "enum" key to create an enum:

1types:
2 WeatherReport:
3 enum:
4 - SUNNY
5 - CLOUDY
6 - RAINING
7 - SNOWING

Enum names are restricted to A-Z, a-z, 0-9, and _ to ensure that generated code can compile across all of the languages that Fern can output. If you have an enum that doesn’t follow this convention, you can use the "name" key to specify a custom name:

1types:
2 Operator:
3 enum:
4 - name: LESS_THAN # <--- the name that will be used in SDKs
5 value: '<' # <--- the value that will be serialized
6 - name: GREATER_THAN
7 value: '>'
8 - name: NOT_EQUAL
9 value: '!='

Discriminated Unions

Fern supports tagged unions (a.k.a. discriminated unions). Unions are useful for polymorphism. This is similar to the oneOf concept in OpenAPI.

In Fern, you use the "union" key to create an union:

1types:
2 Animal:
3 union:
4 dog: Dog
5 cat: Cat
6 Dog:
7 properties:
8 likesToWoof: boolean
9 Cat:
10 properties:
11 likesToMeow: boolean

In JSON, unions have a discriminant property to differentiate between different members of the union. By default, Fern uses "type" as the discriminant property:

1{
2 "type": "dog",
3 "likesToWoof": true
4}

You can customize the discriminant property using the “discriminant” key:

1 types:
2 Animal:
3 discriminant: animalType
4 union:
5 dog: Dog
6 cat: Cat
7 Dog:
8 properties:
9 likesToWoof: boolean
10 Cat:
11 properties:
12 likesToMeow: boolean

This corresponds to a JSON object like this:

1{
2 "animalType": "dog",
3 "likesToWoof": true
4}

Undiscriminated Unions

Undiscriminated unions are similar to discriminated unions, however you don’t need to define an explicit discriminant property.

1MyUnion:
2 discriminated: false
3 union:
4 - string
5 - integer

Generics

Fern supports shallow generic objects, to minimize code duplication. You can define a generic for reuse like so:

1MySpecialMapItem<Key, Value>:
2 properties:
3 key: Key,
4 value: Value,
5 diagnostics: string

Now, you can instantiate generic types as a type alias:

1StringIntegerMapItem:
2 type: Response<string, number>
3
4StringStringMapItem:
5 type: Response<string, string>

You can now freely use this type as if it were any other type! Note, generated code will not use generics. The above example will be generated in typescript as:

1type StringIntegerMapItem = {
2 key: string,
3 value: number,
4 diagnostics: string
5}
6
7type StringStringMapItem = {
8 key: string,
9 value: string,
10 diagnostics: string
11}

Documenting types

You can add documentation for types. These docs are passed into the compiler, and are incredibly useful in the generated outputs (e.g., docstrings in SDKs).

Fern Definition
1types:
2 Person:
3 docs: A person represents a human being
4 properties:
5 name: string
6 age:
7 docs: age in years
8 type: integer
Generated TypeScript SDK from Fern Definition
1/**
2 * A person represents a human being
3 */
4interface Person {
5 name: string;
6 // age in years
7 age: number;
8}