A modern Swift package for interacting with the Google Blogger API v3, built with Swift Concurrency (async/await) and actors for thread-safe operations.
- ✨ Modern Swift Concurrency - Built with async/await and actors
- 🔒 Thread-Safe - All types are
Sendableand use actor isolation - 📅 Date Filtering - Filter posts by published date (before/after)
- 🔍 Type-Safe - Leverages Swift's type system with Codable models
- 🪵 Debug Logging - Integrated OSLog for network request debugging
- 🧪 Well Tested - Comprehensive test coverage
- 🎯 Simple API - Clean, intuitive interface
- macOS 13.0+
- Swift 6.2+
- Xcode 16.0+
Add the following to your Package.swift:
dependencies: [
.package(url: "https://github.com/coodly/BloggerAPI.git", from: "0.2.0")
]Or add it via Xcode:
- File → Add Package Dependencies...
- Enter the repository URL
- Select version requirements
import BloggerAPI
// Create a Blogger instance
let blogger = Blogger(
blogURL: "https://your-blog.blogspot.com",
key: "YOUR_GOOGLE_API_KEY"
)
// Fetch posts
let posts = try await blogger.fetchPosts()
for post in posts {
print("\(post.title ?? "Untitled")")
print("\(post.published)")
}Fetch all posts from your blog:
let blogger = Blogger(blogURL: "https://your-blog.blogspot.com", key: "YOUR_API_KEY")
let posts = try await blogger.fetchPosts()Fetch posts published after a specific date:
let calendar = Calendar.current
let afterDate = calendar.date(from: DateComponents(year: 2024, month: 1, day: 1))!
let posts = try await blogger.fetchPosts(publishedAfter: afterDate)Fetch posts published before a specific date:
let beforeDate = calendar.date(from: DateComponents(year: 2024, month: 12, day: 31))!
let posts = try await blogger.fetchPosts(publishedBefore: beforeDate)Fetch posts within a date range:
let afterDate = calendar.date(from: DateComponents(year: 2024, month: 6, day: 1))!
let beforeDate = calendar.date(from: DateComponents(year: 2024, month: 6, day: 30))!
let posts = try await blogger.fetchPosts(
publishedAfter: afterDate,
publishedBefore: beforeDate
)Provide your own network implementation for custom behavior (e.g., caching, request modification):
let customFetch = NetworkFetch { request in
// Add custom headers, logging, etc.
var modifiedRequest = request
modifiedRequest.addValue("MyApp/1.0", forHTTPHeaderField: "User-Agent")
return try await URLSession.shared.data(for: modifiedRequest)
}
let blogger = Blogger(
blogURL: "https://your-blog.blogspot.com",
key: "YOUR_API_KEY",
fetch: customFetch
)The main actor for interacting with the Blogger API.
public actor Blogger {
public init(blogURL: String, key: String, fetch: NetworkFetch = .default)
public func fetchPosts(
publishedAfter: Date? = nil,
publishedBefore: Date? = nil
) async throws -> [Post]
}Represents a blog post.
public struct Post: Codable, Sendable {
public let id: String
public let blog: Blog?
public let published: Date
public let title: String?
public let content: String?
public let images: [Image]?
public let url: URL?
}Struct for handling network requests. Use .default for standard URLSession behavior or provide a custom implementation.
public struct NetworkFetch: Sendable {
public init(fetch: @escaping @Sendable (URLRequest) async throws -> (Data, URLResponse))
public static var `default`: NetworkFetch
public func fetch(request: URLRequest) async throws -> (Data, URLResponse)
}Errors that can occur during API operations.
public enum BloggerError: Error {
case noData
case invalidJSON(Error)
}The library uses OSLog for debug logging. To view network request logs:
Via Console.app:
- Open Console.app
- Filter by subsystem:
com.coodly.BloggerAPI
Via Terminal:
log stream --predicate 'subsystem == "com.coodly.BloggerAPI"' --level debugLog levels:
- Info: High-level operations (fetching posts, blog ID resolution)
- Debug: Network requests, responses, date filters
- Error: JSON decode errors and network failures
- Go to the Google Cloud Console
- Create a new project or select an existing one
- Enable the Blogger API v3
- Go to "Credentials" and create an API key
- Restrict the key to the Blogger API for security
The library uses modern Swift Concurrency features:
- Actors -
BloggerandAPIClientare actors for thread-safe state management - Sendable Types - All public types conform to
Sendablefor safe concurrent access - Async/Await - All API calls use async/await for clean, sequential code
- Structured Concurrency - Proper error handling and cancellation support
BloggerAPI/
├── Blogger.swift # Main public interface (actor)
├── APIClient.swift # API communication layer (actor)
├── NetworkFetch.swift # Network abstraction
├── Models/
│ ├── Post.swift # Post data model
│ ├── Blog.swift # Blog data model
│ ├── Image.swift # Image data model
│ └── PostsPage.swift # Pagination response
├── BloggerError.swift # Error types
└── Logger.swift # OSLog configuration
Run tests with Swift Package Manager:
swift testThe library includes comprehensive tests covering:
- Blog ID resolution
- Post fetching
- Date filtering (after, before, ranges)
- RFC3339 date format compliance
- Network request construction
Version 0.2.0+ uses async/await instead of callbacks:
Before (v0.1.x):
let blogger = Blogger(blogURL: url, key: key, fetch: fetch)
blogger.fetchUpdates(after: date) { result in
// Handle result
}After (v0.2.0+):
let blogger = Blogger(blogURL: url, key: key)
let posts = try await blogger.fetchPosts(publishedAfter: date)This project is licensed under the Apache License 2.0. See the LICENSE file for details.
Copyright 2016 Coodly LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
- Built with Swift Concurrency best practices
- Uses the Google Blogger API v3
- Follows RFC3339 date formatting standards