Skip to content

Instantly share code, notes, and snippets.

@mizchi
Last active May 11, 2025 12:56
Show Gist options
  • Save mizchi/e9fb4bb87c6590030eca28ebcfe7d030 to your computer and use it in GitHub Desktop.
Save mizchi/e9fb4bb87c6590030eca28ebcfe7d030 to your computer and use it in GitHub Desktop.
///| Raw JavaScript Fetch API wrapper
extern "js" fn js_fetch(url : String, init : @js.Value) -> @js.Promise =
#| (url, init) => {
#| console.log("fetching", url, init);
#| return fetch(url, init)
#| }
///| JavaScript Fetch API wrapper
/// Usage:
/// ```
/// let res = fetch!(
/// "https://jsonplaceholder.typicode.com/posts/1",
/// http_method="GET",
/// headers={
/// "Accept": "application/json",
/// "Content-Type": "application/json",
/// }
/// body=Some({
/// "userId": 1,
/// })
/// )
/// ```
/// TODO: Abort Signal
pub fn fetch(
url : String,
http_method~ : String = "GET",
body~ : Json? = None,
headers~ : Map[String, String] = {}
) -> Response!Error + Async {
let init = build_request_init(http_method~, headers~, body~)
Response(js_fetch(url, init).wait!())
}
///| Fetch API Response
pub type Response @js.Value
///| js: response.json()
extern "js" fn Response::js_json(v : Response) -> @js.Promise =
#| (v) => v.json()
///| js: response.text()
extern "js" fn Response::js_text(v : Response) -> @js.Promise =
#| (v) => v.text()
///| js: response.status
extern "js" fn Response::js_status(v : Response) -> @js.Value =
#| (v) => v.status
///| js: response.status
extern "js" fn Response::js_ok(v : Response) -> @js.Value =
#| (v) => v.ok
///| js: response.status
extern "js" fn Response::js_body_used(v : Response) -> @js.Value =
#| (v) => v.bodyUsed
///| response.status
pub fn Response::status(v : Response) -> Int {
v.js_status().cast()
}
///| response.bodyUsed
pub fn Response::body_used(v : Response) -> Bool {
v.js_body_used().cast()
}
///| response.ok
pub fn Response::ok(v : Response) -> Bool {
v.js_status().cast()
}
///| resposne.json()
pub fn Response::json(v : Response) -> @js.Value!Error + Async {
v.js_json().wait!()
}
///| response.text()
pub fn Response::text(v : Response) -> String!Error + Async {
v.js_text().wait!().cast()
}
@mizchi
Copy link
Author

mizchi commented May 11, 2025

///|
struct ResponseType {
  userId : Int
  id : Int
  title : String
  body : String
} derive(@json.FromJson, Show)

///|
fnalias @fetch.fetch

///|
typealias @fetch.Request
// typealias @fetch.Response;

///|
async fn run() -> Unit!Error + Async {
  let url = "https://jsonplaceholder.typicode.com/posts/1"
  let res = fetch!(url, http_method="GET", headers={
    "Accept": "application/json",
    "Content-Type": "application/json",
  })
  let response_json : ResponseType = res.json!().cast()
  println("data: \{response_json}")
}

///|
fn main {
  @js.spawn_detach(async fn() { run!() })
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment