| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
parent directory.. | ||||
F# bindings for FastAPI, a modern, fast web framework for building APIs with Python.
open Fable.Python.FastAPI
open Fable.Python.Pydantic
// Create FastAPI app
let app = FastAPI(title = "My API", version = "1.0.0")
// Define a Pydantic model
[<Py.ClassAttributes(style = Py.ClassAttributeStyle.Attributes, init = false)>]
type User(Id: int, Name: string, Email: string) =
inherit BaseModel()
member val Id: int = Id with get, set
member val Name: string = Name with get, set
member val Email: string = Email with get, set
// Define API endpoints
[<APIClass>]
type API() =
[<Get("/")>]
static member root() : obj =
{| message = "Hello World" |}
[<Get("/users/{user_id}")>]
static member get_user(user_id: int) : User =
User(Id = user_id, Name = "Alice", Email = "alice@example.com")
[<Post("/users")>]
static member create_user(user: User) : obj =
{| status = "created"; user = user |}let router = APIRouter(prefix = "/users", tags = ResizeArray ["users"])
[<APIClass>]
type UsersAPI() =
[<RouterGet("/")>]
static member list_users() : obj =
{| users = [] |}
[<RouterGet("/{user_id}")>]
static member get_user(user_id: int) : obj =
{| user_id = user_id |}When returning anonymous records ({| ... |}) from API endpoints, be aware that F#'s int type compiles to Fable's int32, which is not a native Python int. This can cause serialization errors with FastAPI's jsonable_encoder.
// This may fail with: "Unable to serialize unknown type: Int32"
[<Delete("/items/{item_id}")>]
static member delete_item(item_id: int) : obj =
{| status = "deleted"; item_id = item_id |} // item_id is int32, not native intOption 1: Use nativeint for values in anonymous records
[<Delete("/items/{item_id}")>]
static member delete_item(item_id: int) : obj =
{| status = "deleted"; item_id = nativeint item_id |}Option 2: Define response models as Pydantic BaseModels
[<Py.ClassAttributes(style = Py.ClassAttributeStyle.Attributes, init = false)>]
type DeleteResponse(Status: string, ItemId: int) =
inherit BaseModel()
member val Status: string = Status with get, set
member val ItemId: int = ItemId with get, set
[<Delete("/items/{item_id}")>]
static member delete_item(item_id: int) : DeleteResponse =
DeleteResponse(Status = "deleted", ItemId = item_id)Option 3: Return Pydantic models directly
Pydantic models serialize correctly because FastAPI uses the model's schema:
[<Get("/users")>]
static member get_users() : ResizeArray<User> =
users // ResizeArray<User> works, User is a BaseModel| Return Type | int32 Serialization |
|---|---|
| Pydantic BaseModel | Works (uses __get_pydantic_core_schema__) |
| Anonymous record `{ | ... |
| ResizeArray<T> where T is BaseModel | Works |
Use ResizeArray<T> instead of F# arrays or lists for API responses:
let users = ResizeArray<User>()
[<Get("/users")>]
static member get_users() : ResizeArray<User> =
users // Compiles to Python list, serializes correctlyF# arrays ([| ... |]) compile to Fable's FSharpArray which may not serialize correctly with FastAPI.
# Build F# to Python
dotnet fable --lang python
# Run with uvicorn
uvicorn app:app --reloadFor hot-reloading during development:
# Terminal 1: Watch F# files
dotnet fable --lang python --watch
# Terminal 2: Run uvicorn with reload
uvicorn app:app --reloadOr use the justfile:
just dev-fastapi| Back | FazBrowse Home | New Git URL |