swift-http-types icon indicating copy to clipboard operation
swift-http-types copied to clipboard

How to set body data to a `HTTPRequest`?

Open li-bei opened this issue 1 year ago • 5 comments

That seems not supported yet?

li-bei avatar Jul 19 '23 13:07 li-bei

It is not currently supported. We need to find good mechanisms for sending data, stream, file, and potentially multipart body, and it will likely be a part of the future server and client HTTP APIs rather than on the currency types themselves.

https://github.com/atrick/swift-evolution/blob/bufferview-roadmap/visions/view-types.md https://forums.swift.org/t/requirements-for-a-high-level-http-server-type/65337

guoye-zhang avatar Jul 23 '23 03:07 guoye-zhang

In the meantime, I think we could add URLSession convenience methods that take in a body parameter.

Currently, in order to send a POST request, the developer needs to manually convert the HTTPRequest to a URLRequest so that they can set the body. Then, they would need to manually convert the URLResponse to an HTTPResponse because there is no URLSession convenience method that accepts a URLRequest.

I was thinking the following two convenience methods could be added:

extension URLSession {
  func data(
    for request: HTTPRequest,
    body: Data,
    delegate: URLSessionTaskDelegate? = nil
  ) async throws -> (Data, HTTPResponse) {
    …
  }

  func data(
    for request: HTTPRequest,
    bodyStream: InputStream,
    delegate: URLSessionTaskDelegate? = nil
  ) async throws -> (Data, HTTPResponse) {
    …
  }
}

fumoboy007 avatar Jan 02 '24 20:01 fumoboy007

We currently have these 2:

public func upload(for request: HTTPRequest, fromFile fileURL: URL, delegate: URLSessionTaskDelegate? = nil) async throws -> (Data, HTTPResponse)
public func upload(for request: HTTPRequest, from bodyData: Data, delegate: URLSessionTaskDelegate? = nil) async throws -> (Data, HTTPResponse)

InputStream should be provided in needNewBodyStream delegate method since URLSession would ask for a new stream from the beginning in situations such as redirection or authentication. It's discouraged to provide a single stream upfront. You can convert HTTPRequest to URLRequest then call uploadTaskWithStreamedRequest. A convenience was not provided because InputStream doesn't work very well with Swift concurrency.

guoye-zhang avatar Jan 02 '24 21:01 guoye-zhang

Ah, I didn’t realize that URLSessionUploadTask can do short-lived requests; I thought it was only for long-lived requests. Thanks!

URLSessionDataTask also supports a request body via URLRequest.httpBody. Do you know what the difference is between using URLSessionDataTask vs. URLSessionUploadTask for short-lived requests with bodies? (If so, please also answer this StackOverflow question. 😆)

fumoboy007 avatar Jan 02 '24 21:01 fumoboy007

Upload task is a subclass of data task, so there is little difference between the 2 of them. It's recommended to use upload task instead of httpBody/httpBodyStream properties on the URLRequest. Upload/download tasks also have the benefit of working with background sessions (but you'll have to use the delegate instead of the convenience or async methods).

guoye-zhang avatar Jan 02 '24 21:01 guoye-zhang