Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(docs): server stub generation #3760

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions fern/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ tabs:
display-name: SDKs
icon: fa-brands fa-codepen
slug: sdks
servers:
display-name: Server Stubs
slug: servers
cli-api:
display-name: CLI & API Reference
icon: fa-regular fa-code
Expand Down Expand Up @@ -385,14 +388,26 @@ navigation:
path: ./pages/docs/components/endpoint-response-snippet.mdx
icon: "turn-down"
slug: response-snippet

- section: Alternatives
hidden: true
contents:
- page: ReadMe
slug: readme
path: ./pages/docs/comparison/readme.mdx

- tab: servers
layout:
- section: Introduction
contents:
- page: What is server code generation?
path: ./pages/servers/introduction.mdx
- section: Server Frameworks
contents:
- page: Express server
path: ./pages/servers/express.mdx
- page: FastAPI server
path: ./pages/servers/fastapi.mdx
- page: Spring server
path: ./pages/servers/spring.mdx
- tab: cli-api
layout:
- section: CLI Reference
Expand Down
143 changes: 143 additions & 0 deletions fern/pages/servers/express.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
---
title: Express Server
description: Generate Express Node.js server code from an API specification including OpenAPI, Swagger, AsyncAPI, and Fern Definition.
subtite: Generate types and networking logic for your Node.js Express server.
slug: express
---

Express is a minimal and flexible Node.js web application framework. It is a popular choice for building APIs and web servers.

Fern generates TypeScript types and networking logic for your Express server. This saves you time and adds compile-time safety by guaranteeing that you are serving the exact API that you specified in your API definition.

## What Fern generates

- TypeScript interfaces for your API types
- Exceptions that you can throw for non-200 responses
- Interfaces for you to define your business logic
- All the networking/HTTP logic to call your API

## Use the starter repository

Clone the [starter repo](https://github.com/fern-api/express-starter/) for Express + React.

## Demo video

Learn how Fern can be helpful when building an Express server.

<div style="position: relative; padding-bottom: 62.5%; height: 0;"><iframe src="https://www.loom.com/embed/31f4243c4d824c54938bdc4840fbb8ba?sid=3f460e48-af22-4db3-be2f-48884ab0170d" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></iframe></div>

## Getting started

<Steps>

### Define your API

Define your API using the [OpenAPI Specification](/learn/api-definition/openapi/overview) or the [Fern Definition](/learn/api-definition/fern/overview).

### Add the Express generator

Add the Express server generator to your `generators.yml` file.

<CodeBlock title="generators.yml">
```yaml
groups:
express-server:
generators:
- name: fernapi/fern-typescript-express
version: 0.15.0
output:
location: local-file-system
path: ../app/server
```
</CodeBlock>

###
Run the [CLI](/learn/cli-api/cli-reference/cli-overview) command `fern generate --group express-server`.

<Note>Make sure to enable `allowSyntheticDefaultImports` in your `tsconfig.json` when using this generator.</Note>

### Implement the functions

Provide the business logic by implementing each function. For example, if we were implenting the IMDb API, we would implement the `get_movie` function.

<CodeBlock title="src/movies_service.py">
```python
from .generated.fern import AbstractMoviesService, Movie, MovieDoesNotExistError, MovieId
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I’m here 🫣 this file should prob have express examples not fastapi examples


class MoviesService(AbstractMoviesService):
def get_movie(self, *, movie_id: str) -> Movie:
if movie_id == "titanic":
return Movie(
id=MovieId.from_str("titantic"),
title="Titanic",
rating=9.8,
)
raise MovieDoesNotExistError(MovieId.from_str(movie_id))
```
</CodeBlock>

### Run the server

```bash
poetry run start
```

### Call the API 🚀

```bash
$ curl --location --request GET --silent 'localhost:8080/movies/titanic' | jq .
{
"id": "titantic",
"title": "Titanic",
"rating": 9.8
}

$ curl --location --request GET --silent 'localhost:8080/movies/oceans-11' | jq .
{
"error": "MovieDoesNotExistError",
"errorInstanceId": "f6e1d69c-bf97-42d5-bc89-5e42773e3880",
"content": "oceans-11"
}
```

</Steps>

## Advanced Configurations
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zachkirsch good ol' server stubs coming back into play

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol love it. I think I have “server INTERFACES not stubs” still burned into my memory


Tailor the `config` of the Express server generator to your needs. The default values for all options are `false`.

| Configuration Option | Description |
| -------------------- | ----------- |
| `useBrandedStringAliases` | When `true`, string aliases are generated as branded strings. This makes each alias feel like its own type and improves compile-time safety. |
| `areImplementationsOptional` | |
| `doNotHandleUnrecognizedErrors` | |
| `includeUtilsOnUnionMembers` | |
| `includeOtherInUnionTypes` | |
| `treatUnknownAsAny` | When `true`, unknown types at runtime are generated into TypeScript using the `any` type. |
| `noSerdeLayer` | Allows you to control whether (de-)serialization code is generated. When true, the client uses JSON.parse() and JSON.stringify() instead. <br /> By default, the generated client includes a layer for serializing requests and deserializing responses. This has three benefits: <br /> 1. The client validates requests and response at runtime, client-side. <br /> 2. The client can support complex types, like Date and Set. <br /> 3. The generated types can stray from the wire/JSON representation to be more idiomatic. For example, when `noSerdeLayer` is disabled, all properties are camelCase, even if the server is expecting snake_case. |
| `skipRequestValidation` | |
| `skipResponseValidation` | By default, this config is set to `false` and the client will throw an error if the response from the server doesn't match the expected type (based on how the response is modeled in the API definition). Set this config to `true` to never throw an error if the response is misshapen. Rather, the client will log the issue using console.warn and return the data (cast to the expected response type). |
| `outputEsm` | Allows you to control whether the generated TypeScript targets `CommonJS` or `esnext`. By default, the generated TypeScript targets `CommonJS`. |
| `outputSourceFiles` | When `false` (default), the generator outputs .js and d.ts files. When `true`, the generator outputs raw TypeScript files. |
| `retainOriginalCasing` | |
| `allowExtraFields` | |

<Note>The configuration options are accessible in [`ExpressCustomConfig.ts`](https://github.com/fern-api/fern/blob/main/generators/typescript/express/cli/src/custom-config/ExpressCustomConfig.ts).</Note>

### Example Configuration

<CodeBlock title="generators.yml">
```diff
groups:
express-server:
generators:
- name: fernapi/fern-typescript-express
version: 0.15.0
output:
location: local-file-system
path: ../app/server
+ config:
+ useBrandedStringAliases: true
+ noSerdeLayer: true
```
</CodeBlock>
133 changes: 133 additions & 0 deletions fern/pages/servers/fastapi.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
---
title: FastAPI Server
description: Generate FastAPI server code from an API specification including OpenAPI, Swagger, AsyncAPI, and Fern Definition.
subtite: Generate types and networking logic for your Python FastAPI server.
slug: fastapi
---

FastAPI is a modern, fast web framework for building APIs with Python based on standard Python type hints. It is a popular choice for building APIs and web servers.

Fern outputs types and networking logic for your FastAPI server. This saves you time and adds compile-time safety by guaranteeing that you are serving the exact API that you specified in your API definition.

## What Fern generates

- Pydantic models for your API types
- Exceptions that you can throw for non-200 responses
- Abstract classes for you to define your business logic
- All the networking/HTTP logic to call your API

## Use the starter repository

Clone the [starter repo](https://github.com/fern-api/fastapi-starter/) for FastAPI + React.

## Demo video

Learn how Fern can be helpful when building a FastAPI server.

<div style="position: relative; padding-bottom: 62.5%; height: 0;"><iframe src="https://www.loom.com/embed/42de542022de4e55a1349383c7a465eb?sid=be3234f7-e0e2-4454-a510-caf4450b271d" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></iframe></div>

## Getting started

<Steps>

### Define your API

Define your API using the [OpenAPI Specification](/learn/api-definition/openapi/overview) or the [Fern Definition](/learn/api-definition/fern/overview).

### Add the FastAPI generator

Add the FastAPI server generator to your `generators.yml` file.

<CodeBlock title="generators.yml">
```yaml
groups:
fastapi-server:
generators:
- name: fernapi/fern-fastapi-server
version: 0.9.3
output:
location: local-file-system
path: ../app/server
```
</CodeBlock>

### Generate code

Run the [CLI](/learn/cli-api/cli-reference/cli-overview) command `fern generate --group fastapi-server`.

### Implement the functions

Provide the business logic by implementing each function. For example, if we were implenting the IMDb API, we would implement the `get_movie` function.

<CodeBlock title="src/movies_service.py">
```python
from .generated.fern import AbstractMoviesService, Movie, MovieDoesNotExistError, MovieId

class MoviesService(AbstractMoviesService):
def get_movie(self, *, movie_id: str) -> Movie:
if movie_id == "titanic":
return Movie(
id=MovieId.from_str("titantic"),
title="Titanic",
rating=9.8,
)
raise MovieDoesNotExistError(MovieId.from_str(movie_id))
```
</CodeBlock>

### Run the server

```bash
poetry run start
```

### Call the API 🚀

```bash
$ curl --location --request GET --silent 'localhost:8080/movies/titanic' | jq .
{
"id": "titantic",
"title": "Titanic",
"rating": 9.8
}

$ curl --location --request GET --silent 'localhost:8080/movies/oceans-11' | jq .
{
"error": "MovieDoesNotExistError",
"errorInstanceId": "f6e1d69c-bf97-42d5-bc89-5e42773e3880",
"content": "oceans-11"
}
```

</Steps>

## Advanced Configurations

Tailor the `config` of the FastAPI server generator to your needs. The default values for all options are `false`.

| Configuration Option | Description |
| -------------------- | ----------- |
| `include_validators` | |
| `skip_formatting` | |
| `async_handlers` | |

<Note>The configuration options are accessible in [`custom_config.py`](https://github.com/fern-api/fern/blob/main/generators/python/src/fern_python/generators/fastapi/custom_config.py).</Note>

### Example Configuration

<CodeBlock title="generators.yml">
```diff
groups:
fastapi-server:
generators:
- name: fernapi/fern-fastapi-server
version: 0.9.3
output:
location: local-file-system
path: ../app/server
+ config:
+ include_validators: true
+ skip_formatting: true
+ async_handlers: true
```

22 changes: 22 additions & 0 deletions fern/pages/servers/introduction.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
title: What is Server Code Generation?
description: Generate server boilerplate code from an API specification including OpenAPI, Swagger, AsyncAPI, and Fern Definition.
subtite: Generate types and networking logic for your server framework of choice.
slug: server-codegen
---

Fern's server-side generators output boilerplate application code that includes models and networking logic. This is intended for API First developers, who write their API definition before building their app. Fern supports generating backend code from an OpenAPI specification or Fern Definition.

## Supported server frameworks

- Node.js [Express](/learn/express)
- Python [FastAPI](/learn/fastapi)
- Java [Spring Boot](/learn/spring)

Want to request a new server framework? [Let us know](https://github.com/fern-api/fern/issues/new?assignees=&labels=&projects=&template=feature-request.md&title=%5BFeature%5D).

## Why use Fern for server code generation?

1. **Save time**: generate boilerplate code instead of writing it.
1. **Compile-time safety**: get validation that your endpoints are being served correctly.
1. **Develop API-first**: design your API contract before you start building your app. Pick the best server framework for the job.
Loading
Loading