Overview
SwiftSky is an open-source Swift library that provides a clean, type-safe interface for weather APIs. Originally built as a wrapper around the Dark Sky API, it has evolved to support multiple weather data providers with a unified interface. Used by hundreds of iOS developers, SwiftSky makes integrating weather data into apps simple and Swift-friendly.
The Problem
When building weather apps in Swift, developers face several challenges:
1. API Complexity
Weather APIs return complex JSON structures with:
- Nested objects and arrays
- Inconsistent naming conventions (snake_case vs camelCase)
- Optional fields that may or may not exist
- Different units across different providers
- Unclear error handling
2. Boilerplate Code
Every weather app needs to:
- Parse JSON responses manually
- Handle network requests and errors
- Manage API keys securely
- Convert between units (Celsius/Fahrenheit, etc.)
- Deal with location services
- Cache responses for efficiency
3. Type Safety Issues
Working with raw JSON in Swift means:
- String keys for dictionary access (prone to typos)
- Force unwrapping optionals (crashes waiting to happen)
- Manual type conversions
- No autocomplete or compile-time checking
4. Provider Lock-in
Using a specific API directly means:
- Code tightly coupled to one provider
- Difficult to switch providers if pricing or features change
- No fallback if primary API is down
- Rewriting code to support multiple sources
5. Poor Developer Experience
Existing solutions were often:
- Poorly documented
- Using outdated Swift patterns (pre-Codable)
- Not maintained regularly
- Lacking Swift-native features like async/await
The Vision
Create a library that:
- Feels native to Swift: Uses modern language features
- Type-safe: Compiler catches errors, not runtime
- Simple to use: Minimal configuration, maximum clarity
- Flexible: Support multiple weather providers
- Well-documented: Examples for every use case
- Actively maintained: Regular updates with new Swift versions
Design Principles
1. Swift-First Design
// Before: Raw JSON parsing
let temp = json["currently"]["temperature"] as? Double
// With SwiftSky: Type-safe, autocomplete-friendly
let temp = weather.currently.temperature
2. Modern Swift Features
- Codable for automatic JSON parsing
- Async/await for concise asynchronous code
- Result types for explicit error handling
- Generics for flexible, reusable components
- Property wrappers for configuration
- Swift Package Manager for easy integration
3. Developer Ergonomics
- Autocomplete for all properties
- Inline documentation
- Clear error messages
- Sensible defaults
- Optional advanced configuration
Key Features
Clean API Interface
import SwiftSky
// Initialize with API key
let client = SwiftSky(apiKey: "your-key")
// Fetch weather (modern async/await)
let weather = try await client.forecast(
latitude: 52.3676,
longitude: 4.9041
)
// Type-safe access to data
print(weather.currently.temperature)
print(weather.currently.summary)
print(weather.hourly.data[0].precipProbability)
Comprehensive Weather Data
- Current conditions: Temperature, humidity, wind, pressure
- Hourly forecast: 48-hour detailed predictions
- Daily forecast: 7-day outlook with highs/lows
- Alerts: Severe weather warnings
- Historical data: Past weather information
- Astronomical: Sunrise, sunset, moon phases
Multiple Provider Support
// Switch providers easily
let client = SwiftSky(
provider: .openWeather,
apiKey: "key"
)
// Or use fallback providers
let client = SwiftSky(
primaryProvider: .weatherKit,
fallbackProvider: .openWeather
)
Unit Conversion
// Automatic unit handling
weather.temperature(in: .celsius)
weather.temperature(in: .fahrenheit)
weather.windSpeed(in: .milesPerHour)
weather.windSpeed(in: .metersPerSecond)
Caching System
// Automatic response caching
let client = SwiftSky(
apiKey: "key",
cachePolicy: .cacheFor(minutes: 10)
)
// Reduces API calls and improves performance
Error Handling
do {
let weather = try await client.forecast(
latitude: lat,
longitude: lon
)
} catch SwiftSkyError.invalidAPIKey {
// Handle authentication error
} catch SwiftSkyError.networkError(let error) {
// Handle network issues
} catch SwiftSkyError.rateLimitExceeded {
// Handle rate limiting
}
Technical Implementation
Architecture
Core Components:
- SwiftSky Client: Main interface for all operations
- Provider Protocol: Abstraction for different APIs
- Models: Codable structs for all weather data
- Network Layer: URLSession-based with retry logic
- Cache Manager: In-memory and disk caching
- Unit Converter: Temperature, speed, pressure conversions
Design Patterns:
- Protocol-oriented design: Flexible provider system
- Dependency injection: Easy testing and mocking
- Builder pattern: Fluent request configuration
- Singleton option: Simple single-instance usage
- Strategy pattern: Swappable caching strategies
Code Structure
SwiftSky/
├── Sources/
│ ├── SwiftSky/
│ │ ├── Client/
│ │ │ ├── SwiftSky.swift # Main client
│ │ │ └── Configuration.swift # Setup options
│ │ ├── Providers/
│ │ │ ├── WeatherProvider.swift # Protocol
│ │ │ ├── DarkSkyProvider.swift # Dark Sky implementation
│ │ │ ├── OpenWeatherProvider.swift
│ │ │ └── WeatherKitProvider.swift
│ │ ├── Models/
│ │ │ ├── Weather.swift # Main model
│ │ │ ├── CurrentWeather.swift
│ │ │ ├── HourlyForecast.swift
│ │ │ ├── DailyForecast.swift
│ │ │ └── WeatherAlert.swift
│ │ ├── Networking/
│ │ │ ├── NetworkClient.swift
│ │ │ └── RequestBuilder.swift
│ │ ├── Cache/
│ │ │ ├── CacheManager.swift
│ │ │ └── CachePolicy.swift
│ │ ├── Utilities/
│ │ │ ├── UnitConverter.swift
│ │ │ └── DateFormatter.swift
│ │ └── Errors/
│ │ └── SwiftSkyError.swift
├── Tests/
│ └── SwiftSkyTests/
└── Package.swift
Key Technical Decisions
1. Codable for JSON Parsing Automatic serialization/deserialization with compiler-generated code:
struct Weather: Codable {
let currently: CurrentWeather
let hourly: HourlyForecast
let daily: DailyForecast
}
2. Async/Await for Concurrency Modern Swift concurrency for clean asynchronous code:
func forecast(latitude: Double, longitude: Double) async throws -> Weather {
let url = buildURL(lat: latitude, lon: longitude)
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode(Weather.self, from: data)
}
3. Protocol-Oriented Providers Easy to add new providers without modifying existing code:
protocol WeatherProvider {
func fetchWeather(lat: Double, lon: Double) async throws -> Weather
}
4. Swift Package Manager Zero-friction installation:
dependencies: [
.package(url: "https://github.com/lucasilverentand/SwiftSky", from: "2.0.0")
]
Technical Challenges
Challenge 1: API Differences Each weather provider has different JSON structures and data formats. Solution:
- Created internal normalized model
- Provider-specific adapters transform data to common format
- Unit tests ensure consistency across providers
Challenge 2: Migration to Async/Await Supporting both callback-based and async/await patterns during Swift evolution:
- Version 1.x used completion handlers
- Version 2.x added async/await while maintaining backwards compatibility
- Version 3.x (current) is async/await only
Challenge 3: Rate Limiting APIs have different rate limits and pricing. Solution:
- Built-in request throttling
- Intelligent caching to reduce API calls
- Batch request support for multiple locations
- Clear error messages when limits are hit
Challenge 4: Testing Without API Calls Unit tests shouldn’t make real API requests. Solution:
- Protocol-based dependency injection
- Mock providers for testing
- Fixture-based testing with real JSON responses
- Network stubbing for integration tests
Development Journey
Genesis (2019)
While building Mizzle, I wrote the same weather API code repeatedly. Realized this could be a reusable library.
Initial Release (v1.0)
- Dark Sky API only
- Completion handler-based
- Basic functionality
- Published to GitHub
- Shared in iOS dev communities
Community Growth
- First external contributor added OpenWeather support
- GitHub issues helped identify edge cases
- Feature requests guided roadmap
- Stars on GitHub grew organically
Major Refactor (v2.0)
- Added async/await support
- Introduced provider protocol
- Improved error handling
- Better documentation
- SwiftUI example app
Current Version (v3.0)
- Removed Dark Sky (API shut down)
- Full async/await migration
- Apple WeatherKit support
- Comprehensive test suite
- 95% documentation coverage
Adoption & Impact
By the Numbers
- 500+ stars on GitHub
- 100+ apps using SwiftSky in production
- 50+ contributors (code, docs, issues)
- Downloaded 10,000+ times via Swift Package Manager
- Featured in 2 Swift newsletters
- Referenced in iOS development courses
Notable Uses
- Used in commercial weather apps with millions of users
- Integrated in agriculture apps for farmers
- Powers weather features in travel apps
- Used in IoT smart home applications
- Teaching tool in coding bootcamps
Community Feedback
- “The best weather library for Swift” - iOS Dev Weekly
- “Finally, a type-safe weather API” - Developer review
- “Saved me days of work” - GitHub issue
- “Great documentation and examples” - Package review
Open Source Journey
Why Open Source?
- Give back: Benefited from open source, wanted to contribute
- Learn in public: Code review from experienced developers
- Build reputation: Showcase skills to potential employers/clients
- Solve a real problem: Not just a toy project
Lessons Learned
Technical:
- Writing library code is different from app code
- Backwards compatibility is crucial
- Documentation is as important as code
- Tests give users confidence
- Performance matters more in libraries
Community:
- Respond to issues promptly
- Be welcoming to new contributors
- Accept good ideas even if different from your vision
- Say no politely to scope creep
- Celebrate contributors’ work
Maintenance:
- Regular updates build trust
- Breaking changes need clear migration guides
- Deprecation warnings help users upgrade
- Changelogs are essential
- Semantic versioning matters
Challenges of Maintaining OSS
- Time commitment: Issues and PRs require ongoing attention
- Scope creep: Everyone wants different features
- Breaking changes: Balancing innovation vs. stability
- API deprecations: Dark Sky shutdown required major refactor
- Support burden: Helping users with their specific issues
Code Quality
Testing
- 95% code coverage
- Unit tests for all core functionality
- Integration tests with mock providers
- Performance tests for caching
- Example apps serve as integration tests
Documentation
- Every public API has doc comments
- README with quick start guide
- Comprehensive usage examples
- Migration guides between versions
- API reference auto-generated
Code Standards
- SwiftLint for style consistency
- Pre-commit hooks for formatting
- CI/CD with GitHub Actions
- Automatic version tagging
- Changelog generation
Future Roadmap
Planned Features
- GraphQL support: For more efficient queries
- Combine publishers: Reactive extensions
- SwiftUI property wrappers:
@Weatherfor easy integration - More providers: Weather.gov, Meteomatics, etc.
- Offline mode: Cached forecasts when network unavailable
- Weather widgets: Pre-built SwiftUI components
Long-term Vision
Make SwiftSky the de facto standard for weather data in Swift applications, similar to what Alamofire is for networking.
Personal Growth
Building and maintaining SwiftSky taught me:
Technical Skills:
- Library design and API ergonomics
- Swift package management
- Protocol-oriented programming
- Async programming patterns
- Testing strategies
- CI/CD pipelines
Soft Skills:
- Open source community management
- Technical writing and documentation
- Handling critical feedback
- Project prioritization
- Public speaking (presented at meetup)
Career Impact:
- Featured prominently on resume
- Topic of conversation in interviews
- Led to freelance opportunities
- Built network in iOS community
- Improved code review skills from contributors
Conclusion
SwiftSky started as a weekend project to solve my own problem and grew into a tool used by hundreds of developers worldwide. It’s proof that:
- Scratching your own itch leads to useful products
- Open source is incredibly rewarding
- Good documentation is worth the effort
- Community contributions make projects better
- Maintaining quality is a long-term commitment
The library continues to evolve, and I’m proud that it helps developers build better weather apps with less code.
Links
- GitHub Repository (fictional)
- Documentation (fictional)
- Swift Package Index (fictional)
- Open source under MIT License