如何在 F# Saturn Framework 中获取查询参数?

How to get a query parameter in F# Saturn Framework?

假设我们有这个网络服务器来处理请求:

let webApp = scope {
    get  "/api/zoo/animals/"    (getAllAnimals())
    getf "/api/zoo/animals/%s"  getAnimalInfo
}

此语法在 docs and demoed in the example 中有描述。

现在,如果我想在 url 查询中包含一个参数,例如过滤结果?

http://localhost:8080/api/zoo/animals?type=mammals

这没有做任何事情:

getf "/api/zoo/animals?type=%s" getAnimalsByType

一种方法是使用上下文的函数 GetQueryStringValue。它returnsResult,一个结构体DU.

因此您保留初始签名(只需删除结尾的斜杠):

get "/api/zoo/animals" (getAnimals())

你有

let getAnimals() : HttpHandler =
    fun _ ctx -> task { 
        let animalTypeFromQuery = ctx.GetQueryStringValue "type"
        let animalType =
            match animalTypeFromQuery with
            | Ok t    -> Some t
            | Error _ -> None
        ...
    }

我不知道这是否是官方的做法,我在一些 F# github repos 中找到了这种做法。

查看示例:

https://github.com/giraffe-fsharp/Giraffe/blob/master/DOCUMENTATION.md#query-strings

它展示了如何绑定查询字符串中的数据,这样您就不必使用 GetQueryStringValue

在你的情况下,我认为这样的事情可能会奏效。

[<CLIMutable>]
type AnimalType =
    { type : string }

let animal (next : HttpFunc) (ctx : HttpContext) =
    // Binds the query string to a Car object
    let animal = ctx.BindQueryString<AnimalType>()

    // Sends the object back to the client
    Successful.OK animal next ctx

let web_app  =

    router {    
        pipe_through (pipeline { set_header "x-pipeline-type" "Api" })
        post "/api/animal" animal
    }

在 Gigraff 中与 POST 参数作斗争 POST

#light "off"
open System.Text.RegularExpressions
open System.IO
open System.Text
open Microsoft.AspNetCore.Http
open Giraffe
open FSharp.Data.Sql
open Giraffe.ViewEngine

let indexView = createPage ("test post") [
...
   let row i d = tr [] [
        td [] [ str (string(i)) ];
        td [] [ str d ]] in
   let db_ctx = mssql.GetDataContext() in
   let rows = [ for r in db_ctx.Dbo.Data do 
           (row r.Id r.Data) done ] in
...  
   form [_method "POST"; _action "/"; _enctype "multipart/form-data"] [
       button [] [str "Add row!" ]  
       input [ _type "text"; _name "Id"]  
       input [ _type "text"; _name "Data"]
   ...
       div[] rows

]

  let chk s = not (String.IsNullOrEmpty s)
  let indexHandler : HttpHandler =
    fun (next : HttpFunc) (ctx : HttpContext) -> task { return! (
         if ctx.Request.ContentType.StartsWith( "multipart/form-data") then begin 
           let id = (ctx.Request.Form.Item("Id").ToString()) in
           let data = (ctx.Request.Form.Item("Data").ToString()) in
           if chk id && chk data 
              && not (Regex.IsMatch( id,"[^\d]"))  then begin
              let db_ctx = mssql.GetDataContext() in
              db_ctx.Dbo.Data.Create( int(id),data) |> ignore;
              db_ctx.SubmitUpdates();
           end;
         end;
         htmlView indexView
      ) next ctx
   }

GET >=> route "/" >=> indexHandler;
POST >=> route "/" >=> indexHandler;