Etymon.Api
0.1.0-preview.9
dotnet add package Etymon.Api --version 0.1.0-preview.9
NuGet\Install-Package Etymon.Api -Version 0.1.0-preview.9
<PackageReference Include="Etymon.Api" Version="0.1.0-preview.9" />
<PackageVersion Include="Etymon.Api" Version="0.1.0-preview.9" />
<PackageReference Include="Etymon.Api" />
paket add Etymon.Api --version 0.1.0-preview.9
#r "nuget: Etymon.Api, 0.1.0-preview.9"
#:package Etymon.Api@0.1.0-preview.9
#addin nuget:?package=Etymon.Api&version=0.1.0-preview.9&prerelease
#tool nuget:?package=Etymon.Api&version=0.1.0-preview.9&prerelease
Etymon.Api
HTTP endpoints described once. This package performs no HTTP.
Part of the Etymon suite. Depends on
Etymon.Core, Etymon.Base, Etymon.Schema and Etymon.Schema.OpenApi — no
web framework, no HttpContext, no socket.
let getUser =
Api.get "getUser" (Route.one [ "users" ] (Param.guid "id") []) userSchema
|> Api.summary "Fetches one user by id"
|> Api.tag "Users"
|> Api.failsWith 404 problemSchema "No user with that id"
That is a value. Several interpreters read it, and because they all read the same one, none of them can describe the endpoint differently from the others:
| Package | What it produces |
|---|---|
Etymon.Api.Giraffe |
a Giraffe HttpHandler |
Etymon.Api.AspNetCore |
a minimal-API registration |
Etymon.Api.Client |
a typed HttpClient function |
| this package | OpenAPI 3.1 paths |
Etymon.Schema.TypeScript |
.d.ts for the frontend |
Adding Falco, Oxpecker or Saturn later is writing one more interpreter. The declarations do not change, and nothing already using them does either.
Routes are data, not format strings
Route.two [ "users" ] (Param.guid "id") [ "orders" ] (Param.int "orderId") []
Route.template route // "/users/{id}/orders/{orderId}" — OpenAPI and ASP.NET both
Route.parameters route // [ "id", Guid; "orderId", Int ] — what a generator reads
Route.toPath route (id, 42) // "/users/9d1c.../orders/42" — what a client requests
Route.matchPath route path // Some (id, 42) — what a server binds
One declaration; the template, the URL builder and the matcher all come out of
it. A printf-style route would read more prettily and be nearly impossible to
introspect, which would mean the OpenAPI path and the client both re-deriving
what the server already knows.
Zero, one and two path parameters have dedicated constructors rather than a
general combinator. That costs a little elegance and buys full inference with no
operator overloading — and a route with three or more parameters is already
telling you something. Route.many is the escape hatch.
Failures are declared, not discovered
|> Api.failsWith 404 problemSchema "No user with that id"
|> Api.failsWithNoBody 401 "Not authenticated"
An undeclared status is one a caller meets in production without warning: absent from the OpenAPI document, unknown to the generated client. So the adapters reject a handler returning a status the endpoint never declared, rather than passing it along undocumented.
Why GET has no request type variable
Api.get returns Endpoint<'Route, unit, 'Response>. Leaving the request type
open would make every declaration hit F#'s value restriction, and would let a
handler be written for a body that can never arrive.
Public surface
The complete public surface of this package, every value with its full signature
and its documentation, is in Surface.fsi beside this file. It is written by the
build from the implementation, so it is where to learn what a function hands
back without compiling anything.
Licence
MIT.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Etymon.Base (>= 0.1.0-preview.9)
- Etymon.Core (>= 0.1.0-preview.9)
- Etymon.Schema (>= 0.1.0-preview.9)
- Etymon.Schema.OpenApi (>= 0.1.0-preview.9)
- FSharp.Core (>= 8.0.100)
-
net8.0
- Etymon.Base (>= 0.1.0-preview.9)
- Etymon.Core (>= 0.1.0-preview.9)
- Etymon.Schema (>= 0.1.0-preview.9)
- Etymon.Schema.OpenApi (>= 0.1.0-preview.9)
- FSharp.Core (>= 8.0.100)
NuGet packages (4)
Showing the top 4 NuGet packages that depend on Etymon.Api:
| Package | Downloads |
|---|---|
|
Etymon.Api.Client
Calls an Etymon.Api endpoint over HTTP. The declaration is enough to build the URL, encode the body and decode the response, so a console application calling an Etymon-described API needs no web framework and no server. |
|
|
Etymon.Api.AspNetCore
Registers an Etymon.Api endpoint on ASP.NET Core minimal-API routing. Needs no third-party web framework: ASP.NET Core is the platform, so this is the adapter for an application that does not want one. |
|
|
Etymon.Api.Giraffe
Serves an Etymon.Api endpoint as a Giraffe HttpHandler. Does not replace Giraffe: the result composes into the routing you already have, so endpoints can be adopted one at a time. |
|
|
Etymon
The Etymon suite: one schema definition as the source of truth for JSON codecs, validation, OpenAPI, TypeScript, configuration and database structure. This package has no code of its own; it references the parts of the suite that cost nothing but FSharp.Core. The adapters (Etymon.Api.Giraffe, Etymon.Api.AspNetCore) and the generator package (Etymon.Invariants.FsCheck) are deliberately left out, because each carries a dependency that would then be everyone's. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0-preview.9 | 0 | 9/22/2026 |
| 0.1.0-preview.8 | 0 | 9/22/2026 |
| 0.1.0-preview.7 | 0 | 9/21/2026 |
| 0.1.0-preview.6 | 0 | 9/21/2026 |
| 0.1.0-preview.5 | 0 | 9/21/2026 |
| 0.1.0-preview.4 | 28 | 9/21/2026 |
| 0.1.0-preview.3 | 31 | 9/21/2026 |
| 0.1.0-preview.2 | 33 | 9/20/2026 |
| 0.1.0-preview.1 | 35 | 9/20/2026 |