Construyendo una API web con F# y Giraffe en .NET 6

En este tutorial, aprenderás cómo construir una API web utilizando F# y Giraffe, una biblioteca de enrutamiento HTTP para .NET. Crearemos una API simple que permita leer y crear publicaciones de blog.

F# es un lenguaje de programación funcional que se ejecuta en la plataforma .NET, y puede ser utilizado para crear aplicaciones web y servicios de backend. La sintaxis simple y expresiva de F# lo hace ideal para construir aplicaciones concisas y eficientes. Giraffe, por otro lado, es una biblioteca de enrutamiento HTTP que se integra perfectamente con F#, lo que permite a los desarrolladores crear aplicaciones web de manera fácil y rápida.

En este tutorial, utilizaremos .NET 6, la última versión del marco de trabajo de .NET. .NET 6 ofrece un gran rendimiento y mejoras de productividad para los desarrolladores.

Comencemos con la creación de nuestra API web con F# y Giraffe en .NET 6.

1
2
dotnet new console -lang "F#" -o api
cd api

Editar el archivo api.fsproj

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>api</RootNamespace>
</PropertyGroup>

<ItemGroup>
<Compile Include="Blog.fs" />
<Compile Include="Program.fs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Giraffe" Version="6.0.0" />
</ItemGroup>

</Project>

En el archivo Blog.fs, definimos un módulo Blog que contiene la lógica del blog. Primero, definimos un tipo de datos BlogPost que representa una publicación en el blog y contiene un título y un contenido.

Luego, definimos un tipo de datos BlogDb que representa una base de datos de blog y contiene una lista mutable de publicaciones. El BlogDb tiene dos miembros, uno que devuelve todas las publicaciones existentes en la base de datos y otro que agrega una nueva publicación a la lista.

A continuación, definimos dos manejadores HTTP: getPostsHttpHandler y createPostHttpHandler. El primero se encarga de manejar solicitudes GET a la ruta /posts y devuelve todas las publicaciones de blog almacenadas en la base de datos. El segundo maneja solicitudes POST a la ruta /posts/create y agrega una nueva publicación a la base de datos.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
module Blog 

open System
open System.Threading.Tasks
open Microsoft.AspNetCore.Http
open Giraffe

[<CLIMutable>]
type BlogPost = {
title: string
content: string
}

type BlogDb() =

let mutable allBlogPosts : BlogPost list = []

member this.GetAllPosts = fun() -> allBlogPosts

member this.AddPost (newPost : BlogPost) =
allBlogPosts <- (newPost::allBlogPosts)
allBlogPosts

type BlogServiceTree = {
getBlogDb : unit -> BlogDb
}

let getPostsHttpHandler (serviceTree: BlogServiceTree) =
fun (next : HttpFunc) (ctx : HttpContext) ->
json (serviceTree.getBlogDb().GetAllPosts()) next ctx

let createPostHttpHandler (serviceTree: BlogServiceTree) =
fun (next : HttpFunc) (ctx : HttpContext) ->
task {
let! newPostJson = ctx.BindJsonAsync<BlogPost>()
serviceTree.getBlogDb().AddPost(newPostJson) |> ignore
return! json (newPostJson) next ctx
}

En el archivo Program.fs, definimos el webApp, que es un árbol de rutas de Giraffe. El árbol de rutas incluye una ruta raíz que devuelve una cadena de texto y una subruta /posts que contiene dos rutas adicionales: una para obtener todas las publicaciones del blog y otra para crear una nueva publicación.

Finalmente, configuramos la aplicación y los servicios que utilizamos. En el método configureServices, agregamos la dependencia de Giraffe y en el método configureApp, configuramos la aplicación para usar Giraffe y nuestro árbol de rutas webApp.

Para ejecutar la aplicación, simplemente escribimos dotnet run en la terminal desde el directorio del proyecto.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
open System
open Microsoft.AspNetCore.Builder
open Microsoft.AspNetCore.Hosting
open Microsoft.Extensions.Hosting
open Microsoft.Extensions.Logging
open Microsoft.Extensions.DependencyInjection

open Blog
open Giraffe

(* Web App Configuration *)

let webApp =
let blogDb = new BlogDb()

let serviceTree = {
getBlogDb = fun() -> blogDb
}

choose[
route "/" >=> text "iamanapi"
subRoute "/posts"
(choose [
route "" >=> GET >=> warbler (fun _ ->
(getPostsHttpHandler serviceTree))
route "/create"
>=> POST
>=> warbler (fun _ ->
(createPostHttpHandler serviceTree))
])
]

(* Infrastructure Configuration *)

let configureApp (app : IApplicationBuilder) =
app.UseGiraffe (webApp)

let configureServices (services : IServiceCollection) =
// Add Giraffe dependencies
services.AddGiraffe() |> ignore

[<EntryPoint>]
let main _ =
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(
fun webHostBuilder ->
webHostBuilder
.Configure(configureApp)
.ConfigureServices(configureServices)
|> ignore)
.Build()
.Run()
0

Ejecutar

1
dotnet run

Si todo funciona correctamente, deberíamos ver un mensaje que indica que la aplicación se está ejecutando. En este punto, podemos abrir un navegador web y acceder a la dirección http://localhost:5000/posts para ver la lista de publicaciones de nuestro blog. Podemos crear una nueva publicación enviando una solicitud POST a la dirección http://localhost:5000/posts/create con el título y el contenido de la publicación en formato JSON.

resultado en consola