Skip to content
Open
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
112 changes: 73 additions & 39 deletions lib/std/jsfetch.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,50 +8,54 @@ from std/httpcore import HttpMethod
from std/jsffi import JsObject

type
FetchOptions* = ref object of JsRoot ## Options for Fetch API.
FetchOptions* = ref object of JsRoot ## Options for Fetch API.
keepalive*: bool
metod* {.importjs: "method".}: cstring
body*, integrity*, referrer*, mode*, credentials*, cache*, redirect*, referrerPolicy*: cstring
body*, integrity*, referrer*, mode*, credentials*, cache*, redirect*,
referrerPolicy*: cstring
headers*: Headers

FetchModes* = enum ## Mode options.
FetchModes* = enum ## Mode options.
fmCors = "cors"
fmNoCors = "no-cors"
fmSameOrigin = "same-origin"

FetchCredentials* = enum ## Credential options. See https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials
FetchCredentials* = enum
## Credential options. See https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials
fcInclude = "include"
fcSameOrigin = "same-origin"
fcOmit = "omit"

FetchCaches* = enum ## https://developer.mozilla.org/docs/Web/API/Request/cache
FetchCaches* = enum ## https://developer.mozilla.org/docs/Web/API/Request/cache
fchDefault = "default"
fchNoStore = "no-store"
fchReload = "reload"
fchNoCache = "no-cache"
fchForceCache = "force-cache"

FetchRedirects* = enum ## Redirects options.
FetchRedirects* = enum ## Redirects options.
frFollow = "follow"
frError = "error"
frManual = "manual"

FetchReferrerPolicies* = enum ## Referrer Policy options.
FetchReferrerPolicies* = enum ## Referrer Policy options.
frpNoReferrer = "no-referrer"
frpNoReferrerWhenDowngrade = "no-referrer-when-downgrade"
frpOrigin = "origin"
frpOriginWhenCrossOrigin = "origin-when-cross-origin"
frpUnsafeUrl = "unsafe-url"

Response* = ref object of JsRoot ## https://developer.mozilla.org/en-US/docs/Web/API/Response
Response* = ref object of JsRoot
## https://developer.mozilla.org/en-US/docs/Web/API/Response
bodyUsed*, ok*, redirected*: bool
typ* {.importjs: "type".}: cstring
url*, statusText*: cstring
status*: cint
headers*: Headers
body*: cstring

Request* = ref object of JsRoot ## https://developer.mozilla.org/en-US/docs/Web/API/Request
Request* = ref object of JsRoot
## https://developer.mozilla.org/en-US/docs/Web/API/Request
bodyUsed*, ok*, redirected*: bool
typ* {.importjs: "type".}: cstring
url*, statusText*: cstring
Expand All @@ -65,7 +69,9 @@ func newResponse*(body: cstring | FormData): Response {.importjs: "(new Response
func newRequest*(url: cstring): Request {.importjs: "(new Request(#))".}
## Constructor for `Request`. This does *not* call `fetch()`. Same as `new Request()`.

func newRequest*(url: cstring; fetchOptions: FetchOptions): Request {.importjs: "(new Request(#, #))".}
func newRequest*(
url: cstring, fetchOptions: FetchOptions
): Request {.importjs: "(new Request(#, #))".}
## Constructor for `Request` with `fetchOptions`. Same as `fetch(url, fetchOptions)`.

func clone*(self: Response | Request): Response {.importjs: "#.$1()".}
Expand All @@ -80,41 +86,69 @@ proc json*(self: Response): Future[JsObject] {.importjs: "#.$1()".}
proc formData*(self: Response): Future[FormData] {.importjs: "#.$1()".}
## https://developer.mozilla.org/en-US/docs/Web/API/Response/formData

proc unsafeNewFetchOptions*(metod, body, mode, credentials, cache, referrerPolicy: cstring;
keepalive: bool; redirect = "follow".cstring; referrer = "client".cstring; integrity = "".cstring; headers: Headers = newHeaders()): FetchOptions {.importjs:
"{method: #, body: #, mode: #, credentials: #, cache: #, referrerPolicy: #, keepalive: #, redirect: #, referrer: #, integrity: #, headers: #}".}
## .. warning:: Unsafe `newfetchOptions`.

func newfetchOptions*(metod = HttpGet; body: cstring = nil;
mode = fmCors; credentials = fcSameOrigin; cache = fchDefault; referrerPolicy = frpNoReferrerWhenDowngrade;
keepalive = false; redirect = frFollow; referrer = "client".cstring; integrity = "".cstring,
headers: Headers = newHeaders()): FetchOptions =
proc unsafeNewFetchOptions*(
metod, body, mode, credentials, cache, referrerPolicy: cstring,
keepalive: bool,
redirect = "follow".cstring,
referrer = "client".cstring,
integrity = "".cstring,
headers: Headers = newHeaders(),
): FetchOptions {.
importjs:
"{method: #, body: #, mode: #, credentials: #, cache: #, referrerPolicy: #, keepalive: #, redirect: #, referrer: #, integrity: #, headers: #}"
.} ## .. warning:: Unsafe `newfetchOptions`.

func newfetchOptions*(
metod = HttpGet,
body: cstring = nil,
mode = fmCors,
credentials = fcSameOrigin,
cache = fchDefault,
referrerPolicy = frpNoReferrerWhenDowngrade,
keepalive = false,
redirect = frFollow,
referrer = "client".cstring,
integrity = "".cstring,
headers: Headers = newHeaders(),
): FetchOptions =
## Constructor for `FetchOptions`.
result = FetchOptions(
body: if metod notin {HttpHead, HttpGet}: body else: nil,
mode: cstring($mode), credentials: cstring($credentials), cache: cstring($cache), referrerPolicy: cstring($referrerPolicy),
keepalive: keepalive, redirect: cstring($redirect), referrer: referrer, integrity: integrity, headers: headers,
metod: (case metod
of HttpHead: "HEAD".cstring
of HttpGet: "GET".cstring
of HttpPost: "POST".cstring
of HttpPut: "PUT".cstring
of HttpDelete: "DELETE".cstring
of HttpPatch: "PATCH".cstring
else: "GET".cstring
)
body: if metod notin {HttpHead, HttpGet}: body else: nil,
mode: cstring($mode),
credentials: cstring($credentials),
cache: cstring($cache),
referrerPolicy: cstring($referrerPolicy),
keepalive: keepalive,
redirect: cstring($redirect),
referrer: referrer,
integrity: integrity,
headers: headers,
# metod: (case metod
# of HttpHead: "HEAD".cstring
# of HttpGet: "GET".cstring
# of HttpPost: "POST".cstring
# of HttpPut: "PUT".cstring
# of HttpDelete: "DELETE".cstring
# of HttpPatch: "PATCH".cstring
# else: "GET".cstring
# )
Comment thread
zivoslav marked this conversation as resolved.
metod: $metod
)

proc fetch*(url: cstring | Request): Future[Response] {.importjs: "$1(#)".}
## `fetch()` API, simple `GET` only, returns a `Future[Response]`.

proc fetch*(url: cstring | Request; options: FetchOptions): Future[Response] {.importjs: "$1(#, #)".}
proc fetch*(
url: cstring | Request, options: FetchOptions
): Future[Response] {.importjs: "$1(#, #)".}
## `fetch()` API that takes a `FetchOptions`, returns a `Future[Response]`.

func toCstring*(self: Request | Response | FetchOptions): cstring {.importjs: "JSON.stringify(#)".}

func `$`*(self: Request | Response | FetchOptions): string = $toCstring(self)
func toCstring*(
self: Request | Response | FetchOptions
): cstring {.importjs: "JSON.stringify(#)".}

func `$`*(self: Request | Response | FetchOptions): string =
$toCstring(self)

runnableExamples("-r:off"):
import std/[asyncjs, jsconsole, jsformdata, jsheaders]
Expand All @@ -134,7 +168,7 @@ runnableExamples("-r:off"):
redirect = "follow".cstring,
referrer = "client".cstring,
integrity = "".cstring,
headers = newHeaders()
headers = newHeaders(),
)
assert options0.keepalive == false
assert options0.metod == "POST".cstring
Expand All @@ -150,7 +184,7 @@ runnableExamples("-r:off"):

block:
let options1: FetchOptions = newFetchOptions(
metod = HttpPost,
metod = HttpPost,
body = """{"key": "value"}""".cstring,
mode = fmNoCors,
credentials = fcOmit,
Expand All @@ -160,7 +194,7 @@ runnableExamples("-r:off"):
redirect = frFollow,
referrer = "client".cstring,
integrity = "".cstring,
headers = newHeaders()
headers = newHeaders(),
)
assert options1.keepalive == false
assert options1.metod == $HttpPost
Expand Down Expand Up @@ -193,7 +227,7 @@ runnableExamples("-r:off"):
discard example()

block:
proc example2 {.async.} =
proc example2() {.async.} =
await fetch("https://api.github.com/users/torvalds".cstring)
.then((response: Response) => response.json())
.then((json: JsObject) => console.log(json))
Expand Down
Loading