diff --git a/test/Falco.OpenApi.Tests.App/Falco.OpenApi.Tests.App.fsproj b/test/Falco.OpenApi.Tests.App/Falco.OpenApi.Tests.App.fsproj new file mode 100644 index 0000000..dd6ad9d --- /dev/null +++ b/test/Falco.OpenApi.Tests.App/Falco.OpenApi.Tests.App.fsproj @@ -0,0 +1,18 @@ + + + net8.0 + + + + + + + + + + + + + + + diff --git a/test/Falco.OpenApi.Tests.App/Program.fs b/test/Falco.OpenApi.Tests.App/Program.fs new file mode 100644 index 0000000..0c7e9e6 --- /dev/null +++ b/test/Falco.OpenApi.Tests.App/Program.fs @@ -0,0 +1,62 @@ +module Falco.OpenApi.Tests.App + +open Falco +open Falco.OpenApi +open Falco.Routing +open Microsoft.AspNetCore.Builder +open Microsoft.Extensions.DependencyInjection +open Microsoft.Extensions.Hosting + +type Greeting = + { Message : string } + +let endpoints = + [ + get "/" (Response.ofPlainText "Hello World!") + |> OpenApi.name "HelloWorld" + |> OpenApi.summary "A hello world greeter" + |> OpenApi.description "This is a simple endpoint that will return a greeting message." + + mapGet "/hello/{name?}" + (fun route -> + let name = route?name.AsStringNonEmpty("world") + let age = route?age.AsIntOption() + + let message = + match age with + | Some a -> $"Hello {name}, you are {a} years old!" + | _ -> $"Hello {name}!" + + { Message = message }) + Response.ofJson + |> OpenApi.name "Greeting" + |> OpenApi.summary "A friendly greeter" + |> OpenApi.description "This endpoint will provide a customized greeting based on the name and age (optional) provided." + |> OpenApi.route [ + { Type = typeof; Name = "Name"; Required = false } ] + |> OpenApi.query [ + { Type = typeof; Name = "Age"; Required = false } ] + |> OpenApi.acceptsType typeof + |> OpenApi.returnType typeof + ] + +let bldr = WebApplication.CreateBuilder() + +bldr.Services + .AddFalcoOpenApi() + .AddSwaggerGen() + |> ignore + +let wapp = bldr.Build() + +wapp.UseHttpsRedirection() + .UseSwagger() + .UseSwaggerUI() +|> ignore + +wapp.UseFalco(endpoints) +|> ignore + +wapp.Run() + +type Program() = class end diff --git a/test/Falco.OpenApi.Tests.App/appsettings.json b/test/Falco.OpenApi.Tests.App/appsettings.json new file mode 100644 index 0000000..e797029 --- /dev/null +++ b/test/Falco.OpenApi.Tests.App/appsettings.json @@ -0,0 +1,8 @@ +{ + "Urls": "https://localhost:5001", + "Logging": { + "LogLevel": { + "Default": "Information" + } + } +} diff --git a/test/Falco.OpenApi.Tests/Falco.OpenApi.Tests.fsproj b/test/Falco.OpenApi.Tests/Falco.OpenApi.Tests.fsproj index 92041af..98980ed 100644 --- a/test/Falco.OpenApi.Tests/Falco.OpenApi.Tests.fsproj +++ b/test/Falco.OpenApi.Tests/Falco.OpenApi.Tests.fsproj @@ -1,4 +1,4 @@ - + net8.0 false @@ -6,6 +6,8 @@ + + @@ -26,6 +28,7 @@ - + + diff --git a/test/Falco.OpenApi.Tests/OpenApiTests.fs b/test/Falco.OpenApi.Tests/OpenApiTests.fs new file mode 100644 index 0000000..4e8c77a --- /dev/null +++ b/test/Falco.OpenApi.Tests/OpenApiTests.fs @@ -0,0 +1,123 @@ +module Falco.OpenApi.Tests.OpenApi + +open Xunit + +[] +let ``Can GET /hello``() = + let factory = FalcoOpenApiTestServer.createFactory () + let client = factory.CreateClient() + let response = client.GetAsync("/").Result + let content = response.Content.ReadAsStringAsync().Result + Assert.Equal("Hello World!", content) + +[] +let ``Can GET /hello/{name?}`` () = + let factory = FalcoOpenApiTestServer.createFactory () + let client = factory.CreateClient() + let response = client.GetAsync("/hello").Result + let content = response.Content.ReadAsStringAsync().Result + Assert.Equal("""{"Message":"Hello world!"}""", content) + + let response = client.GetAsync("/hello/John").Result + let content = response.Content.ReadAsStringAsync().Result + Assert.Equal("""{"Message":"Hello John!"}""", content) + + let response = client.GetAsync("/hello/John?age=42").Result + let content = response.Content.ReadAsStringAsync().Result + Assert.Equal("""{"Message":"Hello John, you are 42 years old!"}""", content) + +let private expectedOpenApiDoc = """{ + "openapi": "3.0.1", + "info": { + "title": "testhost", + "version": "1.0" + }, + "paths": { + "/hello/{name}": { + "get": { + "tags": [ + "Greeting" + ], + "summary": "A friendly greeter", + "description": "This endpoint will provide a customized greeting based on the name and age (optional) provided.", + "operationId": "Greeting", + "parameters": [ + { + "name": "Name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "Age", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Greeting" + } + } + } + } + } + } + }, + "/": { + "get": { + "tags": [ + "HelloWorld" + ], + "summary": "A hello world greeter", + "description": "This is a simple endpoint that will return a greeting message.", + "operationId": "HelloWorld", + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { + "schemas": { + "Greeting": { + "type": "object", + "properties": { + "message": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + } + } +}""" + +[] +let ``Can GET /swagger/v1/swagger.json`` () = + let factory = FalcoOpenApiTestServer.createFactory () + let client = factory.CreateClient() + let response = client.GetAsync("/swagger/v1/swagger.json").Result + let content = response.Content.ReadAsStringAsync().Result + Assert.Equal(expectedOpenApiDoc, content) diff --git a/test/Falco.OpenApi.Tests/TestHelpers.fs b/test/Falco.OpenApi.Tests/TestHelpers.fs new file mode 100644 index 0000000..8951476 --- /dev/null +++ b/test/Falco.OpenApi.Tests/TestHelpers.fs @@ -0,0 +1,9 @@ +namespace Falco.OpenApi.Tests + +open Microsoft.AspNetCore.Mvc.Testing +open Microsoft.AspNetCore.TestHost +open Falco.OpenApi.Tests.App + +module FalcoOpenApiTestServer = + let createFactory() = + new WebApplicationFactory()