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

PUT request using Fetch #197

Closed
lorenalexm opened this issue Jun 7, 2022 · 2 comments
Closed

PUT request using Fetch #197

lorenalexm opened this issue Jun 7, 2022 · 2 comments
Labels
documentation Improvements or additions to documentation

Comments

@lorenalexm
Copy link

I am trying to figure out how to use JSObject.global.fetch.function! along with JSPromise to assemble a PUT request with a body and headers. I keep falling flat on my face 😣 I am able to use fetch and preform GET requests, parse the JSON, and the whole-nine-yards, but I don't understand where to go for sending data.

I have tried assembling a params object using something like this JSObject.construct(from: ["method": "PUT", "body": json.jsString].jsValue) and passing it as a second parameter to fetch. Doing this though, when handling the .then statement I receive an error of:

/Users/lorenalexm/Projects/SwiftScheduleCheck/Sources/SwiftScheduleCheck/Views/ContentView.swift:118:16: Cannot convert value of type '()' to closure result type 'ConvertibleToJSValue'

Might anyone help provide a bit of guidance on how to proceed from here? Thank you!

@MaxDesiatov
Copy link
Contributor

Here's a snippet for posterity, note that it's slightly inconsistent with the use of Codable due to #116:

import Foundation
import JavaScriptEventLoop
import JavaScriptKit

JavaScriptEventLoop.installGlobalExecutor()

struct Body: Codable {
  let x: Int
  let y: String
}

private let jsFetch = JSObject.global.fetch.function!
func fetch(_ url: String, _ options: [String: JSValue]) async throws -> JSValue {
  try await JSPromise(jsFetch(url, options).object!)!.value
}

let encoder = JSONEncoder()
let decoder = JSValueDecoder()

func post<Body: Codable>(_ url: String, _ body: Body) async throws -> Body {
  let data = try encoder.encode(body)
  let response = try await fetch(
    url,
    [
      "method": "POST",
      "headers": ["Content-Type": "application/json"].jsValue,
      "redirect": "follow",
      "body": String(data: data, encoding: .utf8)!.jsValue,
    ]
  ).object!
  let json = try await JSPromise(response.json!().object!)!.value
  return try decoder.decode(Body.self, from: json.object!.json)
}

Also note the use of json.object!.json, it's a peculiarity of httpbin, which I used to test this. It wraps the response in a top-level JSON structure, having body in the inner json property. You may need to use json instance directly with other services instead.

@lorenalexm does that resolve your issue?

@MaxDesiatov MaxDesiatov added the documentation Improvements or additions to documentation label Aug 17, 2022
@lorenalexm
Copy link
Author

@MaxDesiatov I am so sorry for the delay in replying. Thank you so much for the explanation and code snippet, this really helped me work through my issue and build a reusable class for making network requests in my Tokamak projects! Your assistance has helped resolve my problems, thank you again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

2 participants