Skip to content

Conversation

@ssestak
Copy link
Contributor

@ssestak ssestak commented Jan 13, 2026

Summary

  • Adds GraphQLNetworkObserver protocol for passive observation of GraphQL network requests
  • Implements observer pattern matching FTAPIKit's NetworkObserver for API consistency
  • Supports multiple observers with context passing between request and response phases
  • Uses OSAllocatedUnfairLock for thread-safe synchronous context storage

Changes

  • GraphQLNetworkObserver protocol with willSendRequest, didReceiveResponse, and didFail callbacks
  • ObserverInterceptor struct for integrating observers into Apollo's interceptor chain
  • ObserverContextStore class with OSAllocatedUnfairLock for thread-safe context management
  • Uses ObjectIdentifier for stable request correlation across interceptor chain
  • Updated minimum macOS target to 13.0 (for OSAllocatedUnfairLock)

Test plan

  • Unit tests for observer protocol conformance
  • Unit tests for context store operations
  • Integration tests for header capture (default + context headers)
  • Integration tests for multiple observers

🤖 Generated with Claude Code

This change updates the minimum macOS version required for the package to macOS 11.
@ssestak ssestak requested review from jmarek41 and samoilyk January 13, 2026 09:31
@ssestak ssestak marked this pull request as ready for review January 13, 2026 09:31
Šimon Šesták and others added 13 commits January 13, 2026 14:48
Introduce GraphQLNetworkObserver protocol following FTAPIKit pattern.
Observers receive lifecycle callbacks (willSendRequest, didReceiveResponse,
didFail) without ability to modify requests - safer than interceptors.
Replace custom GraphQLOperationContext with URLRequest for observer API,
matching FTAPIKit's NetworkObserver pattern exactly. Use closure capture
pattern in ObserverInterceptor for type erasure without locks.

- Remove GraphQLOperationContext and GraphQLRequestToken
- Add ObserverInterceptor with generic init for type erasure
- Use closure capture pattern (no locks needed)
- Add factory pattern in NetworkInterceptorProvider
- Simplify GraphQLAPIAdapter (observer handling now in interceptor)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Ensures observers see URLRequest with all headers applied (defaultHeaders
and additionalHeaders from context).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add GraphQLAPIAdapterIntegrationTests with MockURLProtocol to verify:
- Observer receives default headers
- Observer receives context headers (RequestHeaders)
- Observer receives both default and context headers
- Multiple observers all receive same headers
- Observer sees Apollo-added headers (X-APOLLO-OPERATION-NAME, etc.)

Also add unit tests for header capture in GraphQLNetworkObserverTests:
- testObserverReceivesHeadersFromURLRequest
- testMultipleObserversReceiveSameHeaders
- testInterceptorChainOrderPlacesObserversAfterHeaders

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change didReceiveResponse signature from HTTPURLResponse? to URLResponse?
to match FTAPIKit's NetworkObserver protocol exactly. This allows a single
class to conform to both protocols without method signature conflicts.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Refactor network observer integration to allow state sharing between pre-network-request and post-network-response/error phases using an `ObserverContextStore` actor. This enables observers to maintain a consistent context throughout a single network operation. Also, update macOS deployment target to v12.

# Conflicts:
#	Package.swift
Extracted `NetworkInterceptorProvider` and `RequestHeaderInterceptor` into their own files and relocated `ObserverInterceptor` to a new `Interceptors` directory for better modularity.
…ency and simplified memory management

The ObserverInterceptor has been refactored from a class to a struct. This change enhances Sendable conformance, eliminates potential reference cycles, and removes the need for explicit weak self captures within asynchronous blocks.
…ork observer

Streamlines `ObserverInterceptor` creation, enhances `NetworkObserver` protocol conformance, and unifies `ObserverContextStore` operations into robust test cases.
…edUnfairLock

The ObserverContextStore was converted from an actor to a final class, utilizing OSAllocatedUnfairLock for thread-safe synchronous access. This simplifies the ObserverInterceptor by removing unnecessary Task wrappers and associated await calls. The minimum macOS deployment target was also updated to v13.
Replaced `urlRequest.hashValue.description` with `ObjectIdentifier(request).debugDescription` for stable request tracking by observers, addressing potential inconsistencies with hash values.
… observers

This introduces a new initializer for `GraphQLAPIAdapter` that leverages Swift 5.9's variadic generics, allowing multiple `GraphQLNetworkObserver` instances to be passed directly without being wrapped in an array. This improves API ergonomics and simplifies usage. The `swift-tools-version` has been updated to 5.9 accordingly.
@ssestak ssestak force-pushed the feature/network-observers branch from 3407612 to f6c8707 Compare January 13, 2026 15:08
@ssestak ssestak merged commit 4ae59ac into main Jan 13, 2026
@ssestak ssestak deleted the feature/network-observers branch January 13, 2026 15:18
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.

4 participants