Sample CodeReviewed 2026-07-21View on Apple Developer

Building a resumable upload server with SwiftNIO

At a glance

Item Summary
Purpose Translate multiple HTTP resumable-upload requests into one continuous SwiftNIO upload channel for application handlers.
Deliverable A Swift package library, not an app or executable server. Tests exercise the handler with embedded channels.
Public surface HTTPResumableUploadContext stores shared uploads; HTTPResumableUploadHandler is inserted into each connection pipeline.

Project structure

Package.swift
├── Sources/NIOResumableUpload/
│   ├── HTTPResumableUploadContext.swift
│   ├── HTTPResumableUploadHandler.swift
│   ├── HTTPResumableUpload.swift
│   ├── HTTPResumableUploadChannel.swift
│   └── HTTPResumableUploadProtocol.swift
├── Tests/NIOResumableUploadTests/
└── Dependencies/swift-http-types/   # vendored package dependency

The architecture analysis concerns Sources/NIOResumableUpload; the dependency tree is supporting library source, not part of the sample’s upload design.

Overall architecture

Reference code

Sources/NIOResumableUpload/HTTPResumableUploadHandler.swift:25 — callers inject a shared context and the child-channel configuration.

public init(context: HTTPResumableUploadContext,
            channelConfigurator: @escaping (Channel) -> Void) {
    self.upload = HTTPResumableUpload(context: context,
                                      channelConfigurator: channelConfigurator)
}

Ownership and state

Ownership evidence

Sources/NIOResumableUpload/HTTPResumableUpload.swift:15 — one logical upload owns the state that survives connection replacement.

final class HTTPResumableUpload {
    // ...
}

The shared context owns the locked token registry. Each logical upload owns offset, completion flags, timeout, persistent child channel, and at most one attached network handler. On resumption, the new handler points to the existing upload rather than creating a second logical stream.

Class and protocol design

Type Responsibility Boundary
HTTPResumableUploadContext Configure origin/path/timeout and find logical uploads Public API
HTTPResumableUploadHandler Bridge parent-channel events into the state machine Public ChannelDuplexHandler
HTTPResumableUpload Classify requests and enforce upload state/offset rules Internal implementation
HTTPResumableUploadChannel Preserve an application pipeline across request connections Internal Channel/ChannelCore
HTTPResumableUploadProtocol Parse headers and construct protocol responses Internal namespace enum

The library uses SwiftNIO protocols as extension seams; it does not add an app-specific storage protocol because its output is the child channel supplied by the caller.

Access control

Boundary Effect and rationale
public context, initializer, handler, and callbacks Defines the small integration API consumed by a server pipeline.
Internal logical upload, virtual channel, and protocol enum Callers cannot couple to state-machine mechanics.
private flags, offset, handlers, channel, and timer Only the logical upload may perform state transitions.
private(set) resumePath Context cleanup can identify an upload, but other code cannot replace its token.
private locked registry All token mutation goes through startUpload, stopUpload, and findUpload.

Sources/NIOResumableUpload/HTTPResumableUploadContext.swift:12 shows the public facade and private registry; Sources/NIOResumableUpload/HTTPResumableUpload.swift:25 shows controlled token mutation.

Logic ownership and placement

Logic Owner
Upload token registry HTTPResumableUploadContext
NIO lifecycle forwarding HTTPResumableUploadHandler
Request/resumption state transitions HTTPResumableUpload
Header parsing and response construction HTTPResumableUploadProtocol
Persistent pipeline lifecycle and backpressure forwarding HTTPResumableUploadChannel
End-to-end behavior verification NIOResumableUploadTests

Design patterns

Pattern Evidence Purpose
Adapter Sources/NIOResumableUpload/HTTPResumableUploadHandler.swift:13 Converts connection-bound NIO events into logical-upload events.
State machine Sources/NIOResumableUpload/HTTPResumableUpload.swift:191 Dispatches creation, query, append, cancellation, and invalid requests.
Registry Sources/NIOResumableUpload/HTTPResumableUploadContext.swift:16 Resolves a resumption token to persistent state safely across channels.
Virtual child channel Sources/NIOResumableUpload/HTTPResumableUploadChannel.swift:14 Makes many requests appear as one stream to app handlers.
Event-loop confinement Sources/NIOResumableUpload/HTTPResumableUpload.swift:81 Serializes mutable upload transitions.

Naming conventions

  • All library types share the HTTPResumableUpload prefix, making the public and internal family obvious.
  • Role suffixes distinguish Context, Handler, Channel, and Protocol.
  • State commands use connection-neutral verbs: attachUploadHandler, detachUploadHandler, receive, and end.

Architecture takeaways

  • Keep the public pipeline API small and hide the protocol state machine.
  • Give resumable state a lifetime longer than any single connection handler.
  • Use a virtual channel to shield application handlers from transport reconnection.
  • Protect registry access with a lock and transition state on one event loop.

Source map

Source Role
Sources/NIOResumableUpload/HTTPResumableUploadContext.swift:12 Public context and registry
Sources/NIOResumableUpload/HTTPResumableUploadHandler.swift:13 Public NIO adapter
Sources/NIOResumableUpload/HTTPResumableUpload.swift:15 Logical upload state owner
Sources/NIOResumableUpload/HTTPResumableUploadChannel.swift:14 Persistent child channel
Sources/NIOResumableUpload/HTTPResumableUploadProtocol.swift:15 Protocol parser/response namespace