Skip to content

Add first-class async/await networking API - #2

Merged
mchirino89 merged 3 commits into
mainfrom
claude/async-await-network-api-50b9e3
Jul 4, 2026
Merged

mchirino89 merged 3 commits into
mainfrom
claude/async-await-network-api-50b9e3

Conversation

@mchirino89

@mchirino89 mchirino89 commented Jul 4, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Rebuilds MauriNet as an async-only networking library on Swift 6, replacing both the completion-handler API and the WIP Combine agent with first-class Swift concurrency.

New async/await API

  • AsyncRequestManager (backed by the new public AsyncRequestable protocol):
    • Vanilla request(_:) async throws -> Data
    • Type-safe request(_:decoder:) async throws -> Model for any Decodable
    • CRUD conveniences: create (POST), read (GET), update (PUT or PATCH), delete (DELETE) — they stamp the HTTP verb and attach the payload for you
    • download(_:into:) — relocates the file out of URLSession's ephemeral storage into an explicit (injectable, testable) destination directory; download(_:) convenience defaults to the temporary directory
    • upload(_:from:)
  • Built directly on URLSession's native async APIs (data(for:) / download(for:) / upload(for:from:)), so cancelling the surrounding Task cancels the network request (surfaced as NetworkError.cancelled)
  • All failures throw the strongly typed NetworkError: HTTP status codes map via the shared ResponseValidator, transport failures map through mapTransportFailure (cancellation → .cancelled, timeout → .timeout, anything else → .unknown)
  • New HTTPMethod.patch case
  • Testability preserved: URLSessionable is a lean async protocol (retrieveData / downloadFile / upload) that URLSession conforms to — mocks are plain types, no more subclassing deprecated URLSessionTask types

Legacy purge (per review)

  • Completion-handler API removed: RequestManager, RequestableManager, NetworkResult
  • URL assembling removed: APIEndpoint, EndpointBuilder, URLBuilderResult/URLBuilderError, APIScheme, plus orphaned URLComponents/Collection helpers and unused HTTPEncoding
  • Internal WIP Combine Agent removed (drops the last Combine import)

Platform floor (n−2 policy)

  • swift-tools 6.0 with Swift 6 language mode and audited Sendable conformances across the public surface
  • iOS 17 / macOS 14 / tvOS 17 / watchOS 10
  • ⚠️ Breaking for consumers on older targets — they can stay pinned to the 0.2.1 tag

Package modernization

  • Package builds on Linux (FoundationNetworking imports)
  • Stale LinuxMain.swift / XCTestManifests.swift (referencing a nonexistent class) removed in favor of automatic test discovery

Tests

24 tests, all passing, zero build warnings (verified with Swift 6.0.3 in Swift 6 language mode): success paths, non-HTTP responses, HTTP error mapping, transport-failure mapping, CRUD verb stamping and payload attachment, Decodable success/failure, upload payload recording, download persistence and destination-directory injection. Payload setup uses XCTUnwrap (no force unwraps) and downloaded artifacts are purged via addTeardownBlock regardless of test outcome.

Documentation

  • README overhauled: SPM installation steps plus copy-pasteable examples for CRUD, Decodable requests, downloads (including explicit destination), uploads and testability
  • Full doc comments on every public signature (Jazzy docs/ intentionally untouched)

🤖 Generated with Claude Code

https://claude.ai/code/session_017esYpGrJ3HtXUTaGiJ5jff

claude added 2 commits July 3, 2026 23:30
Modernizes the library around Swift concurrency while keeping the
existing completion handler API intact:

- New AsyncRequestManager (backed by the AsyncRequestable protocol)
  offering a vanilla async request, CRUD conveniences
  (create/read/update/delete), download and upload APIs, plus a
  Decodable-returning request built on top of a configurable decoder
- Downloaded files are relocated out of URLSession's ephemeral storage
  so they remain usable after the call returns
- New PATCH case in HTTPMethod, surfaced through update(_:payload:method:)
- Extracted shared HTTP response validation into ResponseValidator so
  every API flavor maps NetworkError consistently
- Fixed URLSession.dataTaskWithURL dropping the request's HTTP method,
  headers and body by forwarding only its URL
- URLSessionable now covers data, download and upload tasks; its
  completion typealiases are @sendable to match URLSession's contract
- Bumped tools version to 5.7, declared tvOS/watchOS floors and made
  the package build on Linux (FoundationNetworking imports, Combine
  agent conditionally compiled, stale LinuxMain/XCTestManifests removed
  in favor of automatic test discovery)
- Unit tests for every async use case (success, transport failure,
  HTTP error mapping, CRUD verb stamping, decoding, upload recording,
  download persistence)
- README overhauled with SPM installation steps and async/await usage
  examples

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017esYpGrJ3HtXUTaGiJ5jff
Per the n-2 support policy (keep up to two versions behind current):

- swift-tools 6.0 with Swift 6 language mode; floors raised to
  iOS 17 / macOS 14 / tvOS 17 / watchOS 10
- URLSessionable reshaped into async requirements (retrieveData,
  downloadFile, upload) forwarding to URLSession's native async APIs,
  replacing the hand-rolled continuation wrappers. Task cancellation
  now propagates to the underlying network request
- Transport failures map through ResponseValidator.mapTransportFailure:
  URLError/CancellationError cancellations -> .cancelled, timeouts ->
  .timeout, anything else -> .unknown
- Audited Sendable conformances across the public surface
- Legacy RequestManager bridges its completion API through
  AsyncRequestManager instead of duplicating the session plumbing
- Test doubles no longer subclass deprecated URLSessionTask types;
  new transport-failure mapping tests added (31 tests total)
- README requirements and testability example updated

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017esYpGrJ3HtXUTaGiJ5jff
Comment thread Sources/MauriNet/Concurrency/AsyncRequestManager.swift
Comment thread Tests/MauriNetTests/Tests/AsyncRequestManagerTestCases.swift Outdated
Comment thread Tests/MauriNetTests/Tests/AsyncRequestManagerTestCases.swift Outdated
Comment thread Tests/MauriNetTests/Tests/AsyncRequestManagerTestCases.swift Outdated
Comment thread Tests/MauriNetTests/Tests/MauriNetSessionTestCases.swift Outdated
Comment thread Tests/MauriNetTests/Tests/MauriNetURLBuilderTestCases.swift Outdated
Comment thread README.md Outdated
Comment thread README.md Outdated
Comment thread Tests/MauriNetTests/Tests/AsyncRequestManagerTestCases.swift
Comment thread Sources/MauriNet/Concurrency/AsyncRequestManager.swift Outdated
@mchirino89 mchirino89 self-assigned this Jul 4, 2026
- Remove the completion-handler API (RequestManager, RequestableManager,
  NetworkResult) and its tests: the library is now async-only
- Remove APIEndpoint, EndpointBuilder, URLBuilderResult/URLBuilderError,
  APIScheme and their tests, plus the now-orphaned URLComponents/
  Collection helpers and unused HTTPEncoding
- Remove the internal WIP Combine Agent (drops the last Combine import)
- Rename RequestableManager.swift to URLSessionable.swift to match its
  remaining content
- download now accepts an explicit destination directory
  (download(_:into:)), defaulting to the temporary directory via a
  protocol extension, so the relocation target is injectable and
  assertable in tests
- Replace force unwraps with XCTUnwrap in test payload setup
- Purge downloaded artifacts via addTeardownBlock so cleanup runs
  regardless of test outcome
- Document the uploaded payload variable in the upload example (doc
  comment and README); drop the legacy and endpoint-assembling README
  sections

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017esYpGrJ3HtXUTaGiJ5jff
@mchirino89
mchirino89 merged commit 06b0a75 into main Jul 4, 2026
1 check passed
@mchirino89
mchirino89 deleted the claude/async-await-network-api-50b9e3 branch July 4, 2026 15:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants