Orsak.AspNetCore.OpenApi
0.8.0
dotnet add package Orsak.AspNetCore.OpenApi --version 0.8.0
NuGet\Install-Package Orsak.AspNetCore.OpenApi -Version 0.8.0
<PackageReference Include="Orsak.AspNetCore.OpenApi" Version="0.8.0" />
<PackageVersion Include="Orsak.AspNetCore.OpenApi" Version="0.8.0" />
<PackageReference Include="Orsak.AspNetCore.OpenApi" />
paket add Orsak.AspNetCore.OpenApi --version 0.8.0
#r "nuget: Orsak.AspNetCore.OpenApi, 0.8.0"
#:package Orsak.AspNetCore.OpenApi@0.8.0
#addin nuget:?package=Orsak.AspNetCore.OpenApi&version=0.8.0
#tool nuget:?package=Orsak.AspNetCore.OpenApi&version=0.8.0
Orsak
eff {
let! line = Console.readLine ()
do! Console.writeLine $"Hello {line}"
}
Orsak is a library for functional effects in F#, allowing pragmatic and composable modelling of side-effects through interfaces. It is inspired by Zio, with F# encoding similar to the approach described by Bartosz Sypytkowski here. The library intends to be as complete as is practical, including a computation expression, supporting functions and operators, and should be compatible with FSharpPlus.
However, Orsak is not intended to be a framework. Rather, it is encouraged and recommended to make use of the existing .NET ecosystem, and Orsak is intended to make that as easy and friction-free as possible. It can be used piecemeal, and introduced to existing codebases in isolated chunks.
This implementation makes use of resumable code to implement the computation expression builder for the lowest possible overhead.
The builder also has various overloads for Bind, allowing for friction free interop with TaskLike<'a>, Async<'a>, Result<'T,'E> and more.
It supports for, while, use, try-with and try-finally, and also applicative bind when the error-type supports +.
While the computation expression is the intended way of working with effects, the corresponding module should contain all the expected functions.
Show me the code
Imagine having the following interfaces, which each describes some none-pure operation, that is, they both have side-effects.
type IButtonPusher =
abstract member PushButton: unit -> Task<unit>
type IBeanCounter =
abstract member CountBeans: unit -> Task<int>
By creating the following helper-interfaces
type IButtonPusherProvider =
abstract member ButtonPusher: IButtonPusher
type IBeanCounterProvider =
abstract member BeanCounter: IBeanCounter
and the following helpers
let pushButton () =
Effect.Create(fun (provider: #IButtonPusherProvider) -> provider.ButtonPusher.PushButton())
let countBeans () =
Effect.Create(fun (provider: #IBeanCounterProvider) -> provider.BeanCounter.CountBeans())
then it is possible to partially apply, or 'inject' these interfaces into your code by simply making functions calls:
let pushAndCount<'a, 'b when 'a :> IButtonPusherProvider and 'a :> IBeanCounterProvider> ()
: Effect<'a, int, 'b> =
eff {
do! pushButton ()
let! beans = countBeans ()
return beans * 2
}
In essence, this is a partially applied function, waiting for an instance of 'a which implements both IButtonPusherProvider and IBeanCounterProvider.
Now, in practise you do not need to specify any of this, the type inference will keep track of the requirements of your provider.
let pushAndCount () =
eff {
do! pushButton()
let! beans = countBeans()
return beans * 2
}
And adding further calls to functions with side-effects will apply the correct constraints seamlessly.
Generating the boilerplate
The provider interfaces and Effect.Create helpers above can be generated at build time by
Orsak.Myriad, a Myriad plugin:
[<GenEffects>]
type IButtonPusher =
abstract member PushButton: unit -> Task<unit>
See Generating code for setting it up, and the showcase sample for a complete example.
Documentation
The documentation is at https://johsand.github.io/Orsak/, with guides to errors, resilience, effect sequences, web APIs, OpenAPI, testing and generating code, and the API reference.
To build, test, or work on the documentation, see CONTRIBUTING.md.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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
- FSharp.Core (>= 8.0.300)
- Microsoft.AspNetCore.OpenApi (>= 10.0.14)
- Orsak.AspNetCore (>= 0.8.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.8.0 | 72 | 11/8/2026 |
### Changed
Orsak and Orsak.AspNetCore target net8.0 and net10.0. net6.0 is no longer supported, so ITimeProvider, Time, CancellationSource, CancellationScope, Orsak.Resilience and the worker count metric are available on every target. Microsoft.Extensions.*.Abstractions dependencies now start at 8.0.0. 0.7.x is the last release supporting net6.0
### Added
CancellationProvider: `fromSource` provides a source the caller owns, and `create` a new one, disposed with the provider
Time.delay, which waits on the environment's clock, and ends early when the environment's cancellation source is cancelled
Log: effects that log message templates with the environment's `ILogger`, e.g. `Log.Information("Imported {Count} rows", count)`
CancellationScope: a `CancellationTokenSource` linked to a token, begun and disposed around an effect, so each source lives exactly as long as the effects using it. `Cancellation.within` runs an effect in one, nested in the current scope if there is one, and `Cancellation.timeout` cancels it after a duration, stopping the effect, unlike `Effect.timeout`. `cancellableEff` is a computation expression whose effects run in one
Orsak.Myriad: an environment may grow into a `CancellationScope` by adding an `ICancellationProvider`, and an environment providing an `ICancellationProvider` begins its scopes nested in its source, with `CancellationScope.NestedIn`, so a scope begun in a scope is cancelled with it
Orsak.AspNetCore: endpoints carry `EffectType` metadata, the type of the effect their handler creates, also for a handler that is a lambda
Orsak.AspNetCore: a runner implementing `IDescribeResponses` describes the responses of each endpoint from the type of its effect, as `ResponseDescription` metadata, which is an `IProducesResponseTypeMetadata` for ApiExplorer and OpenAPI generators
Orsak.AspNetCore.OpenApi (.NET 10): `options.AddEffectEndpoints()` adds the endpoints mapped with `MapEffectEndpoints` to Microsoft.AspNetCore.OpenApi's documents, described from their routes, handlers, XML docs and metadata, explicit metadata first
Orsak.AspNetCore.OpenApi: `options.AddFSharpSchemas()` describes options, value options, lists, sets and maps as System.Text.Json writes them: an option is its value or null and not required, and a list, set or map is never null
### Fixed
Effects written in a quotation, such as a route handler lambda or a scaling job's work, can use `let!`, `return!`, `for`, `while` and `Effect.Create`: each overload of the builders has a compiled name of its own, so deserializing the quotation can bind it
### Removed
Orsak.AspNetCore: `scalingJob2`, a prototype, is internal again