Skip to content

Commit ac1d93c

Browse files
authored
Merge pull request #56 from RJSonnenberg/main
2 parents 8dc89a4 + 0e556ff commit ac1d93c

File tree

6 files changed

+83
-33
lines changed

6 files changed

+83
-33
lines changed

Directory.Packages.props

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
</PropertyGroup>
55
<ItemGroup>
66
<!-- Common -->
7-
<PackageVersion Include="Giraffe" Version="7.0.2" />
8-
<PackageVersion Include="Ionide.KeepAChangelog.Tasks" Version="0.1.8" />
9-
<PackageVersion Include="FSharp.Core" Version="8.0.300" />
7+
<PackageVersion Include="Giraffe" Version="8.0.0-alpha-003" />
8+
<PackageVersion Include="Ionide.KeepAChangelog.Tasks" Version="0.2.0" />
9+
<PackageVersion Include="FSharp.Core" Version="8.0.403" />
1010
<!-- Giraffe.OpenApi -->
1111
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
12-
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="8.0.16" />
12+
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="8.0.17" />
1313
<!-- Sample App -->
1414
<PackageVersion Include="Swashbuckle.AspNetCore" Version="8.1.4" />
1515
<!-- Analyzers -->

README.md

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@ An extension for the [Giraffe](https://github.com/giraffe-fsharp/Giraffe) Web Ap
99

1010
## Table of Contents
1111

12-
- [About](#about)
13-
- [Getting Started](#getting-started)
14-
- [Documentation](#documentation)
15-
- [Integration](#integration)
16-
- [addOpenApi](#addopenapi)
17-
- [addOpenApiSimple](#addopenapisimple)
18-
- [configureEndpoint](#configureendpoint)
19-
- [License](#license)
12+
- [Giraffe.OpenApi](#giraffeopenapi)
13+
- [Table of Contents](#table-of-contents)
14+
- [About](#about)
15+
- [Getting Started](#getting-started)
16+
- [Documentation](#documentation)
17+
- [Integration](#integration)
18+
- [addOpenApi](#addopenapi)
19+
- [addOpenApiSimple](#addopenapisimple)
20+
- [Behavior and Nuances](#behavior-and-nuances)
21+
- [configureEndpoint](#configureendpoint)
22+
- [License](#license)
2023

2124
## About
2225

@@ -108,12 +111,44 @@ Response body schema will be inferred from the types passed to `requestBody` and
108111

109112
### addOpenApiSimple
110113

111-
This method is a shortcut for simple cases. It accepts two generic type parameters - request and response, so the schema can be inferred from them.
114+
This method is a shortcut for simple cases. It accepts two generic type parametersrequest and responseso the schema can be inferred from them.
112115

113116
```fsharp
114117
let addOpenApiSimple<'Req, 'Res> = ...
115118
```
116119

120+
#### Behavior and Nuances
121+
122+
- **Request Type (`'Req`)**:
123+
- If `'Req` is `unit`, the endpoint is treated as not requiring a request body (e.g., for GET endpoints).
124+
- If `'Req` is a tuple or a primitive type (e.g., `int`, `string`), the endpoint is treated as not requiring a request body. These are typically used for path or query parameters, and the parameters are inferred from the route template.
125+
- If `'Req` is a any other complex type (e.g., record or class types), the endpoint is treated as requiring a request body. The schema is inferred from the type's fields.
126+
- **Response Type (`'Res`)**:
127+
- The response schema is always inferred from the type provided as `'Res`.
128+
- If `'Res` is `unit`, the endpoint is treated as not returning a response body.
129+
130+
**Important:**
131+
- You do not need to describe route or query parameters when using `addOpenApiSimple`; they are inferred from the route template and the handler signature.
132+
- If you want path parameters to be named, use the `routef` function with parameter labels in the route template (e.g., `routef "/users/%s:username/age/%i:age"`).
133+
- Only use record or class types for request bodies. If you use a tuple or primitive as `'Req`, it will be treated as path/query parameters, not as a body.
134+
- This behavior is designed with the idea that tuples and primitives are used for route parameters and records are used for complex request bodies.
135+
136+
**Examples:**
137+
138+
```fsharp
139+
// No request body, returns a record
140+
route "/hello" (json { Hello = "Hello from Giraffe" })
141+
|> addOpenApiSimple<unit, FsharpMessage>
142+
143+
// Path parameters only, no request body
144+
routef "/users/%s:username/age/%i:age" handler
145+
|> addOpenApiSimple<string * int, string>
146+
147+
// Request body required (record type)
148+
route "/message" handler
149+
|> addOpenApiSimple<MyMessageRecord, string>
150+
```
151+
117152
If your handler doesn't accept any input, you can pass `unit` as a request type (works for response as well).
118153

119154
### configureEndpoint

sample-project/Program.fs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
open System
1+
open System
22
open System.IO
33
open Microsoft.AspNetCore.Builder
44
open Microsoft.AspNetCore.Http
@@ -25,19 +25,32 @@ let handler1 (_: HttpFunc) (ctx: HttpContext) = ctx.WriteTextAsync "Hello World"
2525
let handler2 (firstName: string, age: int) (_: HttpFunc) (ctx: HttpContext) =
2626
$"Hello %s{firstName}, you are %i{age} years old." |> ctx.WriteTextAsync
2727

28+
let handler3 (firstName: string) (_: HttpFunc) (ctx: HttpContext) =
29+
$"Hello %s{firstName}!" |> ctx.WriteTextAsync
30+
31+
/// Redirects to the swagger interface from the root of the site.
32+
let swaggerRedirectHandler: HttpHandler = redirectTo true "swagger/index.html"
33+
2834
let endpoints = [
35+
route "/" swaggerRedirectHandler
2936
GET [
3037
route "/hello" (json { Hello = "Hello from Giraffe" })
3138
|> configureEndpoint _.WithTags("SampleApp")
3239
|> configureEndpoint _.WithSummary("Fetches a Hello from Giraffe")
3340
|> configureEndpoint _.WithDescription("Will return a Hello from Giraffe.")
3441
|> addOpenApiSimple<unit, FsharpMessage>
3542

36-
routef "/%s/%i" handler2
43+
routef "first-names/%s:firstName/ages/%i:age" handler2
3744
|> configureEndpoint _.WithTags("SampleApp")
3845
|> configureEndpoint _.WithSummary("Fetches a response from handler2")
3946
|> configureEndpoint _.WithDescription("Will return a Hello from Handler 2.")
4047
|> addOpenApiSimple<string * int, string>
48+
49+
routef "names/%s:firstName" handler3
50+
|> configureEndpoint _.WithTags("SampleApp")
51+
|> configureEndpoint _.WithSummary("Fetches a response from handler3")
52+
|> configureEndpoint _.WithDescription("Will return a Hello from Handler 3.")
53+
|> addOpenApiSimple<string, string>
4154
]
4255
POST [
4356
route "/message" (text "Message posted!")

sample-project/packages.lock.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
},
1717
"Giraffe": {
1818
"type": "Direct",
19-
"requested": "[7.0.2, )",
20-
"resolved": "7.0.2",
21-
"contentHash": "AwUqNORb9OmsqIGTAmbQtZBHoWz0yxACHA/xJqby3usUaqBUmrcz5dflVzPWUvqkulWPntwdRkQlzdt9zeEr6Q==",
19+
"requested": "[8.0.0-alpha-003, )",
20+
"resolved": "8.0.0-alpha-003",
21+
"contentHash": "q+FSYgPeq4tifAR3wHgFMDa4dCa4Xv2/XeMHQ19uXZwP8SOnkEh0GyukDumjxQLou3cD1OjF6ox498k+fOnWbg==",
2222
"dependencies": {
2323
"FSharp.Core": "6.0.0",
2424
"FSharp.SystemTextJson": "1.3.13",
@@ -106,21 +106,21 @@
106106
"giraffe.openapi": {
107107
"type": "Project",
108108
"dependencies": {
109-
"Giraffe": "[7.0.2, )",
110-
"Microsoft.AspNetCore.OpenApi": "[8.0.16, )"
109+
"Giraffe": "[8.0.0-alpha-003, )",
110+
"Microsoft.AspNetCore.OpenApi": "[8.0.17, )"
111111
}
112112
},
113113
"FSharp.Core": {
114114
"type": "CentralTransitive",
115-
"requested": "[8.0.300, )",
115+
"requested": "[8.0.403, )",
116116
"resolved": "6.0.0",
117117
"contentHash": "fbv1UwJ2LXVcFCt+GGDPu0sIYA5C6gdDvAupDj3iLQF3clRkua/6J33f+FiGQa8P1tEa+zmz3wrjoTnXZ1UiYg=="
118118
},
119119
"Microsoft.AspNetCore.OpenApi": {
120120
"type": "CentralTransitive",
121-
"requested": "[8.0.16, )",
122-
"resolved": "8.0.16",
123-
"contentHash": "jeZBYi62BKGRZXEkXAr9hj1L6u71HRKE7EPaZBouF1xmKdQIX7GO5oSRLTQLQmmST0y/aaI+Mr4OzyyRjmBFog==",
121+
"requested": "[8.0.17, )",
122+
"resolved": "8.0.17",
123+
"contentHash": "sGed2RDkJYAoi7N4gUTota56Mix/Vu6UrzCWdwqH1jZwnLnZb+eP2zdABYCaVlBEHBwzuL1zchUFtJXW4lO5LA==",
124124
"dependencies": {
125125
"Microsoft.OpenApi": "1.4.3"
126126
}

src/Giraffe.OpenApi/Routing.fs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace Giraffe.OpenApi
1+
namespace Giraffe.OpenApi
22

33
// Modified for Giraffe, from https://github.com/Lanayx/Oxpecker/blob/develop/src/Oxpecker.OpenApi/Routing.fs.
44
//
@@ -25,6 +25,7 @@
2525
// SOFTWARE.
2626

2727
open System.Reflection
28+
open FSharp.Reflection
2829

2930
[<AutoOpen>]
3031
module Routing =
@@ -84,7 +85,8 @@ module Routing =
8485
| reqType, respType when reqType = unitType && respType = unitType -> "InvokeUnit"
8586
| reqType, _ when reqType = unitType -> "InvokeUnitReq"
8687
| _, respType when respType = unitType -> "InvokeUnitResp"
87-
| _, _ -> "Invoke"
88+
| reqType, _ when FSharpType.IsTuple reqType -> "InvokeUnitReq"
89+
| _ -> "Invoke"
8890
configureEndpoint
8991
_.WithMetadata(
9092
typeof<FakeFunc<'Req, 'Res>>

src/Giraffe.OpenApi/packages.lock.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
},
1717
"Giraffe": {
1818
"type": "Direct",
19-
"requested": "[7.0.2, )",
20-
"resolved": "7.0.2",
21-
"contentHash": "AwUqNORb9OmsqIGTAmbQtZBHoWz0yxACHA/xJqby3usUaqBUmrcz5dflVzPWUvqkulWPntwdRkQlzdt9zeEr6Q==",
19+
"requested": "[8.0.0-alpha-003, )",
20+
"resolved": "8.0.0-alpha-003",
21+
"contentHash": "q+FSYgPeq4tifAR3wHgFMDa4dCa4Xv2/XeMHQ19uXZwP8SOnkEh0GyukDumjxQLou3cD1OjF6ox498k+fOnWbg==",
2222
"dependencies": {
2323
"FSharp.Core": "6.0.0",
2424
"FSharp.SystemTextJson": "1.3.13",
@@ -35,9 +35,9 @@
3535
},
3636
"Microsoft.AspNetCore.OpenApi": {
3737
"type": "Direct",
38-
"requested": "[8.0.16, )",
39-
"resolved": "8.0.16",
40-
"contentHash": "jeZBYi62BKGRZXEkXAr9hj1L6u71HRKE7EPaZBouF1xmKdQIX7GO5oSRLTQLQmmST0y/aaI+Mr4OzyyRjmBFog==",
38+
"requested": "[8.0.17, )",
39+
"resolved": "8.0.17",
40+
"contentHash": "sGed2RDkJYAoi7N4gUTota56Mix/Vu6UrzCWdwqH1jZwnLnZb+eP2zdABYCaVlBEHBwzuL1zchUFtJXW4lO5LA==",
4141
"dependencies": {
4242
"Microsoft.OpenApi": "1.4.3"
4343
}
@@ -96,7 +96,7 @@
9696
},
9797
"FSharp.Core": {
9898
"type": "CentralTransitive",
99-
"requested": "[8.0.300, )",
99+
"requested": "[8.0.403, )",
100100
"resolved": "6.0.0",
101101
"contentHash": "fbv1UwJ2LXVcFCt+GGDPu0sIYA5C6gdDvAupDj3iLQF3clRkua/6J33f+FiGQa8P1tEa+zmz3wrjoTnXZ1UiYg=="
102102
}

0 commit comments

Comments
 (0)