Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

updated readme, libcurl tweaks #114

Merged
merged 1 commit into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 39 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,70 @@

`nimble install puppy`

![Github Actions](https://github.com/treeform/puppy/workflows/Github%20Actions/badge.svg)
![Github Actions](https://github.com/treeform/puppy/actions/workflows/build.yml/badge.svg)

[API reference](https://treeform.github.io/puppy)

## About

Puppy does not use Nim's HTTP stack, instead it uses `WinHttp` API on Windows , `AppKit` on macOS, and `libcurl` on Linux. Because Puppy uses system APIs, there is no need to ship extra `*.dll`s, `cacert.pem`, or forget to pass the `-d:ssl` flag. This also has the effect of producing slightly smaller binaires.
Puppy makes HTTP requests easy!

Furthermore, Puppy supports gzip transparently right out of the box.
With Puppy you can make HTTP requests without needing to pass the `-d:ssl` flag or shipping extra `*.dll`s and `cacerts.pem` on Windows. Puppy avoids these gotchas by using system APIs instead of Nim's HTTP stack.

Some other highlights of Puppy are:

* Supports gzip'ed responses out of the box
* Make an HTTP request using a one-line `proc` call

OS | Method
----- | ---------------------------
Win32 | WinHttp WinHttpRequest
macOS | AppKit NSMutableURLRequest
linux | libcurl easy_perform
Linux | libcurl easy_perform

*Curently does not support async*

```nim
import puppy
## Easy mode

```nim
echo fetch("http://neverssl.com/")
```

Will raise `PuppyError` if the response status code is not `200`.
A call to `fetch` will raise PuppyError if the response status code is not 200.

## More request types

Make a basic GET request:

```nim
import puppy

let response = get("https://www.google.com/")
```

Need to pass headers?

```nim
import puppy

echo fetch(
let response = get(
"http://neverssl.com/",
headers = @[("User-Agent", "Nim 1.0")]
)
```

Need a more complex API?
* verbs: GET, POST, PUT, UPDATE, DELETE..
* headers: User-Agent, Content-Type..
* response code: 200, 404, 500..
* response headers: Content-Type..
Easy one-line procs for your favorite verbs:

```nim
discard get(url, headers)
discard post(url, headers, body)
discard put(url, headers, body)
discard patch(url, headers, body)
discard delete(url, headers)
discard head(url, headers)
```

Use these instead.
## Working with responses

```nim
Response* = ref object
Expand All @@ -56,8 +76,6 @@ Response* = ref object
body*: string
```

Usage examples:

```nim
import puppy

Expand All @@ -82,7 +100,7 @@ echo response.headers
echo response.body.len
```

## Examples
## More examples

Using multipart/form-data:

Expand All @@ -109,6 +127,8 @@ let response = post("Your API endpoint here", headers, body)

See the [examples/](https://github.com/treeform/puppy) folder for more examples.

## Always use Libcurl
## Always use libcurl

You can pass `-d:puppyLibcurl` to force use of `libcurl` even on Windows and macOS. This is useful if for some reason the native OS API is not working.

You can pass `-d:puppyLibcurl` to force use of `libcurl` even on windows and macOS. This is useful to debug, if the some reason native OS API does not work. Libcurl is usually installed on macOS but requires a `curl.dll` on windows.
Libcurl is typically ready-to-use on macOS and Linux. On Windows you'll need to grab the latest libcurl DLL from https://curl.se/windows/, rename it to libcurl.dll, and put it in the same directory as your executable.
38 changes: 19 additions & 19 deletions src/puppy/platforms/linux/platform.nim
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,26 @@ type StringWrap = object
## some sort of wrapper to be passed to C.
str: string

{.push stackTrace: off.}

proc curlWriteFn(
buffer: cstring,
size: int,
count: int,
outstream: pointer
): int {.cdecl.} =
let
outbuf = cast[ptr StringWrap](outstream)
i = outbuf.str.len
outbuf.str.setLen(outbuf.str.len + count)
copyMem(outbuf.str[i].addr, buffer, count)
result = size * count

{.pop.}

proc internalFetch*(req: Request): Response {.raises: [PuppyError].} =
result = Response()

{.push stackTrace: off.}

proc curlWriteFn(
buffer: cstring,
size: int,
count: int,
outstream: pointer
): int {.cdecl.} =
let
outbuf = cast[ptr StringWrap](outstream)
i = outbuf.str.len
outbuf.str.setLen(outbuf.str.len + count)
copyMem(outbuf.str[i].addr, buffer, count)
result = size * count

{.pop.}

var strings: seq[string]
strings.add $req.url
strings.add req.verb.toUpperAscii()
Expand Down Expand Up @@ -65,9 +65,9 @@ proc internalFetch*(req: Request): Response {.raises: [PuppyError].} =

discard curl.easy_setopt(OPT_HTTPHEADER, headerList)

if req.verb.toUpperAscii() == "HEAD":
if cmpIgnoreCase(req.verb, "HEAD") == 0:
discard curl.easy_setopt(OPT_NOBODY, 1)
elif req.verb.toUpperAscii() == "POST" or req.body.len > 0:
elif cmpIgnoreCase(req.verb, "POST") == 0 or req.body.len > 0:
discard curl.easy_setopt(OPT_POSTFIELDSIZE, req.body.len)
discard curl.easy_setopt(OPT_POSTFIELDS, req.body.cstring)

Expand Down
Loading