F# Giraffe/Saturn - Как BindModelAsync с типами параметров

Я пытаюсь создать простой WebAPI с Saturn и хочу представить входные данные как все необязательные типы, так как есть вероятность, что потребитель API не вводит правильные данные. Я хочу подтвердить ввод пользователя с помощьюValidate метод, который выглядит как UnvalidatedUserInput -> Result<ValidUserInput, ValidationError list>.

Похоже, я должен использовать ctx.BindModelAsync<UnvalidatedUserInput >() для десериализации тела запроса, но он не десериализуется в UnvalidatedUserInput тип из-за optionс. Я получаю следующую ошибку:

Исключение типа "Newtonsoft.Json.JsonSerializationException" произошло в System.Private.CoreLib.dll, но не было обработано в пользовательском коде: "Неожиданное свойство" solarSystemId "обнаружено при чтении объединения. Путь 'solarSystemId', строка 3, позиция 20.'

Итак, я попытался удалить options из типов, но теперь BindModelAsync устанавливает недостающие параметры как null и я не могу использовать isNullна нем, потому что это не допускающий значение NULL тип в F#. Как я могу обойти это и безопасно проверить ввод пользователя?

Я читал, что, возможно, мне следует использовать Json -модуль https://github.com/microsoft/fsharplu/, но я не вижу примеров того, как это сделать. Я также видел, что, возможно, в.NET 5.0 будет поддержка десериализации для различаемых объединений, но что я могу сделать до этого?

Вот мой HttpHandler:

    let asteroidCreatedEventHandler : HttpHandler =
      fun (next : HttpFunc) (ctx : HttpContext) ->
        task {
                let! rawEvent = ctx.BindModelAsync<UnverifiedAsteroidCreatedEvent>()
                let validationResult = Validation.validateAsteroidCreatedEvent rawEvent

                match validationResult with
                | Ok verifiedEvent ->
                    AddMinableToSolarSystem verifiedEvent |> ignore
                    ctx.SetStatusCode 204
                    return! Successful.NO_CONTENT next ctx
                | Error err ->
                    ctx.SetStatusCode 400
                    return! RequestErrors.BAD_REQUEST err next ctx
            }

И мой роутер:

let appRouter = router {
    post "/asteroid-created" Asteroids.Controller.asteroidCreatedEventHandler
    forward "" browserRouter
}

Определения типов:

type Coordinates = 
  {
    X: int
    Y: int
  }
  override this.ToString() =
    sprintf "(%i, %i)" this.X this.Y

type UnverifiedAsteroidCreatedEvent =
    { Id: System.Guid option
      SolarSystemId: System.Guid option
      Coordinates: Coordinates option }

PS любые другие очевидные ошибки или запахи кода, которые вы можете почерпнуть из этих фрагментов, пожалуйста, дайте мне несколько советов!

0 ответов

Другие вопросы по тегам