Fable.Remoting은 Fable 및 .NET 앱을 위한 RPC 통신 계층으로, Http 및 Json을 추상화하고 컴파일 타임에 정적으로 확인되는 순수한 상태 비저장 함수 측면에서만 클라이언트-서버 상호 작용을 생각할 수 있게 해줍니다.
이 인터페이스는 각 필드가 Async<'T>
이거나 Async<'T>
반환하는 함수인 레코드 유형입니다.
IGreetingApi = {를 입력하세요. Greeting : 문자열 -> Async<string>}
GreetingApi = { Greeting = 재미있는 이름 ->async { let Greeting = sprintf "Hello, %s" name return Greeting}}// 구현을 HTTP 서비스렛으로 노출 webApp = Remoting.createApi() |> Remoting.fromValue GreetingApi
// 서비스렛에 대한 형식화된 프록시를 가져옵니다. GreetingApi = Remoting.createApi() |> Remoting.buildProxy<IGreetingApi>// serviceasync 사용 시작 { 허락하다! 메시지 = GreetingApi.greet "세계" printfn "%s" 메시지 // Hello, World}
그게 전부입니다. HTTP도 없고 JSON도 없으며 모두 유형이 안전합니다.
SAFE-TodoList 간단한 풀스택 Todo 목록 애플리케이션(초보자)
tabula-rasa 실제 세계와 같은 블로그 플랫폼(중급)
이벤트 소싱(고급)으로 구현된 Yobo Yoga 클래스 예약 시스템
라이브러리는 Suave WebPart
, Giraffe/Saturn HttpHandler
또는 Asp.NET Core 미들웨어와 같은 기타 프레임워크 등 백엔드의 모든 곳에서 실행됩니다. 클라이언트는 Fable 또는 .NET 애플리케이션일 수 있습니다.
"Fable.Remoting은 컴파일 타임에 프런트 엔드 코드를 백엔드 코드와 동기화하고 F#만큼 사용하기 쉬운 언어로 유지해야 하는 오래된 문제를 해결합니다." - David Falkner
Fable.Remoting이 이미 설정되어 바로 사용할 수 있는 SAFE Simplified 템플릿을 사용하세요.
도서관 | 버전 |
---|---|
Fable.Remoting.MsgPack | |
Fable.Remoting.클라이언트 | |
Fable.Remoting.Json | |
Fable.Remoting.Server | |
Fable.Remoting.Suave | |
우화.원격.기린 | |
Fable.Remoting.AspNetCore | |
Fable.Remoting.DotnetClient | |
Fable.Remoting.AzureFunctions.Worker | |
Fable.Remoting.AwsLambda |
새 F# 콘솔 앱을 만듭니다.
dotnet new console -lang F#
클라이언트와 서버 간에 공유하려는 유형을 정의합니다.
// SharedTypes.fsmodule SharedTypestype Student = {Name : stringAge : int}// Server와 Clienttype 간의 공유 사양 IStudentApi = {studentByName : string -> Async<Student option>allStudents : unit -> Async<list<Student>>}
IStudentApi
유형은 매우 중요합니다. 이는 서버와 클라이언트 간의 프로토콜 사양입니다. Fable.Remoting
이러한 유형에 최종 결과에 대해 Async
반환하는 함수만 있을 것으로 예상합니다.
Async<A>A -> Async<B>A -> B -> Async<C>// 등...
나중에 클라이언트에서 이러한 파일을 참조할 수 있도록 이러한 유형을 별도의 파일에 넣어 보십시오.
그런 다음 서버에서 IStudentApi
에 대한 구현을 제공합니다.
SharedTypeslet getStudents() 열기 = async {return [{ 이름 = "마이크"; 나이 = 23; }{ 이름 = "존"; 나이 = 22; }{ 이름 = "다이애나"; 나이 = 22; }] }findStudentByName 이름 =으로 설정 비동기 {렛! 학생 = getStudents()let 학생 = List.tryFind (재미있는 학생 -> 학생.이름 = 이름) 학생반환 학생 }let StudentApi : IStudentApi = {studentByName = findStudentByName allStudents = getStudents}
이제 studentApi
구현이 완료되었으므로 이를 다양한 웹 프레임워크의 웹 서비스로 노출할 수 있습니다. 우리는 Suave로 시작합니다
Paket을 사용하여 Nuget에서 라이브러리를 설치합니다.
paket add Fable.Remoting.Suave --project /path/to/Project.fsproj
studentApi
값에서 WebPart 생성
open Suaveopen Fable.Remoting.Serveropen Fable.Remoting.Suavelet webApp : WebPart =Remoting.createApi()|> Remoting.fromValue StudentApi|> Remoting.buildWebPart// 웹 서버 시작startWebServer defaultConfig webApp
예, 그렇게 간단합니다. webApp
값을 의사 코드에서 다음과 같이 생각할 수 있습니다.
웹앱 = 시키세요 선택하다 [ POST >=> 경로 "/IStudentApi/studentByName" >=> (* 요청 본문 역직렬화(json에서) *) >=> (* 역직렬화된 입력으로 StudentApi.getStudentByName 호출 *) >=> (* 클라이언트에 직렬화된 출력을 다시 제공합니다(json으로) *) // 다른 경로 ]
Fable.Remoting.Server에서 진단 로깅을 활성화하면(권장) 라이브러리가 뒤에서 어떻게 마법을 수행하는지 확인할 수 있습니다. :)
webApp =Remoting.createApi()|> Remoting.fromValue StudentApi|> Remoting.withDiagnosticsLogger(printfn "%s")|> Remoting.buildWebPart
paket을 사용하여 Nuget에서 패키지 설치
paket add Fable.Remoting.AspNetCore --project /path/to/Project.fsproj
이제 원격 핸들러를 AspNetCore 미들웨어로 구성할 수 있습니다.
let webApp =Remoting.createApi()|> Remoting.fromValue StudentApiletconfigureApp (app : IApplicationBuilder) =// ASP.NET Core 파이프라인에 Remoting 처리기 추가app.UseRemoting webApp[<EntryPoint>]let main _ =WebHostBuilder().UseKestrel ().Configure(Action<IApplicationBuilder>configureApp).Build().Run()0
Suave 부분을 따라 라이브러리 설치까지 진행할 수 있습니다.
paket add Fable.Remoting.Giraffe --project /path/to/Project.fsproj
이제 WebPart 대신 Fable.Remoting.Giraffe
네임스페이스를 열면 값 server
에서 HttpHandler를 얻을 수 있습니다.
open Giraffeopen Fable.Remoting.Serveropen Fable.Remoting.Giraffelet webApp : HttpHandler =Remoting.createApi()|> Remoting.fromValue StudentApi|> Remoting.buildHttpHandlerletconfigureApp (app : IApplicationBuilder) =// ASP.NET Core 파이프라인 앱에 Giraffe 추가 .UseGiraffe webApplet configureServices (services : IServiceCollection) =// 기린 추가 dependencyservices.AddGiraffe() |> 무시[<EntryPoint>]let main _ =WebHostBuilder().UseKestrel().Configure(Action<IApplicationBuilder>configureApp).ConfigureServices(configureServices).Build().Run()0
Giraffe 라이브러리에서 생성된 동일한 webApp
사용할 수 있습니다.
open Saturnopen Fable.Remoting.Serveropen Fable.Remoting.Giraffelet webApp : HttpHandler =Remoting.createApi()|> Remoting.fromValue StudentApi|> Remoting.buildHttpHandlerlet app = application {url "http://127.0.0.1:8083/"use_router webApp}앱 실행
사용자 지정 HttpTrigger를 서버리스 원격 서버로 사용하여 격리 모드에서 Azure Functions를 사용하려면 다음을 설치하면 됩니다.
dotnet add package Fable.Remoting.AzureFunctions.Worker
또는 패킷을 사용하여
paket add Fable.Remoting.AzureFunctions.Worker --project /path/to/Project.fsproj
Azure Functions는 HttpHandler에 대해 아무것도 모르기 때문에 기본 제공 HttpRequestData
및 HttpResponseData
개체를 사용해야 합니다. 다행히 Remoting.buildRequestHandler
및 HttpResponseData.fromRequestHandler
함수를 사용하여 문제를 해결할 수 있습니다.
open Fable.Remoting.Serveropen Fable.Remoting.AzureFunctions.Workeropen Microsoft.Azure.Functions.Workeropen Microsoft.Azure.Functions.Worker.Httpopen Microsoft.Extensions.Loggingtype Functions(log:ILogger<함수>) =[<Function("Index ")>]멤버 _.인덱스 ([<HttpTrigger(AuthorizationLevel.Anonymous, Route = "{*any}")>] req: HttpRequestData, ctx: FunctionContext) =Remoting.createApi()|> Remoting.withRouteBuilder FunctionsRouteBuilder.apiPrefix|> Remoting.fromValue myImplementation|> Remoting.buildRequestHandler|> HttpResponseData.fromRequestHandler 요청
물론 함수 앱당 하나의 구현을 갖는 것은 이상적이지 않으므로 HttpResponseData.fromRequestHandlers
도움이 됩니다.
type Functions(log:ILogger<Functions>) =[<Function("Index")>]member _.Index ([<HttpTrigger(AuthorizationLevel.Anonymous, Route = "{*any}")>] req: HttpRequestData, ctx : FunctionContext) =let handlerOne =Remoting.createApi()|> Remoting.withRouteBuilder FunctionsRouteBuilder.apiPrefix|> Remoting.fromValue myImplementationOne|> Remoting.buildRequestHandler let handlerTwo =Remoting.createApi()|> Remoting.withRouteBuilder FunctionsRouteBuilder.apiPrefix|> Remoting.fromValue myImplementationTwo|> Remoting.buildRequestHandler [ handlerOne; handlerTwo ] |> HttpResponseData.fromRequestHandlers 요청
Paket을 사용하여 nuget에서 Fable.Remoting.Client
설치합니다.
paket add Fable.Remoting.Client --project /path/to/Project.fsproj
클라이언트 프로젝트에 대한 공유 유형 참조
<Compile Include="path/to/SharedTypes.fs" />
라이브러리 사용 시작:
Fable.Remoting.Clientopen SharedTypes// StudentApi : IStudentApilet StudentApi =Remoting.createApi()|> Remoting.buildProxy<IStudentApi>async { // 학생 : 학생[] 허락하다! 학생 = StudentApi.allStudents() for 학생 in 학생 do// 학생 : Studentprintfn "학생 %s은(는) %d세입니다." Student.Name Student.Age}|> Async.StartImmediate
마지막으로 webpack-dev-server
사용하는 경우 구성을 다음과 같이 변경해야 합니다.
개발자서버: { contentBase: 해결('./public'), 포트: 8080}
이것에:
개발자서버: { contentBase: 해결('./public'), 포트: 8080, Proxy: {'/*': { // webpack-dev-server에게 클라이언트의 모든 요청을 서버 대상으로 다시 라우팅하도록 지시: "http://localhost:5000",// 백엔드 서버가 포트에서 호스팅된다고 가정 개발 중 5000.changeOrigin: true}}
그게 다야!
콘솔, 데스크톱, 모바일 애플리케이션 등 Fable이 아닌 프로젝트에서도 클라이언트 기능을 사용할 수 있습니다.
Paket을 사용하여 nuget에서 Fable.Remoting.DotnetClient
설치합니다.
paket add Fable.Remoting.DotnetClient --project /path/to/Project.fsproj
클라이언트 프로젝트에서 공유 유형을 참조하세요.
<Compile Include="path/to/SharedTypes.fs" />
라이브러리 사용 시작:
open Fable.Remoting.DotnetClientopen SharedTypes// StudentApi : IStudentApilet StudentApi = Remoting.createApi "http://localhost:8085" |> Remoting.buildProxy<IStudentApi>async { // 학생 : 학생[] 허락하다! 학생 = StudentApi.allStudents() for 학생 in 학생 do// 학생 : Studentprintfn "학생 %s은(는) %d세입니다." Student.Name Student.Age}|> Async.StartImmediate
여기서 Fable 클라이언트와 달리 dotnet 클라이언트는 백엔드와 별도로 배포되므로 백엔드의 기본 URL을 제공해야 합니다.
IStudentApi
에 다른 레코드 필드 함수 추가
해당 기능을 구현하세요.
서버 및 클라이언트 다시 시작
완료! 이제 클라이언트에서도 해당 기능을 사용할 수 있습니다.
이 라이브러리가 구현되는 방법에 관심이 있다면 다음 문서를 참조하세요.(약간 구식이지만 메커니즘에 대한 개요를 제공합니다.) F#을 사용한 정적으로 형식화된 클라이언트-서버 통신: 개념 증명