https://github.com/rryam/ghostingkit
Unofficial Swift SDK for Ghost API
https://github.com/rryam/ghostingkit
ghost ghost-blog ios ios-development swift swiftui
Last synced: 10 months ago
JSON representation
Unofficial Swift SDK for Ghost API
- Host: GitHub
- URL: https://github.com/rryam/ghostingkit
- Owner: rryam
- License: mit
- Created: 2024-10-15T18:22:00.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-01-30T10:50:57.000Z (over 1 year ago)
- Last Synced: 2025-04-11T01:45:33.609Z (about 1 year ago)
- Topics: ghost, ghost-blog, ios, ios-development, swift, swiftui
- Language: Swift
- Homepage:
- Size: 47.9 KB
- Stars: 4
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# GhostingKit
A modern, type-safe Swift library for interacting with the Ghost Content API. GhostingKit provides a comprehensive set of tools for building Ghost-powered applications with features like caching, retry logic, request cancellation, and more.
## Features
- ✅ **Complete Ghost Content API Coverage**: Posts, pages, authors, tags, tiers, and settings
- ✅ **Type-Safe**: Strongly typed models with proper Swift types (Date, optionals, etc.)
- ✅ **Modern Swift**: Built with async/await, actors, and Swift 5.9+ features
- ✅ **Caching**: Built-in caching with configurable TTL and LRU eviction
- ✅ **Retry Logic**: Configurable exponential backoff for failed requests
- ✅ **Request Cancellation**: Cancel individual requests or all active requests
- ✅ **Pagination**: Helper utilities for paginated content and streaming
- ✅ **Error Handling**: Comprehensive error types with detailed messages
- ✅ **Security**: Secure configuration loading from Bundle, environment, or JSON
- ✅ **SwiftUI Ready**: Complete example app with navigation and detail views
## Requirements
- iOS 15.0+ / macOS 12.0+ / tvOS 15.0+ / watchOS 8.0+
- Swift 5.9+
- Xcode 15.0+
## Installation
### Swift Package Manager
Add GhostingKit to your project using Swift Package Manager:
```swift
dependencies: [
.package(url: "https://github.com/your-username/GhostingKit.git", from: "1.0.0")
]
```
## Quick Start
### Basic Usage
```swift
import GhostingKit
// Initialize with your Ghost site credentials
let ghostingKit = try GhostingKit(
adminDomain: "your-site.ghost.io",
apiKey: "your-content-api-key"
)
// Fetch posts
let posts = try await ghostingKit.getPosts(limit: 10)
print("Found \(posts.posts.count) posts")
// Fetch a specific post
let post = try await ghostingKit.getPost(id: "post-id")
print("Post title: \(post.title)")
```
### Secure Configuration
#### From Info.plist
Add these keys to your `Info.plist`:
```xml
GhostAdminDomain
your-site.ghost.io
GhostAPIKey
your-content-api-key
```
```swift
let configuration = try GhostingKitConfiguration.fromBundle()
let ghostingKit = try GhostingKit(configuration: configuration)
```
#### From Environment Variables
```bash
export GHOST_ADMIN_DOMAIN="your-site.ghost.io"
export GHOST_API_KEY="your-content-api-key"
```
```swift
let configuration = try GhostingKitConfiguration.fromEnvironment()
let ghostingKit = try GhostingKit(configuration: configuration)
```
## API Reference
### Posts
```swift
// Get all posts
let posts = try await ghostingKit.getPosts(limit: 15, page: 1)
// Get posts with authors and tags included
let postsWithAuthors = try await ghostingKit.getPosts(
limit: 10,
include: "authors,tags"
)
// Filter posts by tag
let swiftPosts = try await ghostingKit.getPosts(
filter: "tag:swift",
include: "authors,tags"
)
// Get a specific post
let post = try await ghostingKit.getPost(id: "post-id")
let postBySlug = try await ghostingKit.getPostBySlug(slug: "post-slug")
```
### Authors
```swift
// Get all authors
let authors = try await ghostingKit.getAuthors()
// Get a specific author
let author = try await ghostingKit.getAuthor(id: "author-id")
let authorBySlug = try await ghostingKit.getAuthorBySlug(slug: "author-slug")
```
### Tags
```swift
// Get all tags
let tags = try await ghostingKit.getTags()
// Get public tags only
let publicTags = try await ghostingKit.getTags(filter: "visibility:public")
// Get a specific tag
let tag = try await ghostingKit.getTag(id: "tag-id")
let tagBySlug = try await ghostingKit.getTagBySlug(slug: "tag-slug")
```
### Pages
```swift
// Get all pages
let pages = try await ghostingKit.getPages()
// Get a specific page
let page = try await ghostingKit.getPage(id: "page-id")
let pageBySlug = try await ghostingKit.getPageBySlug(slug: "page-slug")
```
### Settings
```swift
// Get site settings
let settings = try await ghostingKit.getSettings()
print("Site title: \(settings.title)")
print("Site description: \(settings.description)")
```
### Tiers (Membership)
```swift
// Get membership tiers
let tiers = try await ghostingKit.getTiers()
// Get a specific tier
let tier = try await ghostingKit.getTier(id: "tier-id")
```
## Advanced Features
### Caching
```swift
// Configure caching
let cacheConfig = GhostingKitCacheConfiguration(
ttl: 300, // 5 minutes
maxItems: 100, // Maximum 100 cached items
isEnabled: true
)
let config = GhostingKitConfiguration(
adminDomain: "your-site.ghost.io",
apiKey: "your-api-key",
cacheConfiguration: cacheConfig
)
let ghostingKit = try GhostingKit(configuration: config)
// Clear cache when needed
await ghostingKit.clearCache()
```
### Retry Logic
```swift
// Configure retry behavior
let retryConfig = GhostingKitRetryConfiguration(
maxAttempts: 3,
baseDelay: 1.0,
useExponentialBackoff: true,
maxDelay: 60.0,
retryableStatusCodes: [408, 429, 500, 502, 503, 504]
)
let config = GhostingKitConfiguration(
adminDomain: "your-site.ghost.io",
apiKey: "your-api-key",
retryConfiguration: retryConfig
)
```
### Request Cancellation
```swift
// Cancellable requests
let cancellableRequest = await ghostingKit.getPostsCancellable(limit: 10)
// Cancel the specific request
cancellableRequest.cancel()
// Or cancel all active requests
await ghostingKit.cancelAllRequests()
// Get the result
do {
let posts = try await cancellableRequest.task.value
print("Got \(posts.posts.count) posts")
} catch {
print("Request failed or was cancelled: \(error)")
}
```
### Pagination
```swift
// Use pagination helpers
let posts = try await ghostingKit.getPosts(limit: 10, page: 1)
if let pagination = posts.pagination {
print("Page \(pagination.currentPage) of \(pagination.totalPages)")
print("Total posts: \(pagination.totalCount)")
if pagination.hasNextPage {
let nextPage = try await ghostingKit.getPosts(limit: 10, page: pagination.nextPage!)
}
}
// Get all posts across multiple pages
let allPosts = try await ghostingKit.getAllPosts(pageSize: 15, maxPages: 5)
// Stream posts for memory efficiency
for try await post in ghostingKit.postsStream(pageSize: 10) {
print("Processing post: \(post.title)")
}
```
## Error Handling
GhostingKit provides comprehensive error handling with detailed error types:
```swift
do {
let posts = try await ghostingKit.getPosts()
} catch GhostingKitError.invalidURL(let url) {
print("Invalid URL: \(url)")
} catch GhostingKitError.httpError(let statusCode, let message) {
print("HTTP \(statusCode): \(message ?? "Unknown error")")
} catch GhostingKitError.resourceNotFound(let type, let identifier) {
print("\(type) with ID \(identifier) not found")
} catch GhostingKitError.networkError(let error) {
print("Network error: \(error)")
} catch GhostingKitError.cancelled {
print("Request was cancelled")
} catch GhostingKitError.timeout {
print("Request timed out")
} catch {
print("Unknown error: \(error)")
}
```
## SwiftUI Integration
GhostingKit works seamlessly with SwiftUI. Check out the included example app for complete implementations of:
- 📱 Posts list with navigation to detail views
- 👤 Authors list with author detail views
- 🏷️ Tags list with tag detail views
- 📄 Pages list with page detail views
- 🔍 Full-text search and filtering
- ⚡ Async image loading
- 🎨 Modern SwiftUI design patterns
## Example Views
### Posts List
```swift
struct PostsView: View {
@State private var posts: [GhostPost] = []
let ghostingKit: GhostingKit
var body: some View {
List(posts, id: \.id) { post in
NavigationLink(destination: PostDetailView(post: post)) {
VStack(alignment: .leading) {
Text(post.title)
.font(.headline)
Text(post.excerpt ?? "")
.font(.subheadline)
.foregroundColor(.secondary)
}
}
}
.task {
do {
let response = try await ghostingKit.getPosts(include: "authors,tags")
posts = response.posts
} catch {
print("Error loading posts: \(error)")
}
}
}
}
```
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
### Development Setup
1. Clone the repository
2. Open `Package.swift` in Xcode
3. Run tests with ⌘+U
4. Check out the example app in the `Ghosting` folder
### Running Tests
```bash
# Run all tests
swift test
# Run only unit tests (no network required)
swift test --filter MockGhostingKitTests
# Run integration tests (requires network)
swift test --filter integration
```
## License
GhostingKit is available under the MIT license. See the [LICENSE](LICENSE) file for more info.
## Ghost Content API
This library interacts with the Ghost Content API. For more information about Ghost and its API, visit:
- [Ghost Official Website](https://ghost.org)
- [Ghost Content API Documentation](https://ghost.org/docs/content-api/)
- [Ghost Admin API Documentation](https://ghost.org/docs/admin-api/)
## Changelog
### 1.0.0
- Initial release
- Complete Ghost Content API coverage
- SwiftUI example app
- Comprehensive test suite
- Modern Swift async/await support
- Caching, retry logic, and request cancellation
- Type-safe models with proper Date handling
- Secure configuration management