import std/[unittest, strutils] import helpers import chronos, chronos/apps import ../presto/[route, segpath, server, client] when defined(nimHasUsed): {.used.} template asyncTest*(name: string, body: untyped): untyped = test name: waitFor(( proc() {.async, gcsafe.} = body )()) suite "REST API client test suite": let serverAddress = initTAddress("127.0.0.1:30180") asyncTest "Simple requests (without arguments) test": var router = RestRouter.init(testValidate) router.api(MethodGet, "/test/simple/1") do () -> RestApiResponse: return RestApiResponse.response("ok-1") router.api(MethodPost, "/test/simple/2",) do ( contentBody: Option[ContentBody]) -> RestApiResponse: let obody = if contentBody.isSome(): let body = contentBody.get() body.contentType & "," & bytesToString(body.data) else: "nobody" return RestApiResponse.response(obody) router.api(MethodGet, "/test/simple/3") do () -> RestApiResponse: return RestApiResponse.error(Http504, "Some error", "text/error") router.api(MethodPost, "/test/simple/4") do ( contentBody: Option[ContentBody]) -> RestApiResponse: return RestApiResponse.error(Http505, "Different error", "application/error") router.api(MethodGet, "/test/simple/5") do () -> RestApiResponse: return RestApiResponse.redirect(location = "/test/redirect/5") router.api(MethodGet, "/test/redirect/5") do () -> RestApiResponse: return RestApiResponse.response("ok-5-redirect") router.api(MethodPost, "/test/simple/6") do ( contentBody: Option[ContentBody]) -> RestApiResponse: return RestApiResponse.redirect(location = "/test/redirect/6") router.api(MethodPost, "/test/redirect/6") do ( contentBody: Option[ContentBody]) -> RestApiResponse: let obody = if contentBody.isSome(): let body = contentBody.get() body.contentType & "," & bytesToString(body.data) else: "nobody" return RestApiResponse.response(obody) let serverFlags = {HttpServerFlags.NotifyDisconnect, HttpServerFlags.QueryCommaSeparatedArray} var sres = RestServerRef.new(router, serverAddress, serverFlags = serverFlags) let server = sres.get() server.start() proc testSimple1(): string {.rest, endpoint: "/test/simple/1".} proc testSimple2(body: string): string {.rest, endpoint: "/test/simple/2", meth: MethodPost.} proc testSimple3(): string {.rest, endpoint: "/test/simple/3".} proc testSimple4(body: string): string {.rest, endpoint: "/test/simple/4", meth: MethodPost.} proc testSimple5(): string {.rest, endpoint: "/test/simple/5", meth: HttpMethod.MethodGet.} proc testSimple6(body: string): string {.rest, endpoint: "/test/simple/6", meth: HttpMethod.MethodPost.} var client = RestClientRef.new(serverAddress, HttpClientScheme.NonSecure) let res1 = await client.testSimple1() let res2 = await client.testSimple2("ok-2", restContentType = "text/text") let res5 = await client.testSimple5() let res6 = await client.testSimple6("ok-6", restContentType = "text/html") check: res1 == "ok-1" res2 == "text/text,ok-2" res5 == "ok-5-redirect" res6 == "text/html,ok-6" block: let (code, message, contentType) = try: let res3 {.used.} = await client.testSimple3() (0, "", "") except RestResponseError as exc: (exc.status, exc.message, exc.contentType) except CatchableError: (0, "", "") check: code == 504 message == "Some error" contentType == "text/error" block: let (code, message, contentType) = try: let res3 {.used.} = await client.testSimple4("ok-4", restContentType = "text/text") (0, "", "") except RestResponseError as exc: (exc.status, exc.message, exc.contentType) except CatchableError: (0, "", "") check: code == 505 message == "Different error" contentType == "application/error" await client.closeWait() await server.stop() await server.closeWait() asyncTest "Requests [path] arguments test": var router = RestRouter.init(testValidate) router.api(MethodGet, "/test/path/{smp1}") do ( smp1: int) -> RestApiResponse: if smp1.isErr(): return RestApiResponse.error(Http411, $smp1.error()) return RestApiResponse.response("ok:" & $smp1.get()) router.api(MethodPost, "/test/path/{smp1}/{smp2}",) do ( smp1: int, smp2: string, contentBody: Option[ContentBody]) -> RestApiResponse: if smp1.isErr(): return RestApiResponse.error(Http411, $smp1.error()) if smp2.isErr(): return RestApiResponse.error(Http412, $smp2.error()) let obody = if contentBody.isSome(): let body = contentBody.get() body.contentType & "," & bytesToString(body.data) else: "nobody" return RestApiResponse.response($smp1.get() & ":" & smp2.get() & ":" & obody) router.api(MethodGet, "/test/path/{smp1}/{smp2}/{smp3}") do ( smp1: int, smp2: string, smp3: seq[byte]) -> RestApiResponse: if smp1.isErr(): return RestApiResponse.error(Http411, $smp1.error()) if smp2.isErr(): return RestApiResponse.error(Http412, $smp2.error()) if smp3.isErr(): return RestApiResponse.error(Http413, $smp3.error()) return RestApiResponse.response($smp1.get() & ":" & smp2.get() & ":" & bytesToString(smp3.get())) router.api(MethodPost, "/test/path/{smp1}/{smp2}/{smp3}") do ( smp1: int, smp2: string, smp3: seq[byte], contentBody: Option[ContentBody]) -> RestApiResponse: if smp1.isErr(): return RestApiResponse.error(Http411, $smp1.error()) if smp2.isErr(): return RestApiResponse.error(Http412, $smp2.error()) if smp3.isErr(): return RestApiResponse.error(Http413, $smp3.error()) let obody = if contentBody.isSome(): let body = contentBody.get() body.contentType & "," & bytesToString(body.data) else: "nobody" return RestApiResponse.response($smp1.get() & ":" & smp2.get() & ":" & bytesToString(smp3.get()) & ":" & obody) router.api(MethodGet, "/test/path/redirect/{smp1}") do ( smp1: int) -> RestApiResponse: if smp1.isErr(): return RestApiResponse.error(Http411, $smp1.error()) let location = "/test/redirect/" & $smp1.get() return RestApiResponse.redirect(location = location) router.api(MethodGet, "/test/redirect/{smp1}") do ( smp1: int) -> RestApiResponse: if smp1.isErr(): return RestApiResponse.error(Http411, $smp1.error()) return RestApiResponse.response("ok-redirect-" & $smp1.get()) router.api(MethodPost, "/test/path/redirect/{smp1}") do ( smp1: int, contentBody: Option[ContentBody]) -> RestApiResponse: if smp1.isErr(): return RestApiResponse.error(Http411, $smp1.error()) let location = "/test/redirect/" & $smp1.get() return RestApiResponse.redirect(location = location) router.api(MethodPost, "/test/redirect/{smp1}") do ( smp1: int, contentBody: Option[ContentBody]) -> RestApiResponse: if smp1.isErr(): return RestApiResponse.error(Http411, $smp1.error()) let obody = if contentBody.isSome(): let body = contentBody.get() body.contentType & "," & bytesToString(body.data) else: "nobody" return RestApiResponse.response("ok-redirect-" & $smp1.get() & ":" & obody) let serverFlags = {HttpServerFlags.NotifyDisconnect, HttpServerFlags.QueryCommaSeparatedArray} var sres = RestServerRef.new(router, serverAddress, serverFlags = serverFlags) let server = sres.get() server.start() proc testPath1(smp1: int): string {.rest, endpoint: "/test/path/{smp1}".} proc testPath2(smp1: int, smp2: string, body: string): string {. rest, endpoint: "/test/path/{smp1}/{smp2}", meth: MethodPost.} proc testGetPath3(smp1: int, smp2: string, smp3: seq[byte]): string {. rest, endpoint: "/test/path/{smp1}/{smp2}/{smp3}".} proc testPostPath3(smp1: int, smp2: string, smp3: seq[byte], body: string): string {. rest, endpoint: "/test/path/{smp1}/{smp2}/{smp3}", meth: MethodPost.} proc testGetRedirect(smp1: int): string {. rest, endpoint: "/test/redirect/{smp1}", meth: MethodGet.} proc testPostRedirect(smp1: int, body: string): string {. rest, endpoint: "/test/redirect/{smp1}", meth: MethodPost.} var client = RestClientRef.new(serverAddress, HttpClientScheme.NonSecure) let res1 = await client.testPath1(123456) let res2 = await client.testPath2(234567, "argstr1", "ok-2", restContentType = "text/text") let res3 = await client.testGetPath3(345678, "argstr2", stringToBytes("876543")) let res4 = await client.testPostPath3(456789, "argstr3", stringToBytes("987654"), "ok-post-4", restContentType = "text/html") let res5 = await client.testGetRedirect(567890) let res6 = await client.testPostRedirect(678901, "ok-post-6", restContentType = "text/text") let res7 = await client.testGetPath3(345678, "запрос", stringToBytes("876543")) check: res1 == "ok:123456" res2 == "234567:argstr1:text/text,ok-2" res3 == "345678:argstr2:876543" res4 == "456789:argstr3:987654:text/html,ok-post-4" res5 == "ok-redirect-567890" res6 == "ok-redirect-678901:text/text,ok-post-6" res7 == "345678:запрос:876543" await client.closeWait() await server.stop() await server.closeWait() asyncTest "Requests [query] arguments test": var router = RestRouter.init(testValidate) router.api(MethodGet, "/test/query/1") do ( q1: Option[int]) -> RestApiResponse: let o1 = if q1.isSome(): let res = q1.get() if res.isErr(): return RestApiResponse.error(Http411, $res.error()) $res.get() else: "" return RestApiResponse.response("ok-1:[" & o1 & "]") router.api(MethodGet, "/test/query/2") do ( q1: seq[int]) -> RestApiResponse: let o1 = if q1.isErr(): return RestApiResponse.error(Http411, $q1.error()) else: q1.get().join(",") return RestApiResponse.response("ok-2:[" & o1 & "]") router.api(MethodPost, "/test/query/3",) do ( q1: Option[int], q2: Option[string], contentBody: Option[ContentBody]) -> RestApiResponse: let o1 = if q1.isSome(): let res = q1.get() if res.isErr(): return RestApiResponse.error(Http411, $res.error()) $res.get() else: "" let o2 = if q2.isSome(): let res = q2.get() if res.isErr(): return RestApiResponse.error(Http412, $res.error()) res.get() else: "" let obody = if contentBody.isSome(): let body = contentBody.get() body.contentType & "," & bytesToString(body.data) else: "nobody" return RestApiResponse.response("ok-3:" & "[" & o1 & "]:" & "[" & o2 & "]:" & obody) router.api(MethodPost, "/test/query/4",) do ( q1: seq[int], q2: seq[string], contentBody: Option[ContentBody]) -> RestApiResponse: let o1 = if q1.isErr(): return RestApiResponse.error(Http411, $q1.error()) else: q1.get.join(",") let o2 = if q2.isErr(): return RestApiResponse.error(Http412, $q2.error()) else: q2.get.join(",") let obody = if contentBody.isSome(): let body = contentBody.get() body.contentType & "," & bytesToString(body.data) else: "nobody" return RestApiResponse.response("ok-4:" & "[" & o1 & "]:" & "[" & o2 & "]:" & obody) router.api(MethodGet, "/test/query/5") do ( q1: Option[int]) -> RestApiResponse: return RestApiResponse.redirect(location = "/test/query/redirect/5", preserveQuery = true) router.api(MethodGet, "/test/query/redirect/5") do ( q1: Option[int]) -> RestApiResponse: let o1 = if q1.isSome(): let res = q1.get() if res.isErr(): return RestApiResponse.error(Http411, $res.error()) $res.get() else: "" return RestApiResponse.response("ok-5:[" & o1 & "]") router.api(MethodGet, "/test/query/6") do ( q1: seq[int]) -> RestApiResponse: return RestApiResponse.redirect(location = "/test/query/redirect/6", preserveQuery = true) router.api(MethodGet, "/test/query/redirect/6") do ( q1: seq[int]) -> RestApiResponse: let o1 = if q1.isErr(): return RestApiResponse.error(Http411, $q1.error()) else: q1.get.join(",") return RestApiResponse.response("ok-6:[" & o1 & "]") router.api(MethodPost, "/test/query/7") do ( q1: Option[int], contentBody: Option[ContentBody]) -> RestApiResponse: return RestApiResponse.redirect(location = "/test/query/redirect/7", preserveQuery = true) router.api(MethodPost, "/test/query/redirect/7",) do ( q1: Option[int], contentBody: Option[ContentBody]) -> RestApiResponse: let o1 = if q1.isSome(): let res = q1.get() if res.isErr(): return RestApiResponse.error(Http411, $res.error()) $res.get() else: "" let obody = if contentBody.isSome(): let body = contentBody.get() body.contentType & "," & bytesToString(body.data) else: "nobody" return RestApiResponse.response("ok-7:[" & o1 & "]:" & obody) router.api(MethodPost, "/test/query/8") do ( q1: seq[int], contentBody: Option[ContentBody]) -> RestApiResponse: return RestApiResponse.redirect(location = "/test/query/redirect/8", preserveQuery = true) router.api(MethodPost, "/test/query/redirect/8",) do ( q1: seq[int], contentBody: Option[ContentBody]) -> RestApiResponse: let o1 = if q1.isErr(): return RestApiResponse.error(Http411, $q1.error()) else: q1.get.join(",") let obody = if contentBody.isSome(): let body = contentBody.get() body.contentType & "," & bytesToString(body.data) else: "nobody" return RestApiResponse.response("ok-8:[" & o1 & "]:" & obody) let serverFlags = {HttpServerFlags.NotifyDisconnect, HttpServerFlags.QueryCommaSeparatedArray} var sres = RestServerRef.new(router, serverAddress, serverFlags = serverFlags) let server = sres.get() server.start() proc testQuery1(): string {.rest, endpoint: "/test/query/1".} proc testQuery1(q1: Option[int]): string {.rest, endpoint: "/test/query/1".} proc testQuery2(): string {.rest, endpoint: "/test/query/2".} proc testQuery2(q1: seq[int]): string {.rest, endpoint: "/test/query/2".} proc testQuery3(body: string): string {. rest, endpoint: "/test/query/3", meth: MethodPost.} proc testQuery3(q1: Option[int], q2: Option[string], body: string): string {. rest, endpoint: "/test/query/3", meth: MethodPost.} proc testQuery4(body: string): string {. rest, endpoint: "/test/query/4", meth: MethodPost.} proc testQuery4(q1: seq[int], q2: seq[string], body: string): string {. rest, endpoint: "/test/query/4", meth: MethodPost.} proc testQueryGetRedirect(q1: Option[int]): string {. rest, endpoint: "/test/query/5", meth: MethodGet.} proc testQueryGetRedirect(q1: seq[int]): string {. rest, endpoint: "/test/query/6", meth: MethodGet.} proc testQueryPostRedirect(q1: Option[int], body: string): string {. rest, endpoint: "/test/query/7", meth: MethodPost.} proc testQueryPostRedirect(q1: seq[int], body: string): string {. rest, endpoint: "/test/query/8", meth: MethodPost.} var client1 = RestClientRef.new(serverAddress, HttpClientScheme.NonSecure, {}) var client2 = RestClientRef.new(serverAddress, HttpClientScheme.NonSecure, {RestClientFlag.CommaSeparatedArray}) for client in [client1, client2]: let res1 = await client.testQuery1() let res2 = await client.testQuery1(none[int]()) let res3 = await client.testQuery1(some(123456)) let res4 = await client.testQuery2() let res5 = await client.testQuery2(newSeq[int]()) let res6 = await client.testQuery2(@[1,2,3,4,5,6]) let res7 = await client.testQuery3("body3", restContentType = "text/text") let res8 = await client.testQuery3(none[int](), some("запрос"), "body4", restContentType = "text/text") let res9 = await client.testQuery3(some(234567), none[string](), "body5", restContentType = "text/text") let res10 = await client.testQuery3(some(345678), some("запрос"), "body6", restContentType = "text/text") let res11 = await client.testQuery4("body4", restContentType = "text/text") let res12 = await client.testQuery4(@[1, 2, 3], newSeq[string](), "body5", restContentType = "text/text") let res13 = await client.testQuery4(newSeq[int](), @["запрос1", "запрос2", "запрос3"], "body6", restContentType = "text/text") let res14 = await client.testQuery4(@[1, 2, 3], @["запрос1", "запрос2", "запрос3"], "body7", restContentType = "text/text") let res15 = await client.testQueryGetRedirect(none[int]()) let res16 = await client.testQueryGetRedirect(some(123456)) let res17 = await client.testQueryGetRedirect(newSeq[int]()) let res18 = await client.testQueryGetRedirect(@[11, 22, 33, 44, 55]) let res19 = await client.testQueryPostRedirect(none[int](), "bodyPost1", restContentType = "text/text") let res20 = await client.testQueryPostRedirect(some(123456), "bodyPost2", restContentType = "text/text") let res21 = await client.testQueryPostRedirect(newSeq[int](), "bodyPost3", restContentType = "text/text") let res22 = await client.testQueryPostRedirect(@[11, 22, 33, 44, 55], "bodyPost4", restContentType = "text/text") check: res1 == "ok-1:[]" res2 == "ok-1:[]" res3 == "ok-1:[123456]" res4 == "ok-2:[]" res5 == "ok-2:[]" res6 == "ok-2:[1,2,3,4,5,6]" res7 == "ok-3:[]:[]:text/text,body3" res8 == "ok-3:[]:[запрос]:text/text,body4" res9 == "ok-3:[234567]:[]:text/text,body5" res10 == "ok-3:[345678]:[запрос]:text/text,body6" res11 == "ok-4:[]:[]:text/text,body4" res12 == "ok-4:[1,2,3]:[]:text/text,body5" res13 == "ok-4:[]:[запрос1,запрос2,запрос3]:text/text,body6" res14 == "ok-4:[1,2,3]:[запрос1,запрос2,запрос3]:text/text,body7" res15 == "ok-5:[]" res16 == "ok-5:[123456]" res17 == "ok-6:[]" res18 == "ok-6:[11,22,33,44,55]" res19 == "ok-7:[]:text/text,bodyPost1" res20 == "ok-7:[123456]:text/text,bodyPost2" res21 == "ok-8:[]:text/text,bodyPost3" res22 == "ok-8:[11,22,33,44,55]:text/text,bodyPost4" await client1.closeWait() await client2.closeWait() await server.stop() await server.closeWait() asyncTest "Requests [path + query] arguments test": var router = RestRouter.init(testValidate) router.api(MethodGet, "/test/1/full/{smp1}") do ( smp1: int, q1: seq[int]) -> RestApiResponse: if smp1.isErr(): return RestApiResponse.error(Http411, $smp1.error()) let o1 = if q1.isErr(): return RestApiResponse.error(Http412, $q1.error()) else: q1.get.join(",") return RestApiResponse.response("ok-1:" & $smp1.get() & ":[" & o1 & "]") router.api(MethodPost, "/test/2/full/{smp1}/{smp2}") do ( smp1: int, smp2: string, q1: seq[int], q2: seq[string], contentBody: Option[ContentBody]) -> RestApiResponse: if smp1.isErr(): return RestApiResponse.error(Http411, $smp1.error()) if smp2.isErr(): return RestApiResponse.error(Http412, $smp2.error()) let o1 = if q1.isErr(): return RestApiResponse.error(Http413, $q1.error()) else: q1.get.join(",") let o2 = if q2.isErr(): return RestApiResponse.error(Http414, $q2.error()) else: q2.get.join(",") let obody = if contentBody.isSome(): let body = contentBody.get() body.contentType & "," & bytesToString(body.data) else: "nobody" return RestApiResponse.response("ok-2:" & $smp1.get() & ":" & smp2.get() & ":[" & o1 & "]:[" & o2 & "]:" & obody) router.api(MethodGet, "/test/3/full/{smp1}/{smp2}/{smp3}") do ( smp1: int, smp2: string, smp3: seq[byte], q1: seq[int], q2: seq[string], q3: Option[seq[byte]]) -> RestApiResponse: if smp1.isErr(): return RestApiResponse.error(Http411, $smp1.error()) if smp2.isErr(): return RestApiResponse.error(Http412, $smp2.error()) if smp3.isErr(): return RestApiResponse.error(Http413, $smp3.error()) let o1 = if q1.isErr(): return RestApiResponse.error(Http413, $q1.error()) else: q1.get.join(",") let o2 = if q2.isErr(): return RestApiResponse.error(Http414, $q2.error()) else: q2.get.join(",") let o3 = if q3.isSome(): let res = q3.get() if res.isErr(): return RestApiResponse.error(Http412, $res.error()) bytesToString(res.get()) else: "" return RestApiResponse.response("ok-3:" & $smp1.get() & ":" & smp2.get() & ":" & bytesToString(smp3.get()) & ":[" & o1 & "]:[" & o2 & "]:[" & o3 & "]") router.api(MethodPost, "/test/3/full/{smp1}/{smp2}/{smp3}") do ( smp1: int, smp2: string, smp3: seq[byte], q1: seq[int], q2: seq[string], q3: Option[seq[byte]], contentBody: Option[ContentBody]) -> RestApiResponse: if smp1.isErr(): return RestApiResponse.error(Http411, $smp1.error()) if smp2.isErr(): return RestApiResponse.error(Http412, $smp2.error()) if smp3.isErr(): return RestApiResponse.error(Http413, $smp3.error()) let o1 = if q1.isErr(): return RestApiResponse.error(Http413, $q1.error()) else: q1.get.join(",") let o2 = if q2.isErr(): return RestApiResponse.error(Http414, $q2.error()) else: q2.get.join(",") let o3 = if q3.isSome(): let res = q3.get() if res.isErr(): return RestApiResponse.error(Http412, $res.error()) bytesToString(res.get()) else: "" let obody = if contentBody.isSome(): let body = contentBody.get() body.contentType & "," & bytesToString(body.data) else: "nobody" return RestApiResponse.response("ok-3:" & $smp1.get() & ":" & smp2.get() & ":" & bytesToString(smp3.get()) & ":[" & o1 & "]:[" & o2 & "]:[" & o3 & "]:" & obody) router.api(MethodGet, "/test/4/full/redirect/{smp1}") do ( smp1: int, q1: seq[int]) -> RestApiResponse: if smp1.isErr(): return RestApiResponse.error(Http411, $smp1.error()) let location = "/test/redirect/" & $smp1.get() return RestApiResponse.redirect(location = location, preserveQuery = true) router.api(MethodGet, "/test/redirect/{smp1}") do ( smp1: int, q1: seq[int]) -> RestApiResponse: if smp1.isErr(): return RestApiResponse.error(Http411, $smp1.error()) let o1 = if q1.isErr(): return RestApiResponse.error(Http413, $q1.error()) else: q1.get.join(",") return RestApiResponse.response( "ok-redirect-" & $smp1.get() & ":[" & o1 & "]") router.api(MethodPost, "/test/5/full/redirect/{smp1}") do ( smp1: int, q1: seq[int], contentBody: Option[ContentBody]) -> RestApiResponse: if smp1.isErr(): return RestApiResponse.error(Http411, $smp1.error()) let location = "/test/redirect/" & $smp1.get() return RestApiResponse.redirect(location = location, preserveQuery = true) router.api(MethodPost, "/test/redirect/{smp1}") do ( smp1: int, q1: seq[int], contentBody: Option[ContentBody]) -> RestApiResponse: if smp1.isErr(): return RestApiResponse.error(Http411, $smp1.error()) let o1 = if q1.isErr(): return RestApiResponse.error(Http413, $q1.error()) else: q1.get.join(",") let obody = if contentBody.isSome(): let body = contentBody.get() body.contentType & "," & bytesToString(body.data) else: "nobody" return RestApiResponse.response( "ok-redirect-" & $smp1.get() & ":[" & o1 & "]:" & obody) let serverFlags = {HttpServerFlags.NotifyDisconnect, HttpServerFlags.QueryCommaSeparatedArray} var sres = RestServerRef.new(router, serverAddress, serverFlags = serverFlags) let server = sres.get() server.start() proc testFull1(smp1: int): string {. rest, endpoint: "/test/1/full/{smp1}".} proc testFull1(smp1: int, q1: seq[int]): string {. rest, endpoint: "/test/1/full/{smp1}".} proc testFull2(smp1: int, smp2: string, body: string): string {. rest, endpoint: "/test/2/full/{smp1}/{smp2}", meth: MethodPost.} proc testFull2(smp1: int, smp2: string, q1: seq[int], body: string): string {. rest, endpoint: "/test/2/full/{smp1}/{smp2}", meth: MethodPost.} proc testFull2(smp1: int, smp2: string, q2: seq[string], body: string): string {. rest, endpoint: "/test/2/full/{smp1}/{smp2}", meth: MethodPost.} proc testFull2(smp1: int, smp2: string, q1: seq[int], q2: seq[string], body: string): string {. rest, endpoint: "/test/2/full/{smp1}/{smp2}", meth: MethodPost.} proc testFull3Get(smp1: int, smp2: string, smp3: seq[byte]): string {. rest, endpoint: "/test/3/full/{smp1}/{smp2}/{smp3}", meth: MethodGet.} proc testFull3Get(smp1: int, smp2: string, smp3: seq[byte], q1: seq[int]): string {. rest, endpoint: "/test/3/full/{smp1}/{smp2}/{smp3}", meth: MethodGet.} proc testFull3Get(smp1: int, smp2: string, smp3: seq[byte], q2: seq[string]): string {. rest, endpoint: "/test/3/full/{smp1}/{smp2}/{smp3}", meth: MethodGet.} proc testFull3Get(smp1: int, smp2: string, smp3: seq[byte], q3: Option[seq[byte]]): string {. rest, endpoint: "/test/3/full/{smp1}/{smp2}/{smp3}", meth: MethodGet.} proc testFull3Get(smp1: int, smp2: string, smp3: seq[byte], q1: seq[int], q3: Option[seq[byte]]): string {. rest, endpoint: "/test/3/full/{smp1}/{smp2}/{smp3}", meth: MethodGet.} proc testFull3Get(smp1: int, smp2: string, smp3: seq[byte], q1: seq[int], q2: seq[string], q3: Option[seq[byte]]): string {. rest, endpoint: "/test/3/full/{smp1}/{smp2}/{smp3}", meth: MethodGet.} proc testFull3Post(smp1: int, smp2: string, smp3: seq[byte], body: string): string {. rest, endpoint: "/test/3/full/{smp1}/{smp2}/{smp3}", meth: MethodPost.} proc testFull3Post(smp1: int, smp2: string, smp3: seq[byte], q1: seq[int], body: string): string {. rest, endpoint: "/test/3/full/{smp1}/{smp2}/{smp3}", meth: MethodPost.} proc testFull3Post(smp1: int, smp2: string, smp3: seq[byte], q2: seq[string], body: string): string {. rest, endpoint: "/test/3/full/{smp1}/{smp2}/{smp3}", meth: MethodPost.} proc testFull3Post(smp1: int, smp2: string, smp3: seq[byte], q3: Option[seq[byte]], body: string): string {. rest, endpoint: "/test/3/full/{smp1}/{smp2}/{smp3}", meth: MethodPost.} proc testFull3Post(smp1: int, smp2: string, smp3: seq[byte], q1: seq[int], q3: Option[seq[byte]], body: string): string {. rest, endpoint: "/test/3/full/{smp1}/{smp2}/{smp3}", meth: MethodPost.} proc testFull3Post(smp1: int, smp2: string, smp3: seq[byte], q1: seq[int], q2: seq[string], q3: Option[seq[byte]], body: string): string {. rest, endpoint: "/test/3/full/{smp1}/{smp2}/{smp3}", meth: MethodPost.} proc testFull4Redirect(smp1: int): string {. rest, endpoint: "/test/4/full/redirect/{smp1}", meth: MethodGet.} proc testFull4Redirect(smp1: int, q1: seq[int]): string {. rest, endpoint: "/test/4/full/redirect/{smp1}", meth: MethodGet.} proc testFull5Redirect(smp1: int, body: string): string {. rest, endpoint: "/test/5/full/redirect/{smp1}", meth: MethodPost.} proc testFull5Redirect(smp1: int, q1: seq[int], body: string): string {. rest, endpoint: "/test/5/full/redirect/{smp1}", meth: MethodPost.} var client1 = RestClientRef.new(serverAddress, HttpClientScheme.NonSecure) var client2 = RestClientRef.new(serverAddress, HttpClientScheme.NonSecure, {RestClientFlag.CommaSeparatedArray}) for client in [client1, client2]: let res1 = await client.testFull1(123) let res2 = await client.testFull1(124, newSeq[int]()) let res3 = await client.testFull1(125, @[16, 32, 64, 128, 256, 512, 1024]) let res4 = await client.testFull2(126, "textarg1", "bodydata1", restContentType = "text/text") let res5 = await client.testFull2(127, "textarg2", newSeq[int](), "bodydata2", restContentType = "text/text") let res6 = await client.testFull2(128, "textarg3", @[16, 32, 64, 128, 256], "bodydata3", restContentType = "text/text") let res7 = await client.testFull2(129, "textarg4", newSeq[string](), "bodydata4", restContentType = "text/text") let res8 = await client.testFull2(130, "textarg5", @["запрос1", "запрос2", "запрос3"], "bodydata5", restContentType = "text/text") let res9 = await client.testFull2(131, "textarg6", newSeq[int](), newSeq[string](), "bodydata6", restContentType = "text/text") let res10 = await client.testFull2(132, "textarg7", @[16, 32, 64, 128, 256], @["запрос1", "запрос2", "запрос3"], "bodydata7", restContentType = "text/text") let res11 = await client.testFull3Get(133, "textarg1", stringToBytes("133")) let res12 = await client.testFull3Get(134, "textarg2", stringToBytes("134"), newSeq[int]()) let res13 = await client.testFull3Get(135, "textarg3", stringToBytes("135"), @[16, 32, 64, 128, 256]) let res14 = await client.testFull3Get(136, "textarg4", stringToBytes("136"), newSeq[string]()) let res15 = await client.testFull3Get(137, "textarg5", stringToBytes("137"), @["запрос1", "запрос2", "запрос3"]) let res16 = await client.testFull3Get(138, "textarg6", stringToBytes("138"), none[seq[byte]]()) let res17 = await client.testFull3Get(139, "textarg7", stringToBytes("139"), some(stringToBytes("byteArg1"))) let res18 = await client.testFull3Get(140, "textarg8", stringToBytes("140"), newSeq[int](), none[seq[byte]]()) let res19 = await client.testFull3Get(141, "textarg9", stringToBytes("141"), @[16, 32, 64, 128, 256], none[seq[byte]]()) let res20 = await client.testFull3Get(142, "textarg10", stringToBytes("142"), newSeq[int](), some(stringToBytes("byteArg2"))) let res21 = await client.testFull3Get(143, "textarg11", stringToBytes("143"), @[16, 32, 64, 128, 256], some(stringToBytes("byteArg3"))) let res22 = await client.testFull3Get(144, "textarg12", stringToBytes("144"), newSeq[int](), newSeq[string](), none[seq[byte]]()) let res23 = await client.testFull3Get(145, "textarg13", stringToBytes("145"), @[16, 32, 64, 128, 256], @["запрос1", "запрос2", "запрос3"], some(stringToBytes("byteArg4"))) let res24 = await client.testFull3Post(146, "textarg1", stringToBytes("146"), "bodyArg1", restContentType = "text/text1") let res25 = await client.testFull3Post(147, "textarg2", stringToBytes("147"), newSeq[int](), "bodyArg2", restContentType = "text/text2") let res26 = await client.testFull3Post(148, "textarg3", stringToBytes("148"), @[16, 32, 64, 128, 256], "bodyArg3", restContentType = "text/text3") let res27 = await client.testFull3Post(149, "textarg4", stringToBytes("149"), newSeq[string](), "bodyArg4", restContentType = "text/text4") let res28 = await client.testFull3Post(150, "textarg5", stringToBytes("150"), @["запрос1", "запрос2", "запрос3"], "bodyArg5", restContentType = "text/text5") let res29 = await client.testFull3Post(151, "textarg6", stringToBytes("151"), none[seq[byte]](), "bodyArg6", restContentType = "text/text6") let res30 = await client.testFull3Post(152, "textarg7", stringToBytes("152"), some(stringToBytes("byteArg1")), "bodyArg7", restContentType = "text/text7") let res31 = await client.testFull3Post(153, "textarg8", stringToBytes("153"), newSeq[int](), none[seq[byte]](), "bodyArg8", restContentType = "text/text8") let res32 = await client.testFull3Post(154, "textarg9", stringToBytes("154"), @[16, 32, 64, 128, 256], none[seq[byte]](), "bodyArg9", restContentType = "text/text9") let res33 = await client.testFull3Post(155, "textarg10", stringToBytes("155"), newSeq[int](), some(stringToBytes("byteArg2")), "bodyArg10", restContentType = "text/text10") let res34 = await client.testFull3Post(156, "textarg11", stringToBytes("156"), @[16, 32, 64, 128, 256], some(stringToBytes("byteArg3")), "bodyArg11", restContentType = "text/text11") let res35 = await client.testFull3Post(157, "textarg12", stringToBytes("157"), newSeq[int](), newSeq[string](), none[seq[byte]](), "bodyArg12", restContentType = "text/text12") let res36 = await client.testFull3Post(158, "textarg13", stringToBytes("158"), @[16, 32, 64, 128, 256], @["запрос1", "запрос2", "запрос3"], some(stringToBytes("byteArg4")), "bodyArg13", restContentType = "text/text13") let res37 = await client.testFull4Redirect(159) let res38 = await client.testFull4Redirect(160, newSeq[int]()) let res39 = await client.testFull4Redirect(161, @[16, 32, 64, 128, 256]) let res40 = await client.testFull5Redirect(162, "bodyArg14", restContentType = "text/text") let res41 = await client.testFull5Redirect(163, newSeq[int](), "bodyArg15", restContentType = "text/text") let res42 = await client.testFull5Redirect(164, @[256, 512, 1024, 2048], "bodyArg16", restContentType = "text/text") check: res1 == "ok-1:123:[]" res2 == "ok-1:124:[]" res3 == "ok-1:125:[16,32,64,128,256,512,1024]" res4 == "ok-2:126:textarg1:[]:[]:text/text,bodydata1" res5 == "ok-2:127:textarg2:[]:[]:text/text,bodydata2" res6 == "ok-2:128:textarg3:[16,32,64,128,256]:[]:text/text,bodydata3" res7 == "ok-2:129:textarg4:[]:[]:text/text,bodydata4" res8 == "ok-2:130:textarg5:[]:[запрос1,запрос2,запрос3]:text/text," & "bodydata5" res9 == "ok-2:131:textarg6:[]:[]:text/text,bodydata6" res10 == "ok-2:132:textarg7:[16,32,64,128,256]:[запрос1,запрос2," & "запрос3]:text/text,bodydata7" res11 == "ok-3:133:textarg1:133:[]:[]:[]" res12 == "ok-3:134:textarg2:134:[]:[]:[]" res13 == "ok-3:135:textarg3:135:[16,32,64,128,256]:[]:[]" res14 == "ok-3:136:textarg4:136:[]:[]:[]" res15 == "ok-3:137:textarg5:137:[]:[запрос1,запрос2,запрос3]:[]" res16 == "ok-3:138:textarg6:138:[]:[]:[]" res17 == "ok-3:139:textarg7:139:[]:[]:[byteArg1]" res18 == "ok-3:140:textarg8:140:[]:[]:[]" res19 == "ok-3:141:textarg9:141:[16,32,64,128,256]:[]:[]" res20 == "ok-3:142:textarg10:142:[]:[]:[byteArg2]" res21 == "ok-3:143:textarg11:143:[16,32,64,128,256]:[]:[byteArg3]" res22 == "ok-3:144:textarg12:144:[]:[]:[]" res23 == "ok-3:145:textarg13:145:[16,32,64,128,256]:[запрос1,запрос2," & "запрос3]:[byteArg4]" res24 == "ok-3:146:textarg1:146:[]:[]:[]:text/text1,bodyArg1" res25 == "ok-3:147:textarg2:147:[]:[]:[]:text/text2,bodyArg2" res26 == "ok-3:148:textarg3:148:[16,32,64,128,256]:[]:[]:text/text3," & "bodyArg3" res27 == "ok-3:149:textarg4:149:[]:[]:[]:text/text4,bodyArg4" res28 == "ok-3:150:textarg5:150:[]:[запрос1,запрос2,запрос3]:[]:" & "text/text5,bodyArg5" res29 == "ok-3:151:textarg6:151:[]:[]:[]:text/text6,bodyArg6" res30 == "ok-3:152:textarg7:152:[]:[]:[byteArg1]:text/text7,bodyArg7" res31 == "ok-3:153:textarg8:153:[]:[]:[]:text/text8,bodyArg8" res32 == "ok-3:154:textarg9:154:[16,32,64,128,256]:[]:[]:text/text9," & "bodyArg9" res33 == "ok-3:155:textarg10:155:[]:[]:[byteArg2]:text/text10,bodyArg10" res34 == "ok-3:156:textarg11:156:[16,32,64,128,256]:[]:[byteArg3]:" & "text/text11,bodyArg11" res35 == "ok-3:157:textarg12:157:[]:[]:[]:text/text12,bodyArg12" res36 == "ok-3:158:textarg13:158:[16,32,64,128,256]:[запрос1,запрос2," & "запрос3]:[byteArg4]:text/text13,bodyArg13" res37 == "ok-redirect-159:[]" res38 == "ok-redirect-160:[]" res39 == "ok-redirect-161:[16,32,64,128,256]" res40 == "ok-redirect-162:[]:text/text,bodyArg14" res41 == "ok-redirect-163:[]:text/text,bodyArg15" res42 == "ok-redirect-164:[256,512,1024,2048]:text/text,bodyArg16" await client1.closeWait() await client2.closeWait() await server.stop() await server.closeWait() asyncTest "RestStatus/PlainResponse/Response[T] test": var router = RestRouter.init(testValidate) router.api(MethodGet, "/test/error/410") do () -> RestApiResponse: return RestApiResponse.error(Http410, "ERROR-410") router.api(MethodGet, "/test/error/411") do () -> RestApiResponse: return RestApiResponse.error(Http411, "ERROR-411") router.api(MethodGet, "/test/success/200") do () -> RestApiResponse: return RestApiResponse.response("SUCCESS-200", Http200, "text/text") router.api(MethodGet, "/test/success/204") do () -> RestApiResponse: return RestApiResponse.response("204", Http204, "text/integer") var sres = RestServerRef.new(router, serverAddress) let server = sres.get() server.start() proc testStatus1(): RestStatus {.rest, endpoint: "/test/error/410".} proc testStatus2(): RestStatus {.rest, endpoint: "/test/error/411".} proc testStatus3(): RestStatus {.rest, endpoint: "/test/success/200".} proc testStatus4(): RestStatus {.rest, endpoint: "/test/success/204".} proc testStatus5(): RestStatus {.rest, endpoint: "/test/noresource".} proc testPlainResponse1(): RestPlainResponse {. rest, endpoint: "/test/error/410".} proc testPlainResponse2(): RestPlainResponse {. rest, endpoint: "/test/error/411".} proc testPlainResponse3(): RestPlainResponse {. rest, endpoint: "/test/success/200".} proc testPlainResponse4(): RestPlainResponse {. rest, endpoint: "/test/success/204".} proc testPlainResponse5(): RestPlainResponse {.rest, endpoint: "/test/noresource".} proc testGenericResponse1(): RestResponse[string] {. rest, endpoint: "/test/error/410".} proc testGenericResponse2(): RestResponse[string] {. rest, endpoint: "/test/error/411".} proc testGenericResponse3(): RestResponse[string] {. rest, endpoint: "/test/success/200".} proc testGenericResponse4(): RestResponse[int] {. rest, endpoint: "/test/success/204".} proc testGenericResponse5(): RestResponse[string] {. rest, endpoint: "/test/noresource".} var client = RestClientRef.new(serverAddress, HttpClientScheme.NonSecure) let res1 = await client.testStatus1() let res2 = await client.testStatus2() let res3 = await client.testStatus3() let res4 = await client.testStatus4() let res5 = await client.testStatus5() check: res1 == RestStatus(410) res2 == RestStatus(411) res3 == RestStatus(200) res4 == RestStatus(204) res5 == RestStatus(404) let res6 = await client.testPlainResponse1() let res7 = await client.testPlainResponse2() let res8 = await client.testPlainResponse3() let res9 = await client.testPlainResponse4() let res10 = await client.testPlainResponse5() check: res6.status == 410 res6.contentType == "text/html" bytesToString(res6.data) == "ERROR-410" res7.status == 411 res7.contentType == "text/html" bytesToString(res7.data) == "ERROR-411" res8.status == 200 res8.contentType == "text/text" bytesToString(res8.data) == "SUCCESS-200" res9.status == 204 res9.contentType == "text/integer" bytesToString(res9.data) == "204" res10.status == 404 let res11 = await client.testGenericResponse1() let res12 = await client.testGenericResponse2() let res13 = await client.testGenericResponse3() let res14 = await client.testGenericResponse4() let res15 = await client.testGenericResponse5() check: res11.status == 410 res11.contentType == "text/html" res11.data == "ERROR-410" res12.status == 411 res12.contentType == "text/html" res12.data == "ERROR-411" res13.status == 200 res13.contentType == "text/text" res13.data == "SUCCESS-200" res14.status == 204 res14.contentType == "text/integer" res14.data == 204 res15.status == 404 await client.closeWait() await server.stop() await server.closeWait() asyncTest "Accept test": var router = RestRouter.init(testValidate) router.api(MethodPost, "/test/accept") do ( contentBody: Option[ContentBody]) -> RestApiResponse: let obody = if contentBody.isSome(): let b = contentBody.get() b.contentType & "," & bytesToString(b.data) else: "nobody" let preferred = preferredContentType("app/type1", "app/type2") return if preferred.isOk(): case preferred.get() of "app/type1": RestApiResponse.response("type1[" & obody & "]") of "app/type2": RestApiResponse.response("type2[" & obody & "]") else: # This MUST not be happened. RestApiResponse.error(Http407, "") else: RestApiResponse.error(Http406, "") var sres = RestServerRef.new(router, serverAddress) let server = sres.get() server.start() proc testAccept1(body: string): RestPlainResponse {. rest, endpoint: "/test/accept", meth: MethodPost, accept: "*/*".} proc testAccept2(body: string): RestPlainResponse {. rest, endpoint: "/test/accept", meth: MethodPost, accept: "app/type1,app/type2".} proc testAccept3(body: string): RestPlainResponse {. rest, endpoint: "/test/accept", meth: MethodPost, accept: "app/type2".} proc testAccept4(body: string): RestPlainResponse {. rest, endpoint: "/test/accept", meth: MethodPost, accept: "app/type2;q=0.5,app/type1;q=0.7".} proc testAccept5(body: string): RestPlainResponse {. rest, endpoint: "/test/accept", meth: MethodPost, accept: "app/type2".} proc testAccept6(body: string): RestPlainResponse {. rest, endpoint: "/test/accept", meth: MethodPost.} var client = RestClientRef.new(serverAddress, HttpClientScheme.NonSecure) let res1 = await client.testAccept1("accept1") let res2 = await client.testAccept2("accept2") let res3 = await client.testAccept3("accept3") let res4 = await client.testAccept4("accept4") let res5 = await client.testAccept5("accept5") # This procedure is missing `accept` pragma in definition, so default # accept will be used `application/json`. let res6 = await client.testAccept6("accept6") let res7 = await client.testAccept6("accept7", restAcceptType = "app/type1;q=1.0,app/type2;q=0.1") let res8 = await client.testAccept6("accept8", restAcceptType = "") check: res1.status == 200 res2.status == 200 res3.status == 200 res4.status == 200 res5.status == 200 res6.status == 406 res7.status == 200 res8.status == 200 res1.data.bytesToString() == "type1[application/json,accept1]" res2.data.bytesToString() == "type1[application/json,accept2]" res3.data.bytesToString() == "type2[application/json,accept3]" res4.data.bytesToString() == "type1[application/json,accept4]" res5.data.bytesToString() == "type2[application/json,accept5]" res7.data.bytesToString() == "type1[application/json,accept7]" res8.data.bytesToString() == "type1[application/json,accept8]" await client.closeWait() await server.stop() await server.closeWait() test "Leaks test": proc getTrackerLeaks(tracker: string): bool = let tracker = getTracker(tracker) if isNil(tracker): false else: tracker.isLeaked() check: getTrackerLeaks("http.body.reader") == false getTrackerLeaks("http.body.writer") == false getTrackerLeaks("httpclient.connection") == false getTrackerLeaks("httpclient.request") == false getTrackerLeaks("httpclient.response") == false getTrackerLeaks("async.stream.reader") == false getTrackerLeaks("async.stream.writer") == false getTrackerLeaks("stream.server") == false getTrackerLeaks("stream.transport") == false