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’s HTTP paths
  2. Whether the service requires authentication
  3. Endpoints
user.yml
service:
  base-path: /users
  auth: false
  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
service:
  base-path: /users
  auth: false
  endpoints:
    getAllUsers:
      path: /all # <---
      method: GET

The full path for the endpoint is the concatenation of:

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

Path parameters

You can supply path parameters for your endpoints to create dynamic URLs.

user.yml
service:
  base-path: /users
  auth: false
  endpoints:
    getUser:
      path: /{userId} # <---
      path-parameters: # <---
        userId: string
      method: GET

Services can also have path-parameters:

project.yml
service:
  base-path: /projects/{projectId}
  path-parameters:
    projectId: string
  auth: false
  endpoints: ...

Query parameters

Each endpoint can specify query parameters:

user.yml
service:
  base-path: /users
  auth: false
  endpoints:
    getAllUsers:
      path: /all
      method: GET
      request:
        # this name is required for idiomatic SDKs
        name: GetAllUsersRequest
        query-parameters:
          limit: optional<integer>

allow-multiple

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

user.yml
query-parameters:
  filter:
    type: string
    allow-multiple: true # <---

Auth

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

user.yml
service:
  base-path: /users
  auth: false
  endpoints:
    getMe:
      path: ""
      method: GET
      # This endpoint will be authed
      auth: true
      docs: Return the current user based on Authorization header.

Headers

Each endpoint can specify request headers:

user.yml
service:
  base-path: /users
  auth: false
  endpoints:
    getAllUsers:
      path: /all
      method: GET
      request:
        # this name is required for idiomatic SDKs
        name: GetAllUsersRequest
        headers:
          X-Endpoint-Header: string

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

user.yml
 service:
   base-path: /users
   auth: false
+    headers:
+      X-Service-Header: string
   endpoints:
     getAllUsers:
       path: /all
       method: GET
       request:
         # this name is required for idiomatic SDKs
         name: GetAllUsersRequest
         headers:
           X-Endpoint-Header: string

Request body

Endpoints can specify a request body type.

user.yml
service:
  base-path: /users
  auth: false
  endpoints:
    setUserName:
      path: /{userId}/set-name
      path-parameters:
        userId: string
      method: POST
      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
service:
  base-path: /users
  auth: false
  endpoints:
    createUser:
      path: /create
      method: POST
      request:
        # this name is required for idiomatic SDKs
        name: CreateUserRequest
        body:
          properties:
            userName: string

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
service:
  base-path: /users
  auth: false
  endpoints:
    getAllUsers:
      path: /all
      method: GET
      response: list<User>

types:
  User:
    properties:
      userId: string
      name: string

Error responses

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

user.yml
service:
  base-path: /users
  auth: false
  endpoints:
    getUser:
      path: /{userId}
      path-parameters:
        userId: string
      method: GET
      response: User
      errors:
        - UserNotFoundError

types:
  User:
    properties:
      userId: string
      name: string

errors:
  UserNotFoundError:
    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 (e.g. examples in the generated Postman Collection).

user.yml
service:
  base-path: /users
  auth: false
  endpoints:
    getUser:
      path: /{userId}
      path-parameters:
        userId: string
      method: GET
      response: User
      errors:
        - UserNotFoundError
      examples: # <---
        - path-parameters:
            userId: alice-user-id
          response:
            body:
              userId: alice-user-id
              name: Alice

types:
  User:
    properties:
      userId: string
      name: string

errors:
  UserNotFoundError:
    status-code: 404

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

user.yml
examples:
  - path-parameters:
      userId: some-user-id
    query-parameters:
      limit: 50
    headers:
      X-My-Header: some-value
    response:
      body:
        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
examples:
  - path-parameters:
      userId: missing-user-id
    response:
      error: UserNotFoundError # <--

errors:
  UserNotFoundError:
    status-code: 404

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

user.yml
examples:
  - path-parameters:
      userId: missing-user-id
    response:
      error: UserNotFoundError
      body: "User with id `missing-user-id` was not found" # <--

errors:
  UserNotFoundError:
    status-code: 404
    type: string # <--

Referencing examples from types

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

service:
  base-path: /users
  auth: true
  endpoints:
    getUser:
      method: GET
      path: /{userId}
      path-parameters:
        userId: UserId
      examples:
        - path-parameters:
            userId: $UserId.Example1 # <---

types:
  UserId:
    type: integer
    examples:
      - name: Example1
        value: user-id-123