Skip to content

Commit

Permalink
Merge pull request #90 from treeform/guzba
Browse files Browse the repository at this point in the history
use webby
  • Loading branch information
treeform authored Dec 17, 2022
2 parents b1388b9 + 756c065 commit 9e58ce6
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 70 deletions.
43 changes: 23 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,37 +46,40 @@ Need a more complex API?
* headers: User-Agent, Content-Type..
* response code: 200, 404, 500..
* response headers: Content-Type..
* error: timeout, DNS fail ...

Use request/response instead.
Use these instead.

```nim
Request* = ref object
url*: Url
headers*: seq[Header]
timeout*: float32
verb*: string
body*: string
Response* = ref object
url*: Url
headers*: seq[Header]
headers*: HttpHeaders
code*: int
body*: string
```

Usage example:
Usage examples:

```nim
import puppy
let response = get("http://www.istrolid.com", @[("Auth", "1")])
echo response.code
echo response.headers
echo response.body.len
```

```nim
let req = Request(
url: parseUrl("http://www.istrolid.com"),
verb: "get",
headers: @[Header(key: "Auth", value: "1")]
import puppy
let body = "{\"json\":true}"
let response = post(
"http://api.website.com",
@[("Content-Type", "application/json")],
body
)
let res = fetch(req)
echo res.code
echo res.headers
echo res.body.len
echo response.code
echo response.headers
echo response.body.len
```

## Always use Libcurl
Expand Down
4 changes: 2 additions & 2 deletions puppy.nimble
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
version = "1.6.2"
version = "2.0.0"
author = "Andre von Houck"
description = "Puppy fetches resources via HTTP and HTTPS."
license = "MIT"

srcDir = "src"

requires "nim >= 1.2.2"
requires "urlly >= 1.1.0"
requires "libcurl >= 1.0.0"
requires "zippy >= 0.10.0"
requires "webby >= 0.1.3"
60 changes: 53 additions & 7 deletions src/puppy.nim
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import puppy/common, urlly
import puppy/common

when defined(windows) and not defined(puppyLibcurl):
# WinHTTP Windows
Expand All @@ -10,7 +10,7 @@ else:
# LIBCURL Linux
import puppy/platforms/linux/platform

export common, urlly
export common

proc addDefaultHeaders(req: Request) =
if req.headers["user-agent"] == "":
Expand All @@ -35,7 +35,7 @@ proc fetch*(req: Request): Response {.raises: [PuppyError].} =
proc newRequest*(
url: string,
verb = "get",
headers = newSeq[Header](),
headers = emptyHttpHeaders(),
timeout: float32 = 60
): Request =
## Allocates a new request object with defaults.
Expand All @@ -45,10 +45,56 @@ proc newRequest*(
result.headers = headers
result.timeout = timeout

proc fetch*(url: string, headers = newSeq[Header]()): string =
let
req = newRequest(url, "get", headers)
res = req.fetch()
proc get*(
url: string,
headers = emptyHttpHeaders(),
timeout: float32 = 60
): Response =
fetch(newRequest(url, "GET", headers, timeout))

proc post*(
url: string,
headers = emptyHttpHeaders(),
body: sink string = "",
timeout: float32 = 60
): Response =
let request = newRequest(url, "POST", headers, timeout)
request.body = move body
fetch(request)

proc put*(
url: string,
headers = emptyHttpHeaders(),
body: sink string = "",
timeout: float32 = 60
): Response =
let request = newRequest(url, "PUT", headers, timeout)
request.body = move body
fetch(request)

proc patch*(
url: string,
headers = emptyHttpHeaders(),
body: sink string = "",
timeout: float32 = 60
): Response =
let request = newRequest(url, "PATCH", headers, timeout)
request.body = move body
fetch(request)

proc delete*(
url: string,
headers = emptyHttpHeaders(),
timeout: float32 = 60
): Response =
fetch(newRequest(url, "DELETE", headers, timeout))

proc fetch*(url: string, headers = emptyHttpHeaders()): string =
## Simple fetch that directly returns the GET response body.
## Raises an exception if anything goes wrong or if the response code
## is not 200. See get, post, put etc for similar calls that return
## a response object.
let res = get(url, headers)
if res.code == 200:
return res.body
raise newException(PuppyError,
Expand Down
36 changes: 13 additions & 23 deletions src/puppy/common.nim
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import std/strutils, urlly
import std/strutils, webby

export urlly
export webby

const CRLF* = "\r\n"

type
Header* = object
key*: string
value*: string

Request* = ref object
url*: Url
headers*: seq[Header]
headers*: HttpHeaders
timeout*: float32
verb*: string
body*: string
Expand All @@ -20,27 +16,21 @@ type
allowAnyHttpsCertificate*: bool

Response* = ref object
headers*: seq[Header]
headers*: HttpHeaders
code*: int
body*: string

PuppyError* = object of IOError ## Raised if an operation fails.

proc `[]`*(headers: seq[Header], key: string): string =
## Get a key out of headers. Not case sensitive.
## Use a for loop to get multiple keys.
for header in headers:
if cmpIgnorecase(header.key, key) == 0:
return header.value

proc `[]=`*(headers: var seq[Header], key, value: string) =
## Sets a key in the headers. Not case sensitive.
## If key is not there appends a new key-value pair at the end.
for header in headers.mitems:
if cmpIgnorecase(header.key, key) == 0:
header.value = value
return
headers.add(Header(key: key, value: value))
Header* = object
key*: string
value*: string

proc `$`*(req: Request): string =
req.verb.toUpperAscii & " " & $req.url

converter toWebby*(headers: seq[Header]): HttpHeaders =
cast[HttpHeaders](headers)

converter toWebby*(header: Header): (string, string) =
(header.key, header.value)
6 changes: 3 additions & 3 deletions src/puppy/platforms/linux/platform.nim
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ proc fetch*(req: Request): Response {.raises: [PuppyError].} =
var strings: seq[string]
strings.add $req.url
strings.add req.verb.toUpperAscii()
for header in req.headers:
strings.add header.key & ": " & header.value
for (k, v) in req.headers:
strings.add k & ": " & v

let curl = easy_init()

Expand Down Expand Up @@ -89,7 +89,7 @@ proc fetch*(req: Request): Response {.raises: [PuppyError].} =
for headerLine in headerData.split(CRLF):
let arr = headerLine.split(":", 1)
if arr.len == 2:
result.headers.add(Header(key: arr[0].strip(), value: arr[1].strip()))
result.headers.add((arr[0].strip(), arr[1].strip()))
result.body = bodyWrap.str
if result.headers["Content-Encoding"] == "gzip":
try:
Expand Down
6 changes: 3 additions & 3 deletions src/puppy/platforms/macos/platform.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ proc fetch*(req: Request): Response {.raises: [PuppyError].} =

request.setHTTPMethod(@(req.verb.toUpperAscii()))

for header in req.headers:
request.setValue(@(header.value), @(header.key))
for (k, v) in req.headers:
request.setValue(@(v), @(k))

if req.body.len > 0:
request.setHTTPBody(NSData.dataWithBytes(req.body[0].addr, req.body.len))
Expand All @@ -38,7 +38,7 @@ proc fetch*(req: Request): Response {.raises: [PuppyError].} =
if key.int == 0:
break
let value = dictionary.objectForKey(key)
result.headers[$(key.NSString)] = $(value.NSString)
result.headers.add(($(key.NSString), $(value.NSString)))

if data.length > 0:
result.body.setLen(data.length)
Expand Down
10 changes: 5 additions & 5 deletions src/puppy/platforms/win32/platform.nim
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ proc fetch*(req: Request): Response {.raises: [PuppyError].} =
)

var requestHeaderBuf: string
for header in req.headers:
requestHeaderBuf &= header.key & ": " & header.value & CRLF
for (k, v) in req.headers:
requestHeaderBuf &= k & ": " & v & CRLF

let wideRequestHeaderBuf = requestHeaderBuf.wstr()

Expand Down Expand Up @@ -226,9 +226,9 @@ proc fetch*(req: Request): Response {.raises: [PuppyError].} =
if line != "":
let parts = line.split(":", 1)
if parts.len == 2:
result.headers.add(Header(
key: parts[0].strip(),
value: parts[1].strip()
result.headers.add((
parts[0].strip(),
parts[1].strip()
))

var i: int
Expand Down
16 changes: 9 additions & 7 deletions tests/test.nim
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ block:
doAssert res.headers.len > 0
doAssert res.body != ""

block:
discard fetch(Request(
url: parseUrl("https://www.google.com"),
verb: "get",
headers: @[Header(key: "User-Agent", value: "Puppy")]
)
)

when defined(windows):
block:
let httpsServer = startProcess(
Expand Down Expand Up @@ -153,13 +161,7 @@ try:

block:
# test empty post
let req = Request(
url: parseUrl("http://localhost:8080/post"),
verb: "post",
body: ""
)
let res = fetch(req)
doAssert ($req).startsWith("POST http://localhost:8080/post")
let res = post("http://localhost:8080/post")
doAssert res.code == 200
doAssert res.body == ""

Expand Down

0 comments on commit 9e58ce6

Please sign in to comment.