Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ea27718
chore: Upgrade to Swift 6.1 and update minimum deployment targets
Nov 18, 2025
867034c
refactor: Remove deprecated CoreServices API and simplify MIME type d…
Nov 18, 2025
9eb3bbb
feat!: Add Sendable conformance requirement to ResponseEndpoint
Nov 18, 2025
1a6dee4
fix: Resolve Swift 6 concurrency safety warnings
Nov 18, 2025
1977658
ci: Update GitHub Actions workflows to use macOS 14 runners
Nov 18, 2025
00f7d31
docs: Update documentation for Swift 6.1 migration
Nov 18, 2025
788c9b9
feat!: Remove Combine and completion handler APIs
Nov 18, 2025
c73db47
refactor: Implement native async/await execution using URLSession APIs
Nov 18, 2025
7364974
refactor: Make buildRequest async throws in protocol
Nov 18, 2025
1d8be12
test: Add async buildRequest tests demonstrating token refresh and dy…
Nov 18, 2025
8f4142c
docs: Update to version 2.0.0 with async-only API documentation
Nov 18, 2025
7b363fd
feat: Add RequestConfiguring protocol for per-request configuration
Jan 24, 2026
c41f649
WIP
Jan 26, 2026
b20855c
merge: Merge main into feature/request-configuring
jmarek41 Mar 12, 2026
decf6bb
Update gitignore
jmarek41 Mar 12, 2026
21a6c2c
Remove local settings from the project
jmarek41 Mar 12, 2026
5327625
Update workflows
jmarek41 Mar 12, 2026
b19367f
Update lint
jmarek41 Mar 12, 2026
61e3f56
Remove support of cocoa pods
jmarek41 Mar 12, 2026
2b6e4c4
Remove linux support
jmarek41 Mar 12, 2026
f82cd4c
Update tests
jmarek41 Mar 12, 2026
7f1bc25
Update claude.md
jmarek41 Mar 12, 2026
176ab61
Bump os versions
jmarek41 Mar 12, 2026
5b8cd34
Use URLServer naming
jmarek41 Mar 17, 2026
76f8856
Update URLServer
jmarek41 Mar 17, 2026
4d4bd72
Update docs
jmarek41 Mar 17, 2026
254359d
CR updates
jmarek41 Mar 17, 2026
a583751
Code review updates
jmarek41 Mar 17, 2026
5a3007c
Re-add templates
jmarek41 Mar 17, 2026
aaf0a65
Bugfix
jmarek41 Mar 17, 2026
9471682
Update docs
jmarek41 Mar 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions .github/workflows/macos-14.yml → .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: macOS 14
name: CI

on:
push:
Expand All @@ -10,20 +10,15 @@ on:

jobs:
test:
runs-on: macos-14
runs-on: macos-latest

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Install SwiftLint
run: brew install swiftlint
- name: Lint
run: |
swiftlint --strict
- name: Pod lib lint
run: |
gem install bundler
bundle install --jobs 4 --retry 3
bundle exec pod lib lint --allow-warnings
- name: Swift build & test
run: |
swift build
Expand Down
30 changes: 0 additions & 30 deletions .github/workflows/macos-15.yml

This file was deleted.

24 changes: 0 additions & 24 deletions .github/workflows/ubuntu-latest.yml

This file was deleted.

58 changes: 10 additions & 48 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore

## Build generated
build/
DerivedData/
docs/

## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
Expand All @@ -16,60 +9,29 @@ docs/
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/

## Other
**/xcuserdata/
*.moved-aside
*.xccheckout
*.xcscmblueprint

## Obj-C/Swift specific
*.hmap
*.ipa
*.dSYM.zip
*.dSYM

## Playgrounds
# Playgrounds
timeline.xctimeline
playground.xcworkspace

# macOS
.DS_Store

# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
Package.resolved
.swiftpm
.build/
# We do not need the project, because it can be generated or the Package.swift can be open in Xcode 11
.swiftpm/
Package.resolved
FTAPIKit.xcodeproj

# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/

# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts

Carthage/Build

# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/#source-control

fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output
fastlane/README.md
# Claude Code
.claude

# Ignore VSCode files
.vscode
*.xcuserstate
18 changes: 0 additions & 18 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
disabled_rules:
- line_length
# Combination of SwiftLint 0.43.1 and Xcode 12.5.1
# warns about false positives for this rule
- empty_xctest_method
# Type inference of `await try` methods
# does not work well in Xcode 13 Beta
- implicit_return
# Does not work with URL query literals.
- duplicated_key_in_dictionary_literal
excluded:
- Pods
- .build
- Templates
opt_in_rules:
- anyobject_protocol
- array_init
- attributes
- closure_body_length
Expand All @@ -26,12 +18,10 @@ opt_in_rules:
- contains_over_first_not_nil
- contains_over_range_nil_comparison
- convenience_type
- discouraged_object_literal
- discouraged_optional_boolean
- empty_collection_literal
- empty_count
- empty_string
- empty_xctest_method
- enum_case_associated_values_count
- explicit_init
- fallthrough
Expand All @@ -55,22 +45,17 @@ opt_in_rules:
- multiline_literal_brackets
- multiline_parameters
- multiline_parameters_brackets
- nimble_operator
- number_separator
- object_literal
- operator_usage_whitespace
- optional_enum_case_matching
- overridden_super_call
- override_in_extension
- pattern_matching_keywords
- prefer_self_type_over_type_of_self
- private_action
- private_outlet
- prohibited_super_call
- reduce_into
- redundant_nil_coalescing
- required_enum_case
- single_test_class
- sorted_first_last
- sorted_imports
- static_operator
Expand All @@ -80,12 +65,9 @@ opt_in_rules:
- trailing_closure
- unneeded_parentheses_in_closure_argument
- untyped_error_in_catch
- unused_declaration
- unused_import
- vertical_parameter_alignment_on_call
- vertical_whitespace_closing_braces
- yoda_condition

# Rule configurations
identifier_name:
excluded:
Expand Down
152 changes: 152 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

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.

**Key Features:**
- Declarative async/await API for defining web services
- Protocol-oriented design with `URLServer` and `Endpoint` protocols
- Multiple endpoint types for different use cases (GET, POST, multipart uploads, etc.)
- Async buildRequest enabling token refresh, dynamic configuration, and rate limiting
- `RequestConfiguring` protocol for per-request configuration at call site
- `NetworkObserver` protocol for request lifecycle monitoring (logging, analytics)
- Swift 6 concurrency safety with Sendable requirements
- Cross-platform support: iOS 15+, macOS 12+, tvOS 15+, watchOS 8+

## Build and Test Commands

### Building
```bash
# Use xcodebuild (preferred, avoids toolchain mismatch issues)
xcodebuild build -scheme FTAPIKit -destination 'platform=macOS'

# Or with Swift CLI
swift build
```

### Running Tests
```bash
# Use xcodebuild
xcodebuild test -scheme FTAPIKit -destination 'platform=macOS'

# Or with Swift CLI
swift test
```

### Linting
```bash
# Run SwiftLint with strict mode
swiftlint --strict
```

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.

## Architecture

### Core Protocol Design

The framework is built around two core protocols:

1. **`URLServer` Protocol** - Represents a single web service
- Defines `baseUri`, `urlSession`, `encoding`/`decoding`, `networkObservers`
- Builds requests from endpoints via `buildRequest(endpoint:) async throws`
- Provides default implementations for all properties except `baseUri`
- Has `ErrorType` associated type (defaults to `APIError.Standard`)

2. **`Endpoint` Protocol** - Represents access points for resources
- Defines path, headers, query parameters, and HTTP method
- Multiple specialized variants for different use cases

### Endpoint Type Hierarchy

- **`Endpoint`** - Base protocol with empty body (typically for GET requests)
- **`DataEndpoint`** - Sends raw data in body
- **`UploadEndpoint`** - Uploads files using URLSession upload
- **`MultipartEndpoint`** - Combines body parts into multipart request
- **`URLEncodedEndpoint`** - Body in URL query format
- **`RequestEndpoint`** - Has encodable request model (defaults to POST)
- **`ResponseEndpoint`** - Has decodable response model
- **`RequestResponseEndpoint`** - Typealias combining request and response endpoints

### Key Architectural Patterns

**URLServer Protocol**: The `URLServer` protocol provides all URLSession-based functionality with default implementations. Only `baseUri` must be provided by conforming types.

**Network Observers**: The `NetworkObserver` protocol provides lifecycle callbacks (`willSendRequest`, `didReceiveResponse`, `didFail`) with type-safe context passing. Observer integration uses `BoundObserverContext` (private) for type erasure.

**Request Configuration**: The `RequestConfiguring` protocol allows per-request async configuration at the call site, separate from server-level `buildRequest`.

**Encoding/Decoding**: The `Encoding` protocol includes `configure(request:)` for setting content-type headers (with empty default). Both `Encoding` and `Decoding` require `Sendable`.

**Swift 6 Concurrency Safety**: All `ResponseEndpoint` associated types must conform to `Sendable`.

### Module Organization

**Source Structure** (`Sources/FTAPIKit/`):
- Core protocols: `URLServer.swift`, `Endpoint.swift`
- Request building: `URLRequestBuilder.swift`, `RequestConfiguring.swift`
- Async execution: `URLServer+Async.swift` (includes download)
- Observers: `NetworkObserver.swift`
- Utilities: `Coding.swift`, `URLQuery.swift`, `MultipartFormData.swift`, etc.
- Error handling: `APIError.swift`, `APIError+Standard.swift`

**Test Structure** (`Tests/FTAPIKitTests/`):
- Uses Swift Testing framework (`@Suite`, `@Test`, `#expect`)
- Test files: `AsyncTests.swift`, `AsyncBuildRequestTests.swift`, `URLQueryTests.swift`, `NetworkObserverTests.swift`, `RequestConfiguringTests.swift`, `EndpointTypeTests.swift`, `ErrorHandlingTests.swift`
- Test utilities in `Mockups/`: `Servers.swift`, `Endpoints.swift`, `Models.swift`, `Errors.swift`, `MockNetworkObserver.swift`, `MockTokenManager.swift`, `HTTPBinResponse.swift`

### Call Execution Pattern

The framework uses async/await exclusively:

```swift
// Basic call
let response = try await server.call(response: endpoint)

// Data call (raw Data response)
let data = try await server.call(data: endpoint)

// Void call (no response body)
try await server.call(endpoint: endpoint)

// Download call
let fileURL = try await server.download(endpoint: endpoint)
```

### Error Handling

- `APIError` protocol defines error handling interface
- Default implementation: `APIError.Standard` (enum with connection, encoding, decoding, server, client, unhandled cases)
- Network errors (`URLError`) and decoding errors are routed through `ErrorType` for consistent error handling
- Encoding errors (from `buildStandardRequest`) propagate directly as `EncodingError` since they occur before the network request
- Custom error types can be defined via `URLServer.ErrorType` associated type

## Package Management

The project uses **Swift Package Manager** exclusively. See `Package.swift`.

### Platform Support

Minimum deployment targets:
- iOS 15+
- macOS 12+
- tvOS 15+
- watchOS 8+

## Testing Approach

Tests use Swift Testing framework and mock servers (HTTPBin-based) defined in `Tests/FTAPIKitTests/Mockups/Servers.swift`:
- `HTTPBinServer` - Standard test server with async authorization support
- `NonExistingServer` - For testing error conditions
- `ErrorThrowingServer` - Custom error type testing
- `HTTPBinServerWithObservers` - Observer integration testing

## CI/CD

Single GitHub Actions workflow (`ci.yml`) runs on `macos-latest`:
- `swiftlint --strict`
- `swift build`
- `swift test`
Loading