diff --git a/README.md b/README.md index 477134d..989282c 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ All procedures above return `Response` object with fields: - `request` - object with request data processed by `yahttp` - `url` - stores full url with query params - `headers` - stores HTTP headers with `Authorization` for basic authorization + - `httpMethod` - HTTP method `Response` object has some helper procedures: - `Response.json()` - returns response body as JSON diff --git a/examples/examples.nim b/examples/examples.nim index 424b506..7ca77bc 100644 --- a/examples/examples.nim +++ b/examples/examples.nim @@ -13,7 +13,7 @@ for catTag in catTags[0..4]: echo "Working with tag " & tag let catData = get("https://cataas.com/api/cats", query = {"tags": tag, "limit": "10"}) - echo "Request URL: ", catData.request.url + echo "Request method and URL: ", catData.request.httpMethod, " ", catData.request.url echo "Response status: ", catData.status echo "Response headers: ", catData.headers echo "Response body: ", catData.body diff --git a/src/yahttp.nim b/src/yahttp.nim index 28e7c64..cb949ad 100644 --- a/src/yahttp.nim +++ b/src/yahttp.nim @@ -1,5 +1,7 @@ import base64, httpclient, net, json, uri, strutils, tables +import yahttp/internal/utils + type ## Types without methods QueryParam* = tuple[key: string, value: string] ## Type for URL query params @@ -16,7 +18,7 @@ type GET, PUT, POST, PATCH, DELETE, HEAD, OPTIONS -type +type BasicAuth* = tuple[login: string, password: string] ## Basic auth type proc basicAuthHeader(auth: BasicAuth): string = @@ -27,6 +29,7 @@ type ## Type to store request infornation in response url*: string headers*: seq[tuple[key: string, val: string]] + httpMethod*: Method Response* = object ## Type for HTTP response @@ -35,13 +38,14 @@ type headers*: TableRef[string, seq[string]] request*: Request -proc toResp(response: httpclient.Response, requestUrl: string, requestHeaders: seq[tuple[key: string, val: string]]): Response = +proc toResp(response: httpclient.Response, requestUrl: string, + requestHeaders: seq[tuple[key: string, val: string]], requestHttpMethod: Method): Response = ## Convert httpclient.Response to yahttp.Response return Response( status: parseInt(response.status.strip()[0..2]), headers: response.headers.table, body: response.body, - request: Request(url: requestUrl, headers: requestHeaders) + request: Request(url: requestUrl, headers: requestHeaders, httpMethod: requestHttpMethod) ) proc json*(response: Response): JsonNode = @@ -61,7 +65,9 @@ const defaultEncodeQueryParams = EncodeQueryParams(usePlus: false, omitEq: true, proc request*(url: string, httpMethod: Method = Method.GET, headers: openArray[ - RequestHeader] = [], query: openArray[QueryParam] = [], encodeQueryParams: EncodeQueryParams = defaultEncodeQueryParams, body: string = "", + RequestHeader] = [], query: openArray[QueryParam] = [], + encodeQueryParams: EncodeQueryParams = defaultEncodeQueryParams, + body: string = "", auth: BasicAuth = ("", ""), ignoreSsl = false): Response = ## Genreal proc to make HTTP request with every HTTP method @@ -87,7 +93,9 @@ proc request*(url: string, httpMethod: Method = Method.GET, headers: openArray[ # Prepare url - let innerUrl = if query.len() > 0: url & "?" & encodeQuery(query, usePlus = encodeQueryParams.usePlus, omitEq = encodeQueryParams.omitEq, sep = encodeQueryParams.sep) else: url + let innerUrl = if query.len() > 0: url & "?" & encodeQuery(query, + usePlus = encodeQueryParams.usePlus, omitEq = encodeQueryParams.omitEq, + sep = encodeQueryParams.sep) else: url # Prepare HTTP method @@ -105,94 +113,15 @@ proc request*(url: string, httpMethod: Method = Method.GET, headers: openArray[ let response = client.request(innerUrl, httpMethod = innerMethod, body = body) client.close() - return response.toResp(requestUrl = innerUrl, requestHeaders = innerHeaders) - - -# Deidcated procs for individual methods - -proc get*(url: string, headers: openArray[RequestHeader] = [], query: openArray[ - QueryParam] = [], encodeQueryParams: EncodeQueryParams = defaultEncodeQueryParams, auth: BasicAuth = ("", ""), ignoreSsl = false): Response = - return request( - url = url, - httpMethod = Method.GET, - headers = headers, - query = query, - auth = auth, - ignoreSsl = ignoreSsl - ) - -proc put*(url: string, headers: openArray[RequestHeader] = [], query: openArray[ - QueryParam] = [], encodeQueryParams: EncodeQueryParams = defaultEncodeQueryParams, body: string = "", auth: BasicAuth = ("", ""), - ignoreSsl = false): Response = - return request( - url = url, - httpMethod = Method.PUT, - headers = headers, - query = query, - body = body, - auth = auth, - ignoreSsl = ignoreSsl - ) - -proc post*(url: string, headers: openArray[RequestHeader] = [], query: openArray[ - QueryParam] = [], encodeQueryParams: EncodeQueryParams = defaultEncodeQueryParams, body: string = "", auth: BasicAuth = ("", ""), - ignoreSsl = false): Response = - return request( - url = url, - httpMethod = Method.POST, - headers = headers, - query = query, - body = body, - auth = auth, - ignoreSsl = ignoreSsl - ) + return response.toResp(requestUrl = innerUrl, requestHeaders = innerHeaders, requestHttpMethod = httpMethod) -proc patch*(url: string, headers: openArray[RequestHeader] = [], - query: openArray[QueryParam] = [], encodeQueryParams: EncodeQueryParams = defaultEncodeQueryParams, body: string = "", - auth: BasicAuth = ("", ""), ignoreSsl = false): Response = - return request( - url = url, - httpMethod = Method.PATCH, - headers = headers, - query = query, - body = body, - auth = auth, - ignoreSsl = ignoreSsl - ) +# Gnerating procs for individual HTTP methods -proc delete*(url: string, headers: openArray[RequestHeader] = [], - query: openArray[QueryParam] = [], encodeQueryParams: EncodeQueryParams = defaultEncodeQueryParams, body: string = "", - auth: BasicAuth = ("", ""), ignoreSsl = false): Response = - return request( - url = url, - httpMethod = Method.DELETE, - headers = headers, - query = query, - body = body, - auth = auth, - ignoreSsl = ignoreSsl - ) - -proc head*(url: string, headers: openArray[RequestHeader] = [], query: openArray[ - QueryParam] = [], encodeQueryParams: EncodeQueryParams = defaultEncodeQueryParams, auth: BasicAuth = ("", ""), ignoreSsl = false): Response = - return request( - url = url, - httpMethod = Method.HEAD, - headers = headers, - query = query, - auth = auth, - ignoreSsl = ignoreSsl - ) - -proc options*(url: string, headers: openArray[RequestHeader] = [], - query: openArray[QueryParam] = [], encodeQueryParams: EncodeQueryParams = defaultEncodeQueryParams, auth: BasicAuth = ("", ""), - ignoreSsl = false): Response = - return request( - url = url, - httpMethod = Method.OPTIONS, - headers = headers, - query = query, - auth = auth, - ignoreSsl = ignoreSsl - ) +http_method_no_body_gen get +http_method_no_body_gen head +http_method_no_body_gen options +http_method_gen put +http_method_gen post +http_method_gen patch +http_method_gen delete diff --git a/src/yahttp/internal/utils.nim b/src/yahttp/internal/utils.nim new file mode 100644 index 0000000..7443400 --- /dev/null +++ b/src/yahttp/internal/utils.nim @@ -0,0 +1,38 @@ +import macros, strutils, strformat + +macro http_method_gen*(name: untyped): untyped = + let methodUpper = name.strVal().toUpper() + let methodName = newIdentNode(methodUpper) + let comment = newCommentStmtNode(fmt"Proc for {methodUpper} HTTP method") + quote do: + proc `name`*(url: string, headers: openArray[RequestHeader] = [], query: openArray[ + QueryParam] = [], encodeQueryParams: EncodeQueryParams = defaultEncodeQueryParams, body: string = "", auth: BasicAuth = ("", ""), + ignoreSsl = false): Response = + `comment` + return request( + url = url, + httpMethod = Method.`methodName`, + headers = headers, + query = query, + body = body, + auth = auth, + ignoreSsl = ignoreSsl + ) + + +macro http_method_no_body_gen*(name: untyped): untyped = + let methodUpper = name.strVal().toUpper() + let methodName = newIdentNode(methodUpper) + let comment = newCommentStmtNode(fmt"Proc for {methodUpper} HTTP method") + quote do: + proc `name`*(url: string, headers: openArray[RequestHeader] = [], query: openArray[ + QueryParam] = [], encodeQueryParams: EncodeQueryParams = defaultEncodeQueryParams, auth: BasicAuth = ("", ""), ignoreSsl = false): Response = + `comment` + return request( + url = url, + httpMethod = Method.`methodName`, + headers = headers, + query = query, + auth = auth, + ignoreSsl = ignoreSsl + )