Skip to content

Instantly share code, notes, and snippets.

@wallymathieu
Forked from akhansari/onion-1.fs
Last active September 20, 2022 19:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wallymathieu/68b14bcd3e45c4c5b040b60c558a5318 to your computer and use it in GitHub Desktop.
Save wallymathieu/68b14bcd3e45c4c5b040b60c558a5318 to your computer and use it in GitHub Desktop.
F# : Onion architecture in a nutshell
// 1. pure, don't think about IO at all
module Domain =
let add x y = x + y
// 2. think about IO but not its implementation
module App =
let add (getX: unit -> Async<int32>) y =
async {
let! x = getX ()
return Domain.add x y
}
// 3. IO implementation
module Infra =
let getX () = async { return 7 }
// 4. inject dependencies
module Startup =
let add = App.add Infra.getX
// demo
Startup.add 3
|> Async.RunSynchronously
|> printfn "%A" // 10
// 1. pure, don't think about IO at all
module Domain =
let add x y = x + y
// 2. think about IO but not its implementation
module App =
let add (getX: unit -> Async<int32>) y =
async {
let! x = getX ()
return Domain.add x y
}
// 3. IO implementation
module Infra =
open System.Data.SqlClient
let newConnection () = new SqlConnection ()
let getX conn = async { return 7 }
// 4. inject dependencies
module Startup =
let add y =
async {
use conn = Infra.newConnection ()
return! App.add (fun () -> Infra.getX conn) y
}
// demo
Startup.add 3
|> Async.RunSynchronously
|> printfn "%A" // 10
// 1_domain.ts
// 1. pure, don't think about IO at all
export function add(x: number, y: number) {
return x+y;
}
// 2_app.ts
// 2. think about IO but not its implementation
import * as Domain from './1_domain'
export async function add( getX: () => Promise<number>, y: number) {
const x = await getX()
return Domain.add(x, y);
}
// 3_infra.ts
// 3. IO implementation
import fetch from 'node-fetch';
export async function getX(apiUrl:string): Promise<number> {
const response = await fetch(apiUrl, { method: 'GET'});
const data = await response.json();
if (response.ok) {
return (data as number);
} else {
return Promise.reject(`Got an error response ${JSON.stringify(data)}`);
}
}
export function getConfigurationUrl() : string {
throw new Error('Function not implemented.');
}
// 4_index.ts
import * as App from './2_app'
import * as Infra from './3_infra'
// 4. inject dependencies
export function add (y:number){
const apiUrl = Infra.getConfigurationUrl();
return App.add ( ()=> Infra.getX(apiUrl), y);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment