123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- ## - Fetch for the JavaScript target: https://developer.mozilla.org/docs/Web/API/Fetch_API
- when not defined(js):
- {.fatal: "Module jsfetch is designed to be used with the JavaScript backend.".}
- import std/[asyncjs, jsformdata, jsheaders]
- export jsformdata, jsheaders
- from std/httpcore import HttpMethod
- from std/jsffi import JsObject
- type
- FetchOptions* = ref object of JsRoot ## Options for Fetch API.
- keepalive*: bool
- metod* {.importjs: "method".}: cstring
- body*, integrity*, referrer*, mode*, credentials*, cache*, redirect*, referrerPolicy*: cstring
- headers*: Headers
- 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
- fcInclude = "include"
- fcSameOrigin = "same-origin"
- fcOmit = "omit"
- 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.
- frFollow = "follow"
- frError = "error"
- frManual = "manual"
- 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
- 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
- bodyUsed*, ok*, redirected*: bool
- typ* {.importjs: "type".}: cstring
- url*, statusText*: cstring
- status*: cint
- headers*: Headers
- body*: cstring
- func newResponse*(body: cstring | FormData): Response {.importjs: "(new Response(#))".}
- ## Constructor for `Response`. This does *not* call `fetch()`. Same as `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(#, #))".}
- ## Constructor for `Request` with `fetchOptions`. Same as `fetch(url, fetchOptions)`.
- func clone*(self: Response | Request): Response {.importjs: "#.$1()".}
- ## https://developer.mozilla.org/en-US/docs/Web/API/Response/clone
- proc text*(self: Response): Future[cstring] {.importjs: "#.$1()".}
- ## https://developer.mozilla.org/en-US/docs/Web/API/Response/text
- proc json*(self: Response): Future[JsObject] {.importjs: "#.$1()".}
- ## https://developer.mozilla.org/en-US/docs/Web/API/Response/json
- 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 =
- ## 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
- )
- )
- 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(#, #)".}
- ## `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)
- runnableExamples("-r:off"):
- import std/[asyncjs, jsconsole, jsformdata, jsheaders]
- from std/httpcore import HttpMethod
- from std/jsffi import JsObject
- from std/sugar import `=>`
- block:
- let options0: FetchOptions = unsafeNewFetchOptions(
- metod = "POST".cstring,
- body = """{"key": "value"}""".cstring,
- mode = "no-cors".cstring,
- credentials = "omit".cstring,
- cache = "no-cache".cstring,
- referrerPolicy = "no-referrer".cstring,
- keepalive = false,
- redirect = "follow".cstring,
- referrer = "client".cstring,
- integrity = "".cstring,
- headers = newHeaders()
- )
- assert options0.keepalive == false
- assert options0.metod == "POST".cstring
- assert options0.body == """{"key": "value"}""".cstring
- assert options0.mode == "no-cors".cstring
- assert options0.credentials == "omit".cstring
- assert options0.cache == "no-cache".cstring
- assert options0.referrerPolicy == "no-referrer".cstring
- assert options0.redirect == "follow".cstring
- assert options0.referrer == "client".cstring
- assert options0.integrity == "".cstring
- assert options0.headers.len == 0
- block:
- let options1: FetchOptions = newFetchOptions(
- metod = HttpPost,
- body = """{"key": "value"}""".cstring,
- mode = fmNoCors,
- credentials = fcOmit,
- cache = fchNoCache,
- referrerPolicy = frpNoReferrer,
- keepalive = false,
- redirect = frFollow,
- referrer = "client".cstring,
- integrity = "".cstring,
- headers = newHeaders()
- )
- assert options1.keepalive == false
- assert options1.metod == $HttpPost
- assert options1.body == """{"key": "value"}""".cstring
- assert options1.mode == $fmNoCors
- assert options1.credentials == $fcOmit
- assert options1.cache == $fchNoCache
- assert options1.referrerPolicy == $frpNoReferrer
- assert options1.redirect == $frFollow
- assert options1.referrer == "client".cstring
- assert options1.integrity == "".cstring
- assert options1.headers.len == 0
- block:
- let response: Response = newResponse(body = "-. .. --".cstring)
- let request: Request = newRequest(url = "http://nim-lang.org".cstring)
- if not defined(nodejs):
- block:
- proc doFetch(): Future[Response] {.async.} =
- fetch "https://httpbin.org/get".cstring
- proc example() {.async.} =
- let response: Response = await doFetch()
- assert response.ok
- assert response.status == 200.cint
- assert response.headers is Headers
- assert response.body is cstring
- discard example()
- block:
- proc example2 {.async.} =
- await fetch("https://api.github.com/users/torvalds".cstring)
- .then((response: Response) => response.json())
- .then((json: JsObject) => console.log(json))
- .catch((err: Error) => console.log("Request Failed", err))
- discard example2()
|