Add support for passing extra headers in HTTP requests

This commit is contained in:
Zahary Karadjov 2021-12-21 18:10:17 +02:00 committed by zah
parent de7f923c6b
commit fba35d5a67
2 changed files with 52 additions and 16 deletions

View File

@ -54,6 +54,7 @@ const
RestContentTypeArg = "restContentType" RestContentTypeArg = "restContentType"
RestAcceptTypeArg = "restAcceptType" RestAcceptTypeArg = "restAcceptType"
RestClientArg = "restClient" RestClientArg = "restClient"
ExtraHeadersArg = "extraHeaders"
NotAllowedArgumentNames = [RestClientArg, RestContentTypeArg, NotAllowedArgumentNames = [RestClientArg, RestContentTypeArg,
RestAcceptTypeArg] RestAcceptTypeArg]
@ -119,30 +120,35 @@ proc closeWait*(client: RestClientRef) {.async.} =
proc createPostRequest*(client: RestClientRef, path: string, query: string, proc createPostRequest*(client: RestClientRef, path: string, query: string,
contentType: string, acceptType: string, contentType: string, acceptType: string,
extraHeaders: openArray[HttpHeaderTuple],
meth: HttpMethod, meth: HttpMethod,
contentLength: uint64): HttpClientRequestRef = contentLength: uint64): HttpClientRequestRef =
var address = client.address var address = client.address
address.path = path address.path = path
address.query = query address.query = query
let headers =
[ var headers = newSeqOfCap[HttpHeaderTuple](4 + extraHeaders.len)
("content-type", contentType), headers.add(("content-type", contentType))
("content-length", Base10.toString(contentLength)), headers.add(("content-length", Base10.toString(contentLength)))
("accept", acceptType), headers.add(("accept", acceptType))
("user-agent", client.agent) headers.add(("user-agent", client.agent))
] headers.add extraHeaders
HttpClientRequestRef.new(client.session, address, meth, headers = headers) HttpClientRequestRef.new(client.session, address, meth, headers = headers)
proc createGetRequest*(client: RestClientRef, path: string, query: string, proc createGetRequest*(client: RestClientRef, path: string, query: string,
contentType: string, acceptType: string, contentType: string, acceptType: string,
extraHeaders: openArray[HttpHeaderTuple],
meth: HttpMethod): HttpClientRequestRef = meth: HttpMethod): HttpClientRequestRef =
var address = client.address var address = client.address
address.path = path address.path = path
address.query = query address.query = query
let headers = [
("accept", acceptType), var headers = newSeqOfCap[HttpHeaderTuple](2 + extraHeaders.len)
("user-agent", client.agent) headers.add(("accept", acceptType))
] headers.add(("user-agent", client.agent))
headers.add extraHeaders
HttpClientRequestRef.new(client.session, address, meth, headers = headers) HttpClientRequestRef.new(client.session, address, meth, headers = headers)
proc getEndpointOrDefault(prc: NimNode, proc getEndpointOrDefault(prc: NimNode,
@ -269,6 +275,7 @@ proc isPostMethod(node: NimNode): bool {.compileTime.} =
proc transformProcDefinition(prc: NimNode, clientIdent: NimNode, proc transformProcDefinition(prc: NimNode, clientIdent: NimNode,
contentIdent: NimNode, contentIdent: NimNode,
acceptIdent: NimNode, acceptIdent: NimNode,
extraHeadersIdent: NimNode,
acceptValue: NimNode, acceptValue: NimNode,
stmtList: NimNode): NimNode {.compileTime.} = stmtList: NimNode): NimNode {.compileTime.} =
var procdef = copyNimTree(prc) var procdef = copyNimTree(prc)
@ -280,6 +287,10 @@ proc transformProcDefinition(prc: NimNode, clientIdent: NimNode,
let contentTypeArg = let contentTypeArg =
newTree(nnkIdentDefs, contentIdent, newIdentNode("string"), newTree(nnkIdentDefs, contentIdent, newIdentNode("string"),
newStrLitNode("application/json")) newStrLitNode("application/json"))
let extraHeadersArg =
newTree(nnkIdentDefs, extraHeadersIdent,
newTree(nnkBracketExpr, ident"seq", ident"HttpHeaderTuple"),
newTree(nnkPrefix, ident"@", newTree(nnkBracket)))
let acceptTypeArg = let acceptTypeArg =
newTree(nnkIdentDefs, acceptIdent, newIdentNode("string"), newTree(nnkIdentDefs, acceptIdent, newIdentNode("string"),
acceptValue) acceptValue)
@ -308,6 +319,7 @@ proc transformProcDefinition(prc: NimNode, clientIdent: NimNode,
res.insert(clientArg, 1) res.insert(clientArg, 1)
res.add(contentTypeArg) res.add(contentTypeArg)
res.add(acceptTypeArg) res.add(acceptTypeArg)
res.add(extraHeadersArg)
res res
var newPragmas = var newPragmas =
@ -597,6 +609,7 @@ proc restSingleProc(prc: NimNode): NimNode {.compileTime.} =
clientIdent = newIdentNode(RestClientArg) clientIdent = newIdentNode(RestClientArg)
contentTypeIdent = newIdentNode(RestContentTypeArg) contentTypeIdent = newIdentNode(RestContentTypeArg)
acceptTypeIdent = newIdentNode(RestAcceptTypeArg) acceptTypeIdent = newIdentNode(RestAcceptTypeArg)
extraHeadersIdent = newIdentNode(ExtraHeadersArg)
var statements = newStmtList() var statements = newStmtList()
@ -614,7 +627,7 @@ proc restSingleProc(prc: NimNode): NimNode {.compileTime.} =
block: block:
parameters.expectMinLen(1) parameters.expectMinLen(1)
if parameters[0].kind == nnkEmpty: if parameters[0].kind == nnkEmpty:
error("REST procedure should no\\\ave empty return value", parameters) error("REST procedure should non have empty return value", parameters)
let node = copyNimTree(parameters[0]) let node = copyNimTree(parameters[0])
case node.kind case node.kind
of nnkIdent: of nnkIdent:
@ -848,7 +861,8 @@ proc restSingleProc(prc: NimNode): NimNode {.compileTime.} =
let chunkSize = `clientIdent`.session.connectionBufferSize let chunkSize = `clientIdent`.session.connectionBufferSize
let `requestIdent` = createPostRequest( let `requestIdent` = createPostRequest(
`clientIdent`, `requestPath`, `requestQuery`, `clientIdent`, `requestPath`, `requestQuery`,
`contentTypeIdent`, `acceptTypeIdent`, `meth`, `contentTypeIdent`, `acceptTypeIdent`,
`extraHeadersIdent`, `meth`,
uint64(len(`bodyIdent`)) uint64(len(`bodyIdent`))
) )
await requestWithBody(`requestIdent`, await requestWithBody(`requestIdent`,
@ -861,7 +875,8 @@ proc restSingleProc(prc: NimNode): NimNode {.compileTime.} =
block: block:
let `requestIdent` = createGetRequest( let `requestIdent` = createGetRequest(
`clientIdent`, `requestPath`, `requestQuery`, `clientIdent`, `requestPath`, `requestQuery`,
`contentTypeIdent`, `acceptTypeIdent`, `meth` `contentTypeIdent`, `acceptTypeIdent`,
`extraHeadersIdent`, `meth`
) )
await requestWithoutBody(`requestIdent`, `requestFlagsIdent`) await requestWithoutBody(`requestIdent`, `requestFlagsIdent`)
@ -906,8 +921,8 @@ proc restSingleProc(prc: NimNode): NimNode {.compileTime.} =
return `responseResultIdent` return `responseResultIdent`
let res = transformProcDefinition(prc, clientIdent, contentTypeIdent, let res = transformProcDefinition(prc, clientIdent, contentTypeIdent,
acceptTypeIdent, newStrLitNode(accept), acceptTypeIdent, extraHeadersIdent,
statements) newStrLitNode(accept), statements)
res res
macro rest*(prc: untyped): untyped = macro rest*(prc: untyped): untyped =

View File

@ -57,6 +57,12 @@ suite "REST API client test suite":
"nobody" "nobody"
return RestApiResponse.response(obody) return RestApiResponse.response(obody)
router.api(MethodGet, "/test/echo-authorization") do () -> RestApiResponse:
return RestApiResponse.response(request.headers.getString("Authorization"))
router.api(MethodPost, "/test/echo-authorization") do () -> RestApiResponse:
return RestApiResponse.response(request.headers.getString("Authorization"))
let serverFlags = {HttpServerFlags.NotifyDisconnect, let serverFlags = {HttpServerFlags.NotifyDisconnect,
HttpServerFlags.QueryCommaSeparatedArray} HttpServerFlags.QueryCommaSeparatedArray}
var sres = RestServerRef.new(router, serverAddress, var sres = RestServerRef.new(router, serverAddress,
@ -75,6 +81,12 @@ suite "REST API client test suite":
proc testSimple6(body: string): string {.rest, endpoint: "/test/simple/6", proc testSimple6(body: string): string {.rest, endpoint: "/test/simple/6",
meth: HttpMethod.MethodPost.} meth: HttpMethod.MethodPost.}
proc testEchoAuthorizationPost(body: string): string
{.rest, endpoint: "/test/echo-authorization", meth: HttpMethod.MethodPost.}
proc testEchoAuthorizationGet(): string
{.rest, endpoint: "/test/echo-authorization", meth: HttpMethod.MethodGet.}
var client = RestClientRef.new(serverAddress, HttpClientScheme.NonSecure) var client = RestClientRef.new(serverAddress, HttpClientScheme.NonSecure)
let res1 = await client.testSimple1() let res1 = await client.testSimple1()
let res2 = await client.testSimple2("ok-2", restContentType = "text/text") let res2 = await client.testSimple2("ok-2", restContentType = "text/text")
@ -117,6 +129,15 @@ suite "REST API client test suite":
message == "Different error" message == "Different error"
contentType == "application/error" contentType == "application/error"
block:
let postRes = await client.testEchoAuthorizationPost(
body = "{}",
extraHeaders = @[("Authorization", "Bearer XXX")])
check postRes == "Bearer XXX"
let getRes = await client.testEchoAuthorizationGet(extraHeaders = @[("Authorization", "Bearer XYZ")])
check getRes == "Bearer XYZ"
await client.closeWait() await client.closeWait()
await server.stop() await server.stop()
await server.closeWait() await server.closeWait()