Fern Definition

Endpoints

In Fern, you organize related endpoints into a Service. This grouping improves clarity and makes the generated SDKs more idiomatic.

Service definition

Each service defines:

  1. A base-path: A common prefix for all the endpoints’ HTTP paths
  2. Whether the service requires authentication
  3. Endpoints
user.yml
1service:
2 base-path: /users
3 auth: false
4 endpoints: {}

Endpoints

An endpoint includes:

  • A URL path (Optionally including path parameters)
  • An HTTP Method
  • Request information (Optional)
    • Query-parameters
    • Headers
    • Request body
  • Successful (200) response information (Optional)
  • Error (non-200) responses that this endpoint might return (Optional)

URL path

Each endpoint has a URL path.

user.yml
1service:
2 base-path: /users
3 auth: false
4 endpoints:
5 getAllUsers:
6 path: /all # <---
7 method: GET

The full path for the endpoint is the concatenation of:

  • The environment URL
  • The service base-path
  • The endpoint path

Path parameters

Supply path parameters for your endpoints to create dynamic URLs.

user.yml
1service:
2 base-path: /users
3 auth: false
4 endpoints:
5 getUser:
6 path: /{userId} # <---
7 path-parameters: # <---
8 userId: string
9 method: GET

Services can also have path-parameters:

project.yml
1service:
2 base-path: /projects/{projectId}
3 path-parameters:
4 projectId: string
5 auth: false
6 endpoints: ...

Query parameters

Each endpoint can specify query parameters:

user.yml
1service:
2 base-path: /users
3 auth: false
4 endpoints:
5 getAllUsers:
6 path: /all
7 method: GET
8 request:
9 # this name is required for idiomatic SDKs
10 name: GetAllUsersRequest
11 query-parameters:
12 limit: optional<integer>

allow-multiple

Use allow-multiple to specify that a query parameter is allowed multiple times in the URL, as in ?filter=jane&filter=smith. This will alter the generated SDKs so that consumers can provide multiple values for the query parameter.

user.yml
1query-parameters:
2 filter:
3 type: string
4 allow-multiple: true # <---

Auth

Each endpoint can override the auth behavior specified in the service.

user.yml
1service:
2 base-path: /users
3 auth: false
4 endpoints:
5 getMe:
6 path: ""
7 method: GET
8 # This endpoint will be authed
9 auth: true
10 docs: Return the current user based on Authorization header.

Headers

Each endpoint can specify request headers:

user.yml
1service:
2 base-path: /users
3 auth: false
4 endpoints:
5 getAllUsers:
6 path: /all
7 method: GET
8 request:
9 # this name is required for idiomatic SDKs
10 name: GetAllUsersRequest
11 headers:
12 X-Endpoint-Header: string

Services can also specify request headers. These headers will cascade to the service’s endpoints.

user.yml
1 service:
2 base-path: /users
3 auth: false
4+ headers:
5+ X-Service-Header: string
6 endpoints:
7 getAllUsers:
8 path: /all
9 method: GET
10 request:
11 # this name is required for idiomatic SDKs
12 name: GetAllUsersRequest
13 headers:
14 X-Endpoint-Header: string

Request body

Endpoints can specify a request body type.

user.yml
1service:
2 base-path: /users
3 auth: false
4 endpoints:
5 setUserName:
6 path: /{userId}/set-name
7 path-parameters:
8 userId: string
9 method: POST
10 request: string # <---

Inlining a request body

If the request body is an object, you can inline the type declaration. This makes the generated SDKs a bit more idiomatic.

user.yml
1service:
2 base-path: /users
3 auth: false
4 endpoints:
5 createUser:
6 path: /create
7 method: POST
8 request:
9 # this name is required for idiomatic SDKs
10 name: CreateUserRequest
11 body:
12 properties:
13 userName: string

Multipart form uploads

If the request involves uploading a file, use the file type in your request body.

document.yml
1service:
2 base-path: /documents
3 auth: false
4 endpoints:
5 uploadDocument:
6 path: /upload
7 method: POST
8 request:
9 name: UploadDocumentRequest
10 body:
11 properties:
12 file: file # <------

Success response

Endpoints can specify a response, which is the type of the body that will be returned on a successful (200) call.

user.yml
1service:
2 base-path: /users
3 auth: false
4 endpoints:
5 getAllUsers:
6 path: /all
7 method: GET
8 response: list<User>
9
10types:
11 User:
12 properties:
13 userId: string
14 name: string

Error responses

Endpoints can specify error responses, which detail the non-200 responses that the endpoint might return.

user.yml
1service:
2 base-path: /users
3 auth: false
4 endpoints:
5 getUser:
6 path: /{userId}
7 path-parameters:
8 userId: string
9 method: GET
10 response: User
11 errors:
12 - UserNotFoundError
13
14types:
15 User:
16 properties:
17 userId: string
18 name: string
19
20errors:
21 UserNotFoundError:
22 status-code: 404

You can learn more about how to define errors on the Errors page.

Specifying examples

When you declare an example, you can also specify some examples of how that endpoint might be used. These are used by the compiler to enhance the generated outputs. Examples will show up as comments in your SDKs, API documentation, and Postman collection.

You may add examples for endpoints, types, and errors.

user.yml
1service:
2 base-path: /users
3 auth: false
4 endpoints:
5 getUser:
6 path: /{userId}
7 path-parameters:
8 userId: string
9 method: GET
10 response: User
11 errors:
12 - UserNotFoundError
13 examples: # <---
14 - path-parameters:
15 userId: alice-user-id
16 response:
17 body:
18 userId: alice-user-id
19 name: Alice
20
21types:
22 User:
23 properties:
24 userId: string
25 name: string
26
27errors:
28 UserNotFoundError:
29 status-code: 404

If you’re adding an example to an endpoint and the type already has an example, you can reference it using $.

1service:
2 auth: true
3 base-path: /address
4 endpoints:
5 create:
6 method: POST
7 path: ""
8 request: CreateAddress
9 response: Address
10 examples:
11 - request: $CreateAddress.WhiteHouse
12 response:
13 body: $Address.WhiteHouseWithID
14
15 CreateAddress:
16 properties:
17 street1: string
18 street2: optional<string>
19 city: string
20 state: string
21 postalCode: string
22 country: string
23 isResidential: boolean
24 examples:
25 - name: WhiteHouse
26 value:
27 street1: 1600 Pennsylvania Avenue NW
28 city: Washington DC
29 state: Washington DC
30 postalCode: "20500"
31 country: US
32 isResidential: true
33
34 Address:
35 extends: CreateAddress
36 properties:
37 id:
38 type: uuid
39 docs: The unique identifier for the address.
40 examples:
41 - name: WhiteHouseWithID
42 value:
43 id: 65ce514c-41e3-11ee-be56-0242ac120002
44 street1: 1600 Pennsylvania Avenue NW
45 city: Washington DC
46 state: Washington DC
47 postalCode: "20500"
48 country: US
49 isResidential: true

Examples contain all the information about the endpoint call, including the request body, path paramters, query parameters, headers, and response body.

user.yml
1examples:
2 - path-parameters:
3 userId: some-user-id
4 query-parameters:
5 limit: 50
6 headers:
7 X-My-Header: some-value
8 response:
9 body:
10 response-field: hello

Failed examples

You can also specify examples of failed endpoints calls. Add the error property to a response example to designate which failure you’re demonstrating.

user.yml
1examples:
2 - path-parameters:
3 userId: missing-user-id
4 response:
5 error: UserNotFoundError # <--
6
7errors:
8 UserNotFoundError:
9 status-code: 404

If the error has a body, then you must include the body in the example.

user.yml
1examples:
2 - path-parameters:
3 userId: missing-user-id
4 response:
5 error: UserNotFoundError
6 body: "User with id `missing-user-id` was not found" # <--
7
8errors:
9 UserNotFoundError:
10 status-code: 404
11 type: string # <--

Referencing examples from types

To avoid duplication, you can reference examples from types using $.

user.yml
1service:
2 base-path: /users
3 auth: true
4 endpoints:
5 getUser:
6 method: GET
7 path: /{userId}
8 path-parameters:
9 userId: UserId
10 examples:
11 - path-parameters:
12 userId: $UserId.Example1 # <---
13
14types:
15 UserId:
16 type: integer
17 examples:
18 - name: Example1
19 value: user-id-123