在管理错误的同时在管道中链接REST调用 [英] Chaining REST calls in a pipeline while managing errors

查看:90
本文介绍了在管理错误的同时在管道中链接REST调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

来自nodejs,在这里我可以使用 Promises链接异步事件然后是运算符。我试图探索在惯用的F#中是如何完成的。

Coming from nodejs where I could chain asynchronous events using Promises and then operator I'm trying to explore how things are done in idiomatic F#.

我要链接的调用是对某些对象的HTTP剩余调用实体,从创建到更新,再到上传图片再发布。

The calls I'm trying to chain are HTTP rest calls on some entity from creation to update to uploading images to publishing.

函数组成表明,一个函数的输出应与要组成的第二个函数的输入匹配,在我的情况下,常见的输入和输出为 string ,即JSON序列化的字符串作为所有这些函数的输入和输出。

Function composition says the output of one function should match the input of the second one to be composed and that common input and output in my case will be string, i.e. JSON serialized string as input and output of all of these functions.

我了解到可以使用>> 运算符。理想情况下,函数不应引发错误,但事情会随IO发生,例如,在这种情况下,如果我要创建的实体的ID存在等等该怎么办。

I've learned that you can compose functions using >> operator. Ideally functions should not throw errors but things happen with IO, for instance in this case what if the id of the entity I'm trying to create exists etc.

未知问题是,如果在链接序列中发生错误,将发生什么情况,调用者将如何知道错误以及描述消息?该操作可能会在链序列的中间,结尾处或右边失败。

The unknown and the question is what happens if an error occurs during the chained sequence, how the caller will know what went wrong along with description message? The operation could fail in the middle or towards the end or right in the beginning of the chain sequence.

我期望这些函数在出错时会停止执行链接并将错误消息返回给调用方。错误消息也是JSON string ,因此函数的输入和输出之间没有不兼容,所以您知道。

What I'm expecting from these functions upon error to stop executing the chain and return the error message to the caller. Error message is also a JSON string so there's no incompatibility between inputs and outputs of a function so you know.

我看着也可以选择,但不确定是否这是我应该去的方向。

I looked at Choice too but not sure if that's the direction I should be going for.

代码不一定完整,我正在寻找因为这是进一步研究以获得答案并可能改善此问题的方向。

The code is not necessarily complete and all I'm looking for a is a direction to research further to get answers and possibly improve this question. Here's some code to start with.

let create schema =
    // POST request
    """{"id": 1, "title": "title 1"}""" // result output

let update schema =
    // PUT request, update title
    """{"id": 1, "title": "title 2"}""" // output

let upload schema = 
    // PUT request, upload image and add thumbnail to json
    """{"id": 1, "title": "title 2", "thumbnail": "image.jpg"}""" 

let publish schema =
    // PUT request, publish the entity, add url for the entity
    if response.StatusCode <> HttpStatusCode.OK then
        """{"code": "100", "message": "file size above limit"}"""
    else
        """{"id": 1, "title": "title 2", "thumbnail": "image.jpg", "url": "http://example.com/1"}"""

let chain = create >> update >> upload >> publish






编辑-尝试

尝试参数化上传部分中的图像缩略图

Trying to parameterize the image thumbnail in the upload part

let create (schema: string) : Result<string,string> =
    Ok """{"id": 1, "title": "title 1"}""" // result output

let update (schema: string) : Result<string,string>  =
    Ok """{"id": 1, "title": "title 2"}""" // output

let upload2 (img: string) (schema: string) : Result<string,string> =
    printf "upload image %s\n" img
    let statusCode = HttpStatusCode.OK
    match statusCode with
    | HttpStatusCode.OK -> Ok """{"id": 1, "title": "title 2", "thumbnail": "image.jpg"}"""
    | x -> Error (sprintf "%A happened" x)

let publish (schema: string) =
    let statusCode = HttpStatusCode.InternalServerError
    match statusCode with
    | HttpStatusCode.OK -> Ok """{"id": 1, "title": "title 2", "thumbnail": "image.jpg", "url": "http://example.com/1"}"""
    | _ -> Error """{"code": "100", "message": "couldn't publish, file size above limit"}"""

let chain = create >> Result.bind update >> Result.bind (upload2 "image.jpg") >> Result.bind publish


推荐答案

解决此问题的通用方法将函数的返回值包装为Choice / Either类型,并使用高阶函数将它们绑定在一起,从而使 failure 传播/短路一些有意义的数据。 F#的 Result 类型带有 bind 函数,可以这样使用:

A good general approach to this problem is wrapping your functions' return values in a Choice/Either-like type and using a higher-order function to bind them together such that a failure propagates/short-circuits with some meaningful data. F# has a Result type with a bind function that can be used like this:

type MyResult = Result<string,string>
let f1 x : MyResult = printfn "%s" x; Ok "yep"
let f2 x : MyResult = printfn "%s" x; Ok "yep!"
let f3 x : MyResult = printfn "%s" x; Error "nope :("
let fAll = f1 >> Result.bind f2 >> Result.bind f3

> fAll "howdy";;
howdy
yep
yep!
[<Struct>]
val it : Result<string,string> = Error "nope :("

前两个函数成功,但是第三个函数失败,因此您会收到 Error

The first two functions succeed, but the third fails and so you get an Error value back.

也可以在面向铁路的编程

更新,使其更适合您的示例:

Update to be more specific to your example:

let create (schema: string) : Result<string,string> =
    Ok """{"id": 1, "title": "title 1"}""" // result output
let update (schema: string) : Result<string,string>  =
    Ok """{"id": 1, "title": "title 2"}""" // output
let upload (schema: string) = 
    let statusCode = HttpStatusCode.OK
    match statusCode with
    | HttpStatusCode.OK -> Ok """{"id": 1, "title": "title 2", "thumbnail": "image.jpg"}"""
    | x -> Error (sprintf "%A happened" x)
let publish (schema: string) =
    let statusCode = HttpStatusCode.InternalServerError
    match statusCode with
    | HttpStatusCode.OK -> Ok """{"id": 1, "title": "title 2", "thumbnail": "image.jpg", "url": "http://example.com/1"}"""
    | _ -> Error """{"code": "100", "message": "file size above limit"}"""
let chain =
  create >> Result.bind update >> Result.bind upload >> Result.bind publish

这篇关于在管理错误的同时在管道中链接REST调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆