[Proposal] SOAR-0004: Streaming request and response bodies

Hi Swift community,

The proposal SOAR-0004: Streaming request and response bodies for Swift OpenAPI Generator is now up and In Review.

The review period will run until 15th September - please feel free to post your feedback either as a reply to this thread, or on the pull request .

Thanks!

cc @Honza_Dvorsky

5 Likes

This looks good. I don’t think Hummingbird will have any issues moving to using the AsyncSequence based HTTP body.

The only issue I can see is I am still going to need to copy all the body data as I am converting between NIO ByteBuffer and ArraySlice unless someone on the NIO team has a clever way to avoid this.

1 Like

Just to be explicit here: we do not. However, as the community moves towards a standard "bag of bytes" type, we may be able to re-evaluate these APIs.

5 Likes

Hi folks, thanks for the feedback so far, I just published v1.2 of the proposal that adds more Sendable requirements on the AsyncSequences and all inputs: [Proposal] SOAR-0004: Streaming request and response bodies by czechboy0 · Pull Request #254 · apple/swift-openapi-generator · GitHub

Please keep the feedback coming, 3 more days to provide feedback :pray:

i was not aware of anyone moving towards a standard bytebuffer type because i wasn't aware that any such type existed besides NIOCore.ByteBuffer. is there a library besides SwiftNIO that people are moving towards now to replace ByteBuffer?

1 Like
    /// Describes how many times the provided sequence can be iterated.
    public enum IterationBehavior : Sendable {

        /// The input sequence can only be iterated once.
        ///
        /// If a retry or a redirect is encountered, fail the call with
        /// a descriptive error.
        case single

        /// The input sequence can be iterated multiple times.
        ///
        /// Supports retries and redirects, as a new iterator is created each
        /// time.
        case multiple
    }

I just re-read the ownership modifiers proposal and thought these names may also be a good fit here i.e. consume instead of single and borrow for multiple.

2 Likes

The HTTPBody.init has a couple of overloads that take a Sequence/Collection of "Strings"/"Bytes", concretely these types:

  • some Sequence<some StringProtocol>
  • some Collection<some StringProtocol>
  • some Sequence<ArraySlice<UInt8>>
  • some Collection<ArraySlice<UInt8>>

They could all be replaced by importing AsyncAlgorithms and using the .async operator as that's how they are internally transformed. The only benefit I see is for the overload that take some Collection as a Collection can always be iterated multiple times. We would lose this information if we use the .async modifier and users would need to manually specify .multiple. I'm wondering if this warrants the number of overloads.

1 Like

That's a great idea, and I'd happily adopt those names. Before I do, are we sure that using the same names will be a positive for consistency? Or could it actually be more confusing because the methods taking this parameter will not actually have the language-level keywords?

Trying to think about another example of using the same words as keywords, would we prefer or actually find confusing if there was a parameter accessModifier that took one of the values public, internal, private, but meant something application-specific?

But maybe I'm being too cautious, just wanted to double check before I go and update the proposal that we've considered this. WDYT?

Yeah, I took another look and removed all six variants of the sync sequences-of-byte-chunks, I don't think they were pulling their weight. I also added a few other ones for sequences of bytes (as opposed to sequences of chunks). Please take a second look at version v1.3, which was just pushed: https://github.com/czechboy0/swift-openapi-generator/blob/hd-soar-0004/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0004.md (changes since v1.2).

Thanks for such a great write up!

extension HTTPBody {
    /// Creates a new body with the provided async sequence of byte sequences.
    /// - Parameters:
    ///   - sequence: An async sequence that provides the byte chunks.
    ///   - length: The total lenght of the body.
    ///   - iterationBehavior: The iteration behavior of the sequence, which
    ///     indicates whether it can be iterated multiple times.
    @inlinable public convenience init<S, ES>(
        _ sequence: S,
        length: HTTPBody.Length,
        iterationBehavior: IterationBehavior
    ) where S: Sendable, S: AsyncSequence, ES: Sequence, ES == S.Element, ES.Element == UInt8
}

Might just be me, but I found the additional type parameter in the signature confusing, rather than using S.Element in the type constraints, e.g.

@inlinable public convenience init<S>(
    _ sequence: S,
    length: HTTPBody.Length,
    iterationBehavior: IterationBehavior
) where S: Sendable, S: AsyncSequence, S.Element: Sequence, S.Element.Element == UInt8
1 Like

Hah, that's an oversight, you're absolutely right. Will fix.

I would also appreciate describing names for the generic parameters instead of single letters, e.g. Bytes.
In addition, I would prefer the use of opaque parameters where possible.

1 Like

Good point, will do!

@beaumont @dnadoba All addressed in v1.4 (diff).

1 Like

The review period for this proposal is now over, and all suggested changes have been implemented.
For a complete picture of the discussed topics, you can refer to the previous comments on this thread, as well as the conversation on the PR.

The proposal is accepted. SOAR-0004 is now Ready for Implementation.

1 Like