diff --git a/src/Builder.fs b/src/Builder.fs index d368bcf..38e9374 100644 --- a/src/Builder.fs +++ b/src/Builder.fs @@ -31,29 +31,20 @@ type RequestBuilder () = /// Binds value of 'TValue for let! All handlers runs in same context within the builder. member _.Bind ( - source: HttpHandler<'TSource, 'TNext>, - fn: 'TNext -> HttpHandler<'TNext, 'TResult> + source: HttpHandler<'TSource, 'TValue>, + fn: 'TValue -> HttpHandler<'TSource, 'TResult> ): HttpHandler<'TSource, 'TResult> = let subscribe (next: IHttpNext<'TResult>) = - let (next: IHttpNext<'TNext>) = - { new IHttpNext<'TNext> with + let next = + { new IHttpNext<'TValue> with member _.NextAsync(ctx, ?content) = task { - let obv = - { new IHttpNext<'TResult> with - member _.NextAsync(ctx', content) = next.NextAsync(ctx, ?content = content) - member _.ErrorAsync(ctx, exn) = next.ErrorAsync(ctx, exn) - } - match content with | Some content -> - let res = fn content - - return! - res.Subscribe(obv) - |> (fun obv -> obv.NextAsync(ctx, content = content)) - | None -> return! obv.NextAsync(ctx) + let bound: HttpHandler<'TSource, 'TResult> = fn content + return! bound.Subscribe(next).NextAsync(ctx) + | None -> return! next.NextAsync(ctx) } member _.ErrorAsync(ctx, exn) = next.ErrorAsync(ctx, exn) diff --git a/src/Context.fs b/src/Context.fs index 1c38295..57f38a4 100644 --- a/src/Context.fs +++ b/src/Context.fs @@ -267,21 +267,21 @@ module Context = } /// Merge the list of context objects. Used by the sequential and concurrent HTTP handlers. - let merge (context: List): Context = + let merge (ctxs: List): Context = + let ctxs = + match ctxs with + | [] -> [ defaultContext ] + | _ -> ctxs + // Use the max status code. let statusCode = - let codes = - context - |> List.map (fun ctx -> ctx.Response.StatusCode) - - if codes.IsEmpty then - HttpStatusCode.NotFound - else - List.max codes + ctxs + |> List.map (fun ctx -> ctx.Response.StatusCode) + |> List.max // Concat the reason phrases (if they are different) let reasonPhrase = - context + ctxs |> List.map (fun ctx -> ctx.Response.ReasonPhrase) |> List.distinct |> String.concat ", " @@ -297,7 +297,7 @@ module Context = // Merge headers let headers = - context + ctxs |> List.map (fun ctx -> ctx.Response.Headers) |> List.fold (fun state hdr -> merge state hdr (fun k (a, b) -> if a = b then a else Seq.append a b)) @@ -305,10 +305,9 @@ module Context = { Request = - context - |> List.tryHead - |> Option.map (fun ctx -> ctx.Request) - |> Option.defaultValue defaultRequest + ctxs + |> Seq.map (fun ctx -> ctx.Request) + |> Seq.head Response = { Headers = headers diff --git a/test/Builder.fs b/test/Builder.fs index 2502013..16110b5 100644 --- a/test/Builder.fs +++ b/test/Builder.fs @@ -31,7 +31,7 @@ let ``Simple unit handler in builder is Ok`` () = let! result = let a = req { - let! value = unit 42 + let! value = singleton 42 return value } @@ -47,10 +47,10 @@ let ``Simple return from unit handler in builder is Ok`` () = // Arrange let ctx = Context.defaultContext - let a = unit 42 |> runAsync ctx + let a = singleton 42 |> runAsync ctx // Act - let! result = req { return! unit 42 } |> runUnsafeAsync ctx + let! result = req { return! singleton 42 } |> runUnsafeAsync ctx // Assert test <@ result = 42 @> @@ -65,8 +65,8 @@ let ``Multiple handlers in builder is Ok`` () = // Act let request = req { - let! a = unit 10 - let! b = unit 20 + let! a = singleton 10 + let! b = singleton 20 return! add a b } diff --git a/test/Common.fs b/test/Common.fs index 460edb9..8ba5ab2 100644 --- a/test/Common.fs +++ b/test/Common.fs @@ -60,16 +60,16 @@ type HttpMessageHandlerStub (NextAsync: Func = task { return! NextAsync.Invoke(request, cancellationToken) } -let unit<'TSource, 'TResult> (value: 'TResult): HttpHandler<'TSource, 'TResult> = +let singleton<'TSource, 'TResult> (value: 'TResult): HttpHandler<'TSource, 'TResult> = HttpHandler <| fun next -> { new IHttpNext<'TSource> with - member _.NextAsync(ctx, ?content) = next.NextAsync(ctx, value) + member _.NextAsync(ctx, _) = next.NextAsync(ctx, value) member _.ErrorAsync(ctx, exn) = next.ErrorAsync(ctx, exn) } -let add (a: int) (b: int) = unit (a + b) +let add (a: int) (b: int) = singleton (a + b) exception TestException of code: int * message: string with diff --git a/test/Handler.fs b/test/Handler.fs index b3fcf90..2016799 100644 --- a/test/Handler.fs +++ b/test/Handler.fs @@ -22,7 +22,7 @@ let ``Simple unit handler is Ok`` () = let ctx = Context.defaultContext // Act - let! content = unit 42 >=> unit 43 |> runUnsafeAsync ctx + let! content = singleton 42 >=> singleton 43 |> runUnsafeAsync ctx // Assert test <@ content = 43 @> @@ -50,7 +50,7 @@ let ``Simple error then ok is Error`` () = task { // Arrange let ctx = Context.defaultContext - let req = error "failed" >=> unit 42 + let req = error "failed" >=> singleton 42 // Act let! result = req |> runAsync ctx @@ -68,7 +68,7 @@ let ``Simple ok then error is Error`` () = task { // Arrange let ctx = Context.defaultContext - let req = unit 42 >=> error "failed" + let req = singleton 42 >=> error "failed" // Act let! result = req |> runAsync ctx @@ -87,7 +87,7 @@ let ``Catching ok is Ok`` () = let errorHandler = badRequestHandler 420 let req = - unit 42 + singleton 42 >=> map (fun a -> a * 10) >=> catch errorHandler @@ -105,7 +105,7 @@ let ``Catching errors is Ok`` () = let ctx = Context.defaultContext let errorHandler = badRequestHandler 420 - let req = unit 42 >=> error "failed" >=> catch errorHandler + let req = singleton 42 >=> error "failed" >=> catch errorHandler // Act let! content = req |> runUnsafeAsync ctx @@ -121,7 +121,7 @@ let ``Not catching errors is Error`` () = let ctx = Context.defaultContext let errorHandler = badRequestHandler 420 - let req = unit 42 >=> catch errorHandler >=> error "failed" + let req = singleton 42 >=> catch errorHandler >=> error "failed" // Act let! result = req |> runAsync ctx @@ -137,7 +137,7 @@ let ``Sequential handlers is Ok`` () = task { // Arrange let ctx = Context.defaultContext - let req = sequential [ unit 1; unit 2; unit 3; unit 4; unit 5 ] + let req = sequential [ singleton 1; singleton 2; singleton 3; singleton 4; singleton 5 ] // Act let! content = req |> runUnsafeAsync ctx @@ -151,7 +151,7 @@ let ``Sequential handlers with an Error is Error`` () = task { // Arrange let ctx = Context.defaultContext - let req = sequential [ unit 1; unit 2; error "fail"; unit 4; unit 5 ] + let req = sequential [ singleton 1; singleton 2; error "fail"; singleton 4; singleton 5 ] // Act let! result = req |> runAsync ctx @@ -169,7 +169,7 @@ let ``Concurrent handlers is Ok`` () = task { // Arrange let ctx = Context.defaultContext - let req = concurrent [ unit 1; unit 2; unit 3; unit 4; unit 5 ] + let req = concurrent [ singleton 1; singleton 2; singleton 3; singleton 4; singleton 5 ] // Act let! result = req |> runAsync ctx @@ -187,7 +187,7 @@ let ``Concurrent handlers with an Error is Error`` () = task { // Arrange let ctx = Context.defaultContext - let req = concurrent [ unit 1; unit 2; error "fail"; unit 4; unit 5 ] + let req = concurrent [ singleton 1; singleton 2; error "fail"; singleton 4; singleton 5 ] // Act let! result = req |> runAsync ctx @@ -207,7 +207,7 @@ let ``Chunked handlers is Ok`` (PositiveInt chunkSize) (PositiveInt maxConcurren let ctx = Context.defaultContext let req = - chunk chunkSize maxConcurrency unit [ 1; 2; 3; 4; 5 ] + chunk chunkSize maxConcurrency singleton [ 1; 2; 3; 4; 5 ] // Act let! result = req |> runUnsafeAsync ctx @@ -220,7 +220,7 @@ let ``Choose handlers is Ok`` = // Arrange let ctx = Context.defaultContext - let req = choose [ error "1"; unit 2; error "3"; unit 4 ] + let req = choose [ error "1"; singleton 2; error "3"; singleton 4 ] // Act let! result = req |> runUnsafeAsync ctx @@ -258,7 +258,7 @@ let ``Request with token renewer without token gives error`` () = let renewer _ = err |> Error |> Task.FromResult let ctx = Context.defaultContext - let req = withTokenRenewer renewer >=> unit 42 + let req = withTokenRenewer renewer >=> singleton 42 // Act let! result = req |> runAsync ctx @@ -276,7 +276,7 @@ let ``Request with token renewer throws exception gives error`` () = let renewer _ = failwith "failing" |> Task.FromResult let ctx = Context.defaultContext - let req = withTokenRenewer renewer >=> unit 42 + let req = withTokenRenewer renewer >=> singleton 42 // Act let! result = req |> runAsync ctx