-
Notifications
You must be signed in to change notification settings - Fork 170
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add readme draft * Capitalize ID * Update example and lowercase websocket * Updating readme spec * Add concepts folder * Removing files * Update readme and add concept draft * Revise core concepts * Revise readme from food deliver example to weather report * Update readme * Undo readme changes * Fix casing I hope * revise docs * Remove hathora.yml Co-authored-by: Danny Sheridan <[email protected]> Co-authored-by: Danny Sheridan <[email protected]>
- Loading branch information
1 parent
3900702
commit b78355c
Showing
7 changed files
with
310 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,94 +1,110 @@ | ||
# Fern | ||
|
||
Fern is an open source framework that makes it easier to build APIs. | ||
</p> | ||
|
||
Fern allows you to | ||
TODO Fern makes it easy to define APIs. | ||
|
||
1. Define a source-of-truth for your API | ||
2. Autogenerate idiomatic & typesafe clients and servers | ||
3. Supports WebSocket and REST APIs | ||
4. Easily manage backwards compatiblity | ||
### Single source of truth | ||
|
||
Fern is interoperable with Open API so you are never locked in. | ||
Define your data model and your APIs in **one place** in your repo. | ||
|
||
## Example Spec | ||
### Type-safe servers and clients | ||
|
||
Below we have written out a sample spec for a Food Delivery App. | ||
Run `fern generate` to automatically generate **server stubs** and **type-safe clients**. | ||
|
||
> "Wow, this codegen is so idiomatic!" - Chuck Norris | ||
## What languages are supported? | ||
|
||
The Fern compiler reads API definitions written in the [human-readable YML format](/docs/fern_definitions.md) and produces a JSON [intermediate representation](/docs/intermediate_representation.md) (IR). | ||
|
||
| **Language** | **Server Stub** | **Client** | | ||
| ------------ | ---------------- | ---------- | | ||
| Java | ✅ | ✅ | | ||
| TypeScript | 🚧 _in progress_ | ✅ | | ||
| Python | 🚧 | 🚧 | | ||
|
||
_Interested in another language? [Get in touch]([email protected])_ | ||
|
||
## Let's do an example | ||
|
||
Here's a simple API to get the current weather report: | ||
|
||
```yaml | ||
ids: | ||
- MenuItemId | ||
- OrderId: long | ||
# api.yml | ||
|
||
types: | ||
DeliveryMethod: | ||
enum: | ||
- PICKUP | ||
- DELIVERY | ||
OrderStatus: | ||
union: | ||
pickup: PickupOrderStatus | ||
delivery: DeliveryOrderStatus | ||
PickupOrderStatus: | ||
WeatherReport: | ||
properties: | ||
tempInFahrenheit: double | ||
humidity: | ||
type: integer | ||
docs: a number between 0 and 100 | ||
conditions: WeatherConditions | ||
WeatherConditions: | ||
enum: | ||
- PREPARING | ||
- READY_FOR_PICKUP | ||
- PICKED_UP | ||
DeliveryOrderStatus: | ||
enum: | ||
- PREPARING | ||
- ON_THE_WAY | ||
- DELIVERED | ||
- SUNNY | ||
- CLOUDY | ||
- RAINY | ||
|
||
services: | ||
http: | ||
OrderService: | ||
base-path: /order | ||
WeatherService: | ||
base-path: /weather | ||
endpoints: | ||
addItemToCart: | ||
docs: Adds a menu item to a cart. | ||
method: POST | ||
path: /add | ||
request: | ||
properties: | ||
menuItemId: MenuItemId | ||
quantity: integer | ||
placeOrder: | ||
method: POST | ||
path: /order/new | ||
request: | ||
properties: | ||
deliveryMethod: DeliveryMethod | ||
tip: optional<double> | ||
response: OrderId | ||
errors: | ||
union: | ||
emptyCart: EmptyCartError | ||
|
||
websocket: | ||
OrderStatusChannel: | ||
messages: | ||
subscribeToOrderStatus: | ||
origin: client | ||
body: OrderId | ||
response: | ||
properties: | ||
orderStatus: OrderStatus | ||
etaInMinutes: integer | ||
behavior: ongoing | ||
errors: | ||
union: | ||
notFound: OrderNotFoundError | ||
|
||
errors: | ||
OrderNotFoundError: | ||
http: | ||
statusCode: 404 | ||
EmptyCartError: | ||
http: | ||
statusCode: 400 | ||
getWeather: | ||
method: GET | ||
path: /{zipCode} | ||
parameters: | ||
zipCode: string | ||
response: WeatherReport | ||
``` | ||
### The server | ||
Here's the Typescript/express server stubs that Fern generates: | ||
TODO | ||
### The client | ||
Let's say we published the client to npm... TODO make this better. Here's an example of someone consuming it: | ||
```ts | ||
import { WeatherService } from "weather-api"; | ||
|
||
const weatherService = WeatherService.create({ | ||
baseUrl: | ||
}) | ||
|
||
const weatherReport = await Weather | ||
|
||
``` | ||
|
||
The app has REST endpoints so that clients can add items to their cart and place orders. It also has a websocket channel where a client can subscribe to updates about an order's ETA. | ||
## Contributing | ||
|
||
The team welcomes contributions! To make code changes to one of the Fern repos: | ||
|
||
- Fork the repo and make a branch | ||
- Write your code | ||
- Open a PR (optionally linking to a Github issue) | ||
|
||
## Getting started | ||
|
||
### Installation | ||
|
||
`$ npm install -g fern-api` | ||
|
||
### Initialize Fern in your repo | ||
|
||
`fern init` | ||
|
||
### Generate code | ||
|
||
`fern generate` | ||
|
||
`fern add` | ||
|
||
## License | ||
|
||
This spec can be used to generate clients and servers. | ||
This tooling is made available under the [MIT License](LICENSE). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
# Model | ||
|
||
</p> | ||
|
||
The _Fern model_ describes the data model used to defining your APIs in Fern. | ||
|
||
## Core Concepts | ||
|
||
- [imports](#imports) | ||
- [ids](#ids) | ||
- [types](#types) | ||
- [errors](#errors) | ||
- [services](#services) | ||
|
||
### Imports | ||
|
||
_Reference Core Concepts from other Fern models._ | ||
|
||
```yml | ||
import: | ||
blog: blog.yml | ||
user: user.yml | ||
``` | ||
### Ids | ||
_Identifiers are named and default to string._ | ||
```yml | ||
ids: | ||
blog: BlogPostId | ||
user: UserId | ||
publication: PublicationId | ||
``` | ||
### Types | ||
_Users may define the following kinds of types. These can be referenced by their name elsewhere in a Fern data model._ | ||
- [Primitives](#primitives) | ||
- [Objects](#objects) | ||
- [Aliases](#aliases) | ||
- [Enums](#enums) | ||
- [Containers](#containers) | ||
### Errors | ||
_Users may define a name and structure for errors so that clients can expect specific pieces of information on failure._ | ||
_Structured errors_ have the following properties: | ||
- _Name_ - a user chosen description e.g. `BlogNotFoundError` | ||
- _Status code_ - an optional HTTP status code e.g. `404` | ||
|
||
```yml | ||
errors: | ||
BlogNotFoundError: | ||
http: | ||
statusCode: 404 | ||
UserInvalidError: | ||
http: | ||
statusCode: 400 | ||
``` | ||
|
||
### Services | ||
|
||
_HTTP endpoints that support `GET`, `PUT`, `POST`, `DELETE`_ | ||
|
||
```yml | ||
services: | ||
http: | ||
PostsService: | ||
base-path: /posts | ||
endpoints: | ||
getPost: | ||
method: GET | ||
path: /{postId} | ||
parameters: | ||
postId: string | ||
request: CreatePostRequest | ||
response: PostId | ||
publishPost: | ||
method: POST | ||
path: /publish | ||
request: PublishPostRequest | ||
response: PublishPostResponse | ||
deletePost: | ||
method: DELETE | ||
path: /{postId} | ||
parameters: | ||
postId: string | ||
``` | ||
|
||
### Primitives | ||
|
||
_Types that are built-in to the Fern data model._ | ||
|
||
```yml | ||
types: | ||
Primitives: | ||
properties: | ||
a: any # a catch-all type | ||
b: boolean | ||
c: double | ||
d: integer | ||
e: long | ||
f: string | ||
``` | ||
|
||
### Objects | ||
|
||
_A collection of named properties, each of which has their own Fern type. Below is an example of a `Post` object._ | ||
|
||
```yml | ||
types: | ||
Post: | ||
docs: A blog post | ||
properties: | ||
id: PostId | ||
type: PostType | ||
title: string | ||
author: Author | ||
content: string | ||
Podcast: | ||
docs: An audio version of a blog post | ||
extends: Post | ||
properties: | ||
duration: integer | ||
coverArt: string | ||
``` | ||
|
||
### Aliases | ||
|
||
_A new name for an existing type to make a user's types more self-documenting._ | ||
|
||
```yml | ||
types: | ||
PostType: | ||
properties: | ||
length: PostLength | ||
``` | ||
|
||
### Unions | ||
|
||
_A tagged union data structure that can take on several different, but fixed, types._ | ||
|
||
```yml | ||
types: | ||
Author: | ||
union: | ||
anonymous: {} | ||
name: string | ||
``` | ||
|
||
### Enums | ||
|
||
_A type consisting of named string variants._ | ||
|
||
```yml | ||
types: | ||
BlogStatus: | ||
enum: | ||
- DRAFT | ||
- PUBLISHED | ||
- ARCHIVED | ||
``` | ||
|
||
### Containers | ||
|
||
- `list<T>` - an ordered sequence of items of type `T`. | ||
- `map<K, V>` - values of type `V` each indexed by a unique key of type `K` (keys are unordered). | ||
- `optional<T>` - represents a value of type `T` which is either present or not present. | ||
- `set<T>` - a collection of distinct values of type `T`. |
Oops, something went wrong.