Skip to content

Commit 1c9e9f1

Browse files
authored
Merge pull request #113 from futuredapp/feature/request-configuring
Migrate to Swift 6
2 parents 04ac575 + f1496bc commit 1c9e9f1

58 files changed

Lines changed: 1220 additions & 1466 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: macOS 14
1+
name: CI
22

33
on:
44
push:
@@ -10,20 +10,15 @@ on:
1010

1111
jobs:
1212
test:
13-
runs-on: macos-14
13+
runs-on: macos-latest
1414

1515
steps:
16-
- uses: actions/checkout@v4
16+
- uses: actions/checkout@v6
1717
- name: Install SwiftLint
1818
run: brew install swiftlint
1919
- name: Lint
2020
run: |
2121
swiftlint --strict
22-
- name: Pod lib lint
23-
run: |
24-
gem install bundler
25-
bundle install --jobs 4 --retry 3
26-
bundle exec pod lib lint --allow-warnings
2722
- name: Swift build & test
2823
run: |
2924
swift build

.github/workflows/macos-15.yml

Lines changed: 0 additions & 30 deletions
This file was deleted.

.github/workflows/ubuntu-latest.yml

Lines changed: 0 additions & 24 deletions
This file was deleted.

.gitignore

Lines changed: 10 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
11
# Xcode
2-
#
3-
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4-
5-
## Build generated
62
build/
73
DerivedData/
8-
docs/
9-
10-
## Various settings
114
*.pbxuser
125
!default.pbxuser
136
*.mode1v3
@@ -16,60 +9,29 @@ docs/
169
!default.mode2v3
1710
*.perspectivev3
1811
!default.perspectivev3
19-
xcuserdata/
20-
21-
## Other
12+
**/xcuserdata/
2213
*.moved-aside
2314
*.xccheckout
2415
*.xcscmblueprint
25-
26-
## Obj-C/Swift specific
2716
*.hmap
2817
*.ipa
2918
*.dSYM.zip
3019
*.dSYM
3120

32-
## Playgrounds
21+
# Playgrounds
3322
timeline.xctimeline
3423
playground.xcworkspace
3524

25+
# macOS
26+
.DS_Store
27+
3628
# Swift Package Manager
37-
#
38-
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
39-
# Packages/
40-
Package.resolved
41-
.swiftpm
4229
.build/
43-
# We do not need the project, because it can be generated or the Package.swift can be open in Xcode 11
30+
.swiftpm/
31+
Package.resolved
4432
FTAPIKit.xcodeproj
4533

46-
# CocoaPods
47-
#
48-
# We recommend against adding the Pods directory to your .gitignore. However
49-
# you should judge for yourself, the pros and cons are mentioned at:
50-
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
51-
#
52-
# Pods/
53-
54-
# Carthage
55-
#
56-
# Add this line if you want to avoid checking in source code from Carthage dependencies.
57-
# Carthage/Checkouts
58-
59-
Carthage/Build
60-
61-
# fastlane
62-
#
63-
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
64-
# screenshots whenever they are needed.
65-
# For more information about the recommended setup visit:
66-
# https://docs.fastlane.tools/best-practices/source-control/#source-control
67-
68-
fastlane/report.xml
69-
fastlane/Preview.html
70-
fastlane/screenshots
71-
fastlane/test_output
72-
fastlane/README.md
34+
# Claude Code
35+
.claude
7336

74-
# Ignore VSCode files
75-
.vscode
37+
*.xcuserstate

.swiftlint.yml

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,11 @@
11
disabled_rules:
22
- line_length
3-
# Combination of SwiftLint 0.43.1 and Xcode 12.5.1
4-
# warns about false positives for this rule
5-
- empty_xctest_method
6-
# Type inference of `await try` methods
7-
# does not work well in Xcode 13 Beta
8-
- implicit_return
93
# Does not work with URL query literals.
104
- duplicated_key_in_dictionary_literal
115
excluded:
12-
- Pods
136
- .build
147
- Templates
158
opt_in_rules:
16-
- anyobject_protocol
179
- array_init
1810
- attributes
1911
- closure_body_length
@@ -26,12 +18,10 @@ opt_in_rules:
2618
- contains_over_first_not_nil
2719
- contains_over_range_nil_comparison
2820
- convenience_type
29-
- discouraged_object_literal
3021
- discouraged_optional_boolean
3122
- empty_collection_literal
3223
- empty_count
3324
- empty_string
34-
- empty_xctest_method
3525
- enum_case_associated_values_count
3626
- explicit_init
3727
- fallthrough
@@ -55,22 +45,17 @@ opt_in_rules:
5545
- multiline_literal_brackets
5646
- multiline_parameters
5747
- multiline_parameters_brackets
58-
- nimble_operator
5948
- number_separator
60-
- object_literal
6149
- operator_usage_whitespace
6250
- optional_enum_case_matching
6351
- overridden_super_call
6452
- override_in_extension
6553
- pattern_matching_keywords
6654
- prefer_self_type_over_type_of_self
67-
- private_action
68-
- private_outlet
6955
- prohibited_super_call
7056
- reduce_into
7157
- redundant_nil_coalescing
7258
- required_enum_case
73-
- single_test_class
7459
- sorted_first_last
7560
- sorted_imports
7661
- static_operator
@@ -80,12 +65,9 @@ opt_in_rules:
8065
- trailing_closure
8166
- unneeded_parentheses_in_closure_argument
8267
- untyped_error_in_catch
83-
- unused_declaration
84-
- unused_import
8568
- vertical_parameter_alignment_on_call
8669
- vertical_whitespace_closing_braces
8770
- yoda_condition
88-
8971
# Rule configurations
9072
identifier_name:
9173
excluded:

CLAUDE.md

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
FTAPIKit is a declarative async/await REST API framework for Swift using Swift Concurrency and Codable. It provides a protocol-oriented approach to defining web services with standard implementation using URLSession and JSON encoder/decoder. The framework is built for Swift 6.1 with full concurrency safety.
8+
9+
**Key Features:**
10+
- Declarative async/await API for defining web services
11+
- Protocol-oriented design with `URLServer` and `Endpoint` protocols
12+
- Multiple endpoint types for different use cases (GET, POST, multipart uploads, etc.)
13+
- Async buildRequest enabling token refresh, dynamic configuration, and rate limiting
14+
- `RequestConfiguring` protocol for per-request configuration at call site
15+
- `NetworkObserver` protocol for request lifecycle monitoring (logging, analytics)
16+
- Swift 6 concurrency safety with Sendable requirements
17+
- Cross-platform support: iOS 15+, macOS 12+, tvOS 15+, watchOS 8+
18+
19+
## Build and Test Commands
20+
21+
### Building
22+
```bash
23+
# Use xcodebuild (preferred, avoids toolchain mismatch issues)
24+
xcodebuild build -scheme FTAPIKit -destination 'platform=macOS'
25+
26+
# Or with Swift CLI
27+
swift build
28+
```
29+
30+
### Running Tests
31+
```bash
32+
# Use xcodebuild
33+
xcodebuild test -scheme FTAPIKit -destination 'platform=macOS'
34+
35+
# Or with Swift CLI
36+
swift test
37+
```
38+
39+
### Linting
40+
```bash
41+
# Run SwiftLint with strict mode
42+
swiftlint --strict
43+
```
44+
45+
The project uses an extensive SwiftLint configuration (`.swiftlint.yml`) with many opt-in rules enabled. Linting must pass with `--strict` flag with zero violations before committing any code.
46+
47+
## Architecture
48+
49+
### Core Protocol Design
50+
51+
The framework is built around two core protocols:
52+
53+
1. **`URLServer` Protocol** - Represents a single web service
54+
- Defines `baseUri`, `urlSession`, `encoding`/`decoding`, `networkObservers`
55+
- Builds requests from endpoints via `buildRequest(endpoint:) async throws`
56+
- Provides default implementations for all properties except `baseUri`
57+
- Has `ErrorType` associated type (defaults to `APIError.Standard`)
58+
59+
2. **`Endpoint` Protocol** - Represents access points for resources
60+
- Defines path, headers, query parameters, and HTTP method
61+
- Multiple specialized variants for different use cases
62+
63+
### Endpoint Type Hierarchy
64+
65+
- **`Endpoint`** - Base protocol with empty body (defaults to GET)
66+
- **`DataEndpoint`** - Sends raw data in body (defaults to POST)
67+
- **`UploadEndpoint`** - Uploads files using URLSession upload (defaults to POST)
68+
- **`MultipartEndpoint`** - Combines body parts into multipart request (defaults to POST)
69+
- **`URLEncodedEndpoint`** - Body in URL query format (defaults to POST)
70+
- **`RequestEndpoint`** - Has encodable request model (defaults to POST)
71+
- **`ResponseEndpoint`** - Has decodable response model
72+
- **`RequestResponseEndpoint`** - Typealias combining request and response endpoints
73+
74+
### Key Architectural Patterns
75+
76+
**URLServer Protocol**: The `URLServer` protocol provides all URLSession-based functionality with default implementations. Only `baseUri` must be provided by conforming types.
77+
78+
**Network Observers**: The `NetworkObserver` protocol provides lifecycle callbacks (`willSendRequest`, `didReceiveResponse`, `didFail`) with type-safe context passing. Observer integration uses `BoundObserverContext` (private) for type erasure.
79+
80+
**Request Configuration**: The `RequestConfiguring` protocol allows per-request async configuration at the call site, separate from server-level `buildRequest`.
81+
82+
**Encoding/Decoding**: The `Encoding` protocol includes `configure(request:)` for setting content-type headers (with empty default). Both `Encoding` and `Decoding` require `Sendable`.
83+
84+
**Swift 6 Concurrency Safety**: All `ResponseEndpoint.Response` and `RequestEndpoint.Request` associated types must conform to `Sendable`.
85+
86+
### Module Organization
87+
88+
**Source Structure** (`Sources/FTAPIKit/`):
89+
- Core protocols: `URLServer.swift`, `Endpoint.swift`
90+
- Request building: `URLRequestBuilder.swift`, `RequestConfiguring.swift`
91+
- Async execution: `URLServer+Async.swift` (includes download)
92+
- Observers: `NetworkObserver.swift`
93+
- Utilities: `Coding.swift`, `URLQuery.swift`, `MultipartFormData.swift`, etc.
94+
- Error handling: `APIError.swift`, `APIError+Standard.swift`
95+
96+
**Test Structure** (`Tests/FTAPIKitTests/`):
97+
- Uses Swift Testing framework (`@Suite`, `@Test`, `#expect`)
98+
- Test files: `AsyncTests.swift`, `AsyncBuildRequestTests.swift`, `URLQueryTests.swift`, `NetworkObserverTests.swift`, `RequestConfiguringTests.swift`, `EndpointTypeTests.swift`, `ErrorHandlingTests.swift`
99+
- Test utilities in `Mockups/`: `Servers.swift`, `Endpoints.swift`, `Models.swift`, `Errors.swift`, `MockNetworkObserver.swift`, `MockTokenManager.swift`, `HTTPBinResponse.swift`
100+
101+
### Call Execution Pattern
102+
103+
The framework uses async/await exclusively:
104+
105+
```swift
106+
// Basic call
107+
let response = try await server.call(response: endpoint)
108+
109+
// Data call (raw Data response)
110+
let data = try await server.call(data: endpoint)
111+
112+
// Void call (no response body)
113+
try await server.call(endpoint: endpoint)
114+
115+
// Download call (temporary file — caller must move before returning)
116+
let fileURL = try await server.download(endpoint: endpoint)
117+
118+
// Download call (moved to destination automatically)
119+
try await server.download(endpoint: endpoint, destination: destinationURL)
120+
```
121+
122+
### Error Handling
123+
124+
- `APIError` protocol defines error handling interface
125+
- Default implementation: `APIError.Standard` (enum with connection, encoding, decoding, server, client, unhandled cases)
126+
- Network errors (`URLError`) and decoding errors are routed through `ErrorType` for consistent error handling
127+
- Encoding errors (from `buildStandardRequest`) propagate directly as `EncodingError` since they occur before the network request
128+
- Custom error types can be defined via `URLServer.ErrorType` associated type
129+
130+
## Package Management
131+
132+
The project uses **Swift Package Manager** exclusively. See `Package.swift`.
133+
134+
### Platform Support
135+
136+
Minimum deployment targets:
137+
- iOS 15+
138+
- macOS 12+
139+
- tvOS 15+
140+
- watchOS 8+
141+
142+
## Testing Approach
143+
144+
Tests use Swift Testing framework and mock servers (HTTPBin-based) defined in `Tests/FTAPIKitTests/Mockups/Servers.swift`:
145+
- `HTTPBinServer` - Standard test server with async authorization support
146+
- `NonExistingServer` - For testing error conditions
147+
- `ErrorThrowingServer` - Custom error type testing
148+
- `HTTPBinServerWithObservers` - Observer integration testing
149+
150+
## CI/CD
151+
152+
Single GitHub Actions workflow (`ci.yml`) runs on `macos-latest`:
153+
- `swiftlint --strict`
154+
- `swift build`
155+
- `swift test`

0 commit comments

Comments
 (0)