mirror of
https://github.com/Smaug123/WoofWare.Myriad
synced 2025-10-05 20:18:43 +00:00
Implement AllowAnyStatusCode (#41)
This commit is contained in:
@@ -361,4 +361,43 @@ module PureGymApi =
|
|||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
||||||
|
|
||||||
|
member _.GetWithAnyReturnCode (ct : CancellationToken option) =
|
||||||
|
async {
|
||||||
|
let! ct = Async.CancellationToken
|
||||||
|
|
||||||
|
let uri =
|
||||||
|
System.Uri (client.BaseAddress, System.Uri ("endpoint", System.UriKind.Relative))
|
||||||
|
|
||||||
|
let httpMessage =
|
||||||
|
new System.Net.Http.HttpRequestMessage (
|
||||||
|
Method = System.Net.Http.HttpMethod.Get,
|
||||||
|
RequestUri = uri
|
||||||
|
)
|
||||||
|
|
||||||
|
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
|
||||||
|
let node = response
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
||||||
|
|
||||||
|
member _.GetWithoutAnyReturnCode (ct : CancellationToken option) =
|
||||||
|
async {
|
||||||
|
let! ct = Async.CancellationToken
|
||||||
|
|
||||||
|
let uri =
|
||||||
|
System.Uri (client.BaseAddress, System.Uri ("endpoint", System.UriKind.Relative))
|
||||||
|
|
||||||
|
let httpMessage =
|
||||||
|
new System.Net.Http.HttpRequestMessage (
|
||||||
|
Method = System.Net.Http.HttpMethod.Get,
|
||||||
|
RequestUri = uri
|
||||||
|
)
|
||||||
|
|
||||||
|
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
|
||||||
|
let response = response.EnsureSuccessStatusCode ()
|
||||||
|
let node = response
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
||||||
}
|
}
|
||||||
|
@@ -16,13 +16,13 @@ type IPureGymApi =
|
|||||||
[<Get "v1/gyms/{gym_id}/attendance">]
|
[<Get "v1/gyms/{gym_id}/attendance">]
|
||||||
abstract GetGymAttendance : [<Path "gym_id">] gymId : int * ?ct : CancellationToken -> Task<GymAttendance>
|
abstract GetGymAttendance : [<Path "gym_id">] gymId : int * ?ct : CancellationToken -> Task<GymAttendance>
|
||||||
|
|
||||||
[<Get "v1/member">]
|
[<RestEase.GetAttribute "v1/member">]
|
||||||
abstract GetMember : ?ct : CancellationToken -> Task<Member>
|
abstract GetMember : ?ct : CancellationToken -> Task<Member>
|
||||||
|
|
||||||
[<Get "v1/gyms/{gym_id}">]
|
[<RestEase.Get "v1/gyms/{gym_id}">]
|
||||||
abstract GetGym : [<Path "gym_id">] gymId : int * ?ct : CancellationToken -> Task<Gym>
|
abstract GetGym : [<Path "gym_id">] gymId : int * ?ct : CancellationToken -> Task<Gym>
|
||||||
|
|
||||||
[<Get "v1/member/activity">]
|
[<GetAttribute "v1/member/activity">]
|
||||||
abstract GetMemberActivity : ?ct : CancellationToken -> Task<MemberActivityDto>
|
abstract GetMemberActivity : ?ct : CancellationToken -> Task<MemberActivityDto>
|
||||||
|
|
||||||
// We'll use this one to check handling of absolute URIs too
|
// We'll use this one to check handling of absolute URIs too
|
||||||
@@ -53,3 +53,10 @@ type IPureGymApi =
|
|||||||
|
|
||||||
[<Get "endpoint">]
|
[<Get "endpoint">]
|
||||||
abstract GetResponseMessage''' : ?ct : CancellationToken -> Task<HttpResponseMessage>
|
abstract GetResponseMessage''' : ?ct : CancellationToken -> Task<HttpResponseMessage>
|
||||||
|
|
||||||
|
[<Get "endpoint">]
|
||||||
|
[<AllowAnyStatusCode>]
|
||||||
|
abstract GetWithAnyReturnCode : ?ct : CancellationToken -> Task<HttpResponseMessage>
|
||||||
|
|
||||||
|
[<Get "endpoint">]
|
||||||
|
abstract GetWithoutAnyReturnCode : ?ct : CancellationToken -> Task<HttpResponseMessage>
|
||||||
|
@@ -10,6 +10,7 @@
|
|||||||
<Compile Include="HttpClient.fs"/>
|
<Compile Include="HttpClient.fs"/>
|
||||||
<Compile Include="TestPathParam.fs" />
|
<Compile Include="TestPathParam.fs" />
|
||||||
<Compile Include="TestReturnTypes.fs" />
|
<Compile Include="TestReturnTypes.fs" />
|
||||||
|
<Compile Include="TestAllowAnyStatusCode.fs" />
|
||||||
<Compile Include="TestSurface.fs"/>
|
<Compile Include="TestSurface.fs"/>
|
||||||
<Compile Include="TestRemoveOptions.fs"/>
|
<Compile Include="TestRemoveOptions.fs"/>
|
||||||
<Compile Include="TestJsonParse.fs"/>
|
<Compile Include="TestJsonParse.fs"/>
|
||||||
|
62
MyriadPlugin.Test/TestAllowAnyStatusCode.fs
Normal file
62
MyriadPlugin.Test/TestAllowAnyStatusCode.fs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
namespace MyriadPlugin.Test
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.Net
|
||||||
|
open System.Net.Http
|
||||||
|
open NUnit.Framework
|
||||||
|
open FsUnitTyped
|
||||||
|
open PureGym
|
||||||
|
|
||||||
|
[<TestFixture>]
|
||||||
|
module TestAllowAnyStatusCode =
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let ``Without AllowAnyStatusCode we throw`` () =
|
||||||
|
let proc (message : HttpRequestMessage) : HttpResponseMessage Async =
|
||||||
|
async {
|
||||||
|
message.Method |> shouldEqual HttpMethod.Get
|
||||||
|
let content = new StringContent ("nothing was here :(")
|
||||||
|
let resp = new HttpResponseMessage (HttpStatusCode.NotFound)
|
||||||
|
resp.Content <- content
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
use client = HttpClientMock.make (Uri "https://example.com") proc
|
||||||
|
let api = PureGymApi.make client
|
||||||
|
|
||||||
|
let exc =
|
||||||
|
async {
|
||||||
|
let! message = Async.AwaitTask (api.GetWithoutAnyReturnCode ()) |> Async.Catch
|
||||||
|
|
||||||
|
match message with
|
||||||
|
| Choice1Of2 _ -> return failwith "test failure"
|
||||||
|
| Choice2Of2 exc -> return exc
|
||||||
|
}
|
||||||
|
|> Async.RunSynchronously
|
||||||
|
|
||||||
|
let exc =
|
||||||
|
match exc with
|
||||||
|
| :? AggregateException as exc -> exc
|
||||||
|
| exc -> failwith $"Test failure: expected AggregateException, got %+A{exc}"
|
||||||
|
|
||||||
|
match exc.InnerException with
|
||||||
|
| :? HttpRequestException as exc -> exc.Message.Contains "404 (Not Found)" |> shouldEqual true
|
||||||
|
| e -> failwith $"Test failure: %+A{e}"
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let ``With AllowAnyStatusCode we do not throw`` () =
|
||||||
|
let proc (message : HttpRequestMessage) : HttpResponseMessage Async =
|
||||||
|
async {
|
||||||
|
message.Method |> shouldEqual HttpMethod.Get
|
||||||
|
let content = new StringContent ("nothing was here :(")
|
||||||
|
let resp = new HttpResponseMessage (HttpStatusCode.NotFound)
|
||||||
|
resp.Content <- content
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
use client = HttpClientMock.make (Uri "https://example.com") proc
|
||||||
|
let api = PureGymApi.make client
|
||||||
|
|
||||||
|
let message = api.GetWithAnyReturnCode().Result
|
||||||
|
message.StatusCode |> shouldEqual HttpStatusCode.NotFound
|
||||||
|
message.Content.ReadAsStringAsync().Result |> shouldEqual "nothing was here :("
|
@@ -52,6 +52,7 @@ module internal HttpClientGenerator =
|
|||||||
Arity : SynArgInfo list
|
Arity : SynArgInfo list
|
||||||
Args : Parameter list
|
Args : Parameter list
|
||||||
Identifier : Ident
|
Identifier : Ident
|
||||||
|
EnsureSuccessHttpCode : bool
|
||||||
}
|
}
|
||||||
|
|
||||||
let httpMethodString (m : HttpMethod) : string =
|
let httpMethodString (m : HttpMethod) : string =
|
||||||
@@ -116,6 +117,17 @@ module internal HttpClientGenerator =
|
|||||||
| matchingAttrs ->
|
| matchingAttrs ->
|
||||||
failwithf "Required exactly one recognised RestEase attribute on member, but got %i" matchingAttrs.Length
|
failwithf "Required exactly one recognised RestEase attribute on member, but got %i" matchingAttrs.Length
|
||||||
|
|
||||||
|
let shouldAllowAnyStatusCode (attrs : SynAttribute list) : bool =
|
||||||
|
attrs
|
||||||
|
|> List.exists (fun attr ->
|
||||||
|
match attr.TypeName.AsString with
|
||||||
|
| "AllowAnyStatusCode"
|
||||||
|
| "AllowAnyStatusCodeAttribute"
|
||||||
|
| "RestEase.AllowAnyStatusCode"
|
||||||
|
| "RestEase.AllowAnyStatusCodeAttribute" -> true
|
||||||
|
| _ -> false
|
||||||
|
)
|
||||||
|
|
||||||
let constructMember (info : MemberInfo) : SynMemberDefn =
|
let constructMember (info : MemberInfo) : SynMemberDefn =
|
||||||
let valInfo =
|
let valInfo =
|
||||||
SynValInfo.SynValInfo (
|
SynValInfo.SynValInfo (
|
||||||
@@ -392,14 +404,15 @@ module internal HttpClientGenerator =
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
yield
|
if info.EnsureSuccessHttpCode then
|
||||||
Let (
|
yield
|
||||||
"response",
|
Let (
|
||||||
SynExpr.CreateApp (
|
"response",
|
||||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "response" ; "EnsureSuccessStatusCode" ]),
|
SynExpr.CreateApp (
|
||||||
SynExpr.CreateConst SynConst.Unit
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "response" ; "EnsureSuccessStatusCode" ]),
|
||||||
|
SynExpr.CreateConst SynConst.Unit
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
match info.ReturnType with
|
match info.ReturnType with
|
||||||
| HttpResponseMessage -> yield Let ("node", SynExpr.CreateIdentString "response")
|
| HttpResponseMessage -> yield Let ("node", SynExpr.CreateIdentString "response")
|
||||||
| String ->
|
| String ->
|
||||||
@@ -617,6 +630,8 @@ module internal HttpClientGenerator =
|
|||||||
|
|
||||||
let httpMethod, url = extractHttpInformation attrs
|
let httpMethod, url = extractHttpInformation attrs
|
||||||
|
|
||||||
|
let shouldEnsureSuccess = not (shouldAllowAnyStatusCode attrs)
|
||||||
|
|
||||||
{
|
{
|
||||||
HttpMethod = httpMethod
|
HttpMethod = httpMethod
|
||||||
UrlTemplate = url
|
UrlTemplate = url
|
||||||
@@ -624,6 +639,7 @@ module internal HttpClientGenerator =
|
|||||||
Arity = arity
|
Arity = arity
|
||||||
Args = args
|
Args = args
|
||||||
Identifier = ident
|
Identifier = ident
|
||||||
|
EnsureSuccessHttpCode = shouldEnsureSuccess
|
||||||
}
|
}
|
||||||
| _ -> failwithf "Unrecognised member definition: %+A" defn
|
| _ -> failwithf "Unrecognised member definition: %+A" defn
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user