HttpHandler for easily working with query string parameters within Giraffe apps.
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.github
.paket
.vscode
sample
src/Giraffe.QueryReader
tests/Giraffe.QueryReader.Tests
tools
.editorconfig
.gitignore
.travis.yml
Giraffe.QueryReader.sln
LICENSE.md
README.md
RELEASE_NOTES.md
appveyor.yml
build.cmd
build.fsx
build.sh
paket.dependencies
paket.lock

README.md

Giraffe.QueryReader Build Status Nuget

HttpHandler for better working with query string paramters within Giraffe applications. Easily extract values from query string in a type-safe manner without defining intermediate types for model binding. The library can parse primitive values and can handle their optional counter parts.

Install

# using nuget client
dotnet add package Giraffe.QueryReader
# using Paket
.paket/paket.exe add Giraffe.QueryReader --project path/to/Your.fsproj

The library code is actually only a single-file: QueryReader.fs so you can add it manually to your project and modify however you want.

Usage

Namespace Giraffe.QueryReader is opened in all examples below

Query.read is the only function is this library, it is overloaded so takes a number of strings as the first parameters being the names of the parameters in the query string (for now up to 6 parameters. Need more? PRs are welcome) and the last parameter is a function that transforms the parsed query string parameter into another HttpHandler

Basis use case: reading required parameter as string

GET 
  >=> route "/sayHello"
  >=> Query.read("to", sprintf "Hello %s" >> text)

Notice that because we used %s the type of the parameter was inferred to be string. This implies that to is a required query string parameter and if omitted, a bad request (400) response is returned to the client, i.e.

curl /sayHello?to=John 
OK (200) "Hello John"

curl /sayHello 
Bad Request (400) '{ "message": "Required query string parameter to was not found" }'

Optional query string parameters

GET 
  >=> route "/greet"
  >=> Query.read("name", 
        function 
        | Some name -> text (sprintf "Hello %s" name)
        | None -> text "Hello World")

Since the input type now has been inferred to be Option<string> the query string parameter can be omitted:

curl /greet?name=John
OK (200) "Hello John"

curl /greet
OK (200) "Hello World"

Use multiple query string parameters

GET 
  >=> route "/data"
  >=> Query.read("fromDate", "toDate", "format", 
        fun fromDate toDate format -> 
            let data = sprintf "Data from %s to %s as %s" fromDate toDate format
            text data)

Notice here we are not reading the values as DateTime but using string instead. This library doesn't try to do everything and for parsing complex structures like DateTime or similar, just read as string and parse/validate yourself.

Use optional boolean flags

Mix and match different parameters of different types

GET 
  >=> route "/ablums"
  >=> Query.read("search", "includeArtist", 
        fun search includeArtist -> 
            match includeArtist with
            | Some true -> text (sprintf "Search '%s' and include artist" search)
            | Some false -> text (sprintf "Search '%s' and do not include artist" search)
            | None -> text (sprintf "Just searching '%s', includeArtist omitted")
        )           

Here we are using multiple query string parameters: search and includeArtist where the latter is an optional boolean flag (implied by the Option<bool> type):

# implicit includeArtist=true because flag is present 
curl /albums?search=Metallica&includeArtist
OK (200) "Search 'Metallica' and include artist"

# explicit boolean value
curl /albums?search=Metallica&includeArtist=true
OK (200) "Search 'Metallica' and include artist"

curl /albums?search=Metallica&includeArtist=false
OK (200) "Search 'Metallica' and do not include artist"

curl /albums?search=Metallica
OK (200) "Just searching 'Metallica', includeArtist omitted"

Parsing integers and floating numbers

GET 
  >=> route "/int-sum"
  >=> Query.read("x", "y", 
        fun x y -> 
            let sum = x + y
            let result = sprintf "x + y = %d" sum
            text result)

Here the parameters are inferred to be of type int because of using + and %d.

curl /int-sum?x=10&y=5 
OK (200) "x + y = 15"

if you want to use float then just give a hint at the compiler:

GET 
  >=> route "/number-sum"
  >=> Query.read("x", "y", 
        fun (x:float) y -> 
            let sum = x + y
            let result = sprintf "x + y = %.1f" sum
            text result)

then use

curl /number-sum?x=1.5&y=2.5
OK (200) "x + y = 4.0"

Notice here that numbers are parsed with an CultureInfo.InvariantCulture format provider. If you want to use a different format provider, then read the query string parameter as string then parse yourself.

Supported types

  • string
  • int
  • Int64
  • bool
  • float
  • Guid
  • Option<string>
  • Option<int>
  • Option<Int64>
  • Option<bool>
  • Option<float>
  • Option<Guid>

Using optional types implies that the query string parameter can be omitted, in which case, None will be passed to the function.

Builds

Build History

Building

Make sure the following requirements are installed in your system:

> build.cmd // on windows
$ ./build.sh  // on unix

Watch Tests

The WatchTests target will use dotnet-watch to watch for changes in your lib or tests and re-run your tests on all TargetFrameworks

./build.sh WatchTests