gpt4 book ai didi

f# - F# 中 API 包装器的功能建模

转载 作者:行者123 更新时间:2023-12-02 01:30:26 24 4
gpt4 key购买 nike

我正在尝试学习 F# 和函数式编程,但不确定如何对以下场景进行建模。

我正在尝试用 F# 围绕 XML API 编写一个简单的包装器。此 API 要求我首先使用用户名和密码进行“登录”API 调用。然后,API 返回一个 session token ,用于验证后续调用。在某些时候, session 将过期,我将需要再次“登录”。

在面向对象的项目中,我将创建一个 ApiClient 类。它将把用户名和密码作为构造函数参数,为每个 API 调用公开一个公共(public)方法,并在内部处理登录过程。 session token 和状态可以对消费应用程序完全隐藏,并且只要 ApiClient 实例存在,就会维护 session token 。

我不确定如何以功能方式组织我的代码以实现类似的结果。如果我不创建 ApiClient 类,则在哪里存储内部 session token 数据?显然,我可以在 F# 中创建一个 ApiClient 类,但我正在寻找如何更有效地执行此操作的见解。

感谢您的见解。

最佳答案

我对我的答案进行了大幅修改,试图将这个过程压缩为最基本的要素,以帮助您入门。

要做的第一件事是设计一个系统来处理 session 状态。最简单的事情是创建一个类型来包含只能在库内创建的 session 数据,并创建第二种类型(这是一个可区分的联合)来处理该数据的验证。

type SessionData internal (id : System.Guid, creationTime : System.DateTime) = 
member this.UniqueID = id
member this.CreationTime = creationTime

type SessionState<'a> =
|Valid of 'a * SessionData
|Invalid

您的登录函数需要用户名和密码并返回有效或无效的 session 状态。

let login username password =
match isUsernameAndPasswordCorrect with
|true -> Valid ((), SessionData(System.Guid.NewGuid(), System.DateTime.UtcNow))
|false -> Invalid

当我们调用 API 时,我们将把 session 状态映射从旧 session 状态更新到新 session 状态,并在此过程中检查有效性。

let private updateSession result (sessionState : SessionData) =
let loginTimeSpan = sessionState.CreationTime - System.DateTime.UtcNow
match loginTimeSpan < maxLoginSpan with
|true -> Valid <| (result, SessionData(System.Guid.NewGuid(), System.DateTime.UtcNow))
|false -> Invalid

显然,如果我们愿意,我们可以使验证和更新过程更加严格。

这里我们包含在 session 状态中调用 API 的结果。每个 API 调用都有:

let apiCall args sessionState =
updateSession (internalFunction args) sessionState

如果调用成功,我们会得到一个新的有效状态,其中包含新 session 和结果。

<小时/>

如果您想完全隐藏交换 session 状态信息的过程,您可以创建一个计算表达式来处理它。一个非常简单的例子可能是:

 type XMLAPIBuilder() =
member this.Bind (x, f) =
fun sessionState ->
match x sessionState with
|Valid (call, newSessionState) -> f call newSessionState
|Invalid -> Invalid

member this.Return(x) =
fun sessionState -> Valid (x, sessionState)

您可以使用计算表达式语法来使用它:

let xmlapi = XMLAPIBuilder()
let apiCalls =
xmlapi {
let! a = apiCall1 args1
let! b = apiCall2 args2
let! c = apiCall3 args3
return (a, b, c) // result of several api calls
}
let result = apiCalls session // pass in session data once to retrieve results

要完全删除 session 数据,我们可以创建一个不包含 session 状态和 run 函数的新类型:

type APICallState<'a> =
|CallSuccess of 'a
|CallFailed

let run username password apiExpression =
match testmagic.login "" "" with
|Valid (_, state) ->
match apiExpression state with
|Valid (result, _) -> CallSuccess result
|Invalid -> CallFailed
|Invalid -> CallFailed

这使我们能够设计一个复杂的表达式,对您的 API 进行一系列相关的调用。我们提供一次用户名和密码,然后进行所有调用。

对于新手来说,计算表达式绝对是该语言中较难理解的部分之一,因此我建议查看一些教程,例如:http://fsharpforfunandprofit.com/series/computation-expressions.html

关于f# - F# 中 API 包装器的功能建模,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33715717/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com