{"id":18060203,"url":"https://github.com/rryam/ghostingkit","last_synced_at":"2025-08-07T14:33:14.251Z","repository":{"id":257936305,"uuid":"873180165","full_name":"rryam/GhostingKit","owner":"rryam","description":"Unofficial Swift SDK for Ghost API","archived":false,"fork":false,"pushed_at":"2025-01-30T10:50:57.000Z","size":49,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-11T01:45:33.609Z","etag":null,"topics":["ghost","ghost-blog","ios","ios-development","swift","swiftui"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rryam.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-15T18:22:00.000Z","updated_at":"2025-04-04T12:48:16.000Z","dependencies_parsed_at":"2024-10-19T10:37:50.165Z","dependency_job_id":null,"html_url":"https://github.com/rryam/GhostingKit","commit_stats":null,"previous_names":["rudrankriyam/phantomkit","rryam/phantomkit"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rryam%2FGhostingKit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rryam%2FGhostingKit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rryam%2FGhostingKit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rryam%2FGhostingKit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rryam","download_url":"https://codeload.github.com/rryam/GhostingKit/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248398368,"owners_count":21097291,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ghost","ghost-blog","ios","ios-development","swift","swiftui"],"created_at":"2024-10-31T04:06:27.035Z","updated_at":"2025-07-12T03:42:36.592Z","avatar_url":"https://github.com/rryam.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GhostingKit\n\nA 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.\n\n## Features\n\n- ✅ **Complete Ghost Content API Coverage**: Posts, pages, authors, tags, tiers, and settings\n- ✅ **Type-Safe**: Strongly typed models with proper Swift types (Date, optionals, etc.)\n- ✅ **Modern Swift**: Built with async/await, actors, and Swift 5.9+ features\n- ✅ **Caching**: Built-in caching with configurable TTL and LRU eviction\n- ✅ **Retry Logic**: Configurable exponential backoff for failed requests\n- ✅ **Request Cancellation**: Cancel individual requests or all active requests\n- ✅ **Pagination**: Helper utilities for paginated content and streaming\n- ✅ **Error Handling**: Comprehensive error types with detailed messages\n- ✅ **Security**: Secure configuration loading from Bundle, environment, or JSON\n- ✅ **SwiftUI Ready**: Complete example app with navigation and detail views\n\n## Requirements\n\n- iOS 15.0+ / macOS 12.0+ / tvOS 15.0+ / watchOS 8.0+\n- Swift 5.9+\n- Xcode 15.0+\n\n## Installation\n\n### Swift Package Manager\n\nAdd GhostingKit to your project using Swift Package Manager:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/your-username/GhostingKit.git\", from: \"1.0.0\")\n]\n```\n\n## Quick Start\n\n### Basic Usage\n\n```swift\nimport GhostingKit\n\n// Initialize with your Ghost site credentials\nlet ghostingKit = try GhostingKit(\n    adminDomain: \"your-site.ghost.io\",\n    apiKey: \"your-content-api-key\"\n)\n\n// Fetch posts\nlet posts = try await ghostingKit.getPosts(limit: 10)\nprint(\"Found \\(posts.posts.count) posts\")\n\n// Fetch a specific post\nlet post = try await ghostingKit.getPost(id: \"post-id\")\nprint(\"Post title: \\(post.title)\")\n```\n\n### Secure Configuration\n\n#### From Info.plist\n\nAdd these keys to your `Info.plist`:\n```xml\n\u003ckey\u003eGhostAdminDomain\u003c/key\u003e\n\u003cstring\u003eyour-site.ghost.io\u003c/string\u003e\n\u003ckey\u003eGhostAPIKey\u003c/key\u003e\n\u003cstring\u003eyour-content-api-key\u003c/string\u003e\n```\n\n```swift\nlet configuration = try GhostingKitConfiguration.fromBundle()\nlet ghostingKit = try GhostingKit(configuration: configuration)\n```\n\n#### From Environment Variables\n\n```bash\nexport GHOST_ADMIN_DOMAIN=\"your-site.ghost.io\"\nexport GHOST_API_KEY=\"your-content-api-key\"\n```\n\n```swift\nlet configuration = try GhostingKitConfiguration.fromEnvironment()\nlet ghostingKit = try GhostingKit(configuration: configuration)\n```\n\n## API Reference\n\n### Posts\n\n```swift\n// Get all posts\nlet posts = try await ghostingKit.getPosts(limit: 15, page: 1)\n\n// Get posts with authors and tags included\nlet postsWithAuthors = try await ghostingKit.getPosts(\n    limit: 10,\n    include: \"authors,tags\"\n)\n\n// Filter posts by tag\nlet swiftPosts = try await ghostingKit.getPosts(\n    filter: \"tag:swift\",\n    include: \"authors,tags\"\n)\n\n// Get a specific post\nlet post = try await ghostingKit.getPost(id: \"post-id\")\nlet postBySlug = try await ghostingKit.getPostBySlug(slug: \"post-slug\")\n```\n\n### Authors\n\n```swift\n// Get all authors\nlet authors = try await ghostingKit.getAuthors()\n\n// Get a specific author\nlet author = try await ghostingKit.getAuthor(id: \"author-id\")\nlet authorBySlug = try await ghostingKit.getAuthorBySlug(slug: \"author-slug\")\n```\n\n### Tags\n\n```swift\n// Get all tags\nlet tags = try await ghostingKit.getTags()\n\n// Get public tags only\nlet publicTags = try await ghostingKit.getTags(filter: \"visibility:public\")\n\n// Get a specific tag\nlet tag = try await ghostingKit.getTag(id: \"tag-id\")\nlet tagBySlug = try await ghostingKit.getTagBySlug(slug: \"tag-slug\")\n```\n\n### Pages\n\n```swift\n// Get all pages\nlet pages = try await ghostingKit.getPages()\n\n// Get a specific page\nlet page = try await ghostingKit.getPage(id: \"page-id\")\nlet pageBySlug = try await ghostingKit.getPageBySlug(slug: \"page-slug\")\n```\n\n### Settings\n\n```swift\n// Get site settings\nlet settings = try await ghostingKit.getSettings()\nprint(\"Site title: \\(settings.title)\")\nprint(\"Site description: \\(settings.description)\")\n```\n\n### Tiers (Membership)\n\n```swift\n// Get membership tiers\nlet tiers = try await ghostingKit.getTiers()\n\n// Get a specific tier\nlet tier = try await ghostingKit.getTier(id: \"tier-id\")\n```\n\n## Advanced Features\n\n### Caching\n\n```swift\n// Configure caching\nlet cacheConfig = GhostingKitCacheConfiguration(\n    ttl: 300,        // 5 minutes\n    maxItems: 100,   // Maximum 100 cached items\n    isEnabled: true\n)\n\nlet config = GhostingKitConfiguration(\n    adminDomain: \"your-site.ghost.io\",\n    apiKey: \"your-api-key\",\n    cacheConfiguration: cacheConfig\n)\n\nlet ghostingKit = try GhostingKit(configuration: config)\n\n// Clear cache when needed\nawait ghostingKit.clearCache()\n```\n\n### Retry Logic\n\n```swift\n// Configure retry behavior\nlet retryConfig = GhostingKitRetryConfiguration(\n    maxAttempts: 3,\n    baseDelay: 1.0,\n    useExponentialBackoff: true,\n    maxDelay: 60.0,\n    retryableStatusCodes: [408, 429, 500, 502, 503, 504]\n)\n\nlet config = GhostingKitConfiguration(\n    adminDomain: \"your-site.ghost.io\",\n    apiKey: \"your-api-key\",\n    retryConfiguration: retryConfig\n)\n```\n\n### Request Cancellation\n\n```swift\n// Cancellable requests\nlet cancellableRequest = await ghostingKit.getPostsCancellable(limit: 10)\n\n// Cancel the specific request\ncancellableRequest.cancel()\n\n// Or cancel all active requests\nawait ghostingKit.cancelAllRequests()\n\n// Get the result\ndo {\n    let posts = try await cancellableRequest.task.value\n    print(\"Got \\(posts.posts.count) posts\")\n} catch {\n    print(\"Request failed or was cancelled: \\(error)\")\n}\n```\n\n### Pagination\n\n```swift\n// Use pagination helpers\nlet posts = try await ghostingKit.getPosts(limit: 10, page: 1)\nif let pagination = posts.pagination {\n    print(\"Page \\(pagination.currentPage) of \\(pagination.totalPages)\")\n    print(\"Total posts: \\(pagination.totalCount)\")\n    \n    if pagination.hasNextPage {\n        let nextPage = try await ghostingKit.getPosts(limit: 10, page: pagination.nextPage!)\n    }\n}\n\n// Get all posts across multiple pages\nlet allPosts = try await ghostingKit.getAllPosts(pageSize: 15, maxPages: 5)\n\n// Stream posts for memory efficiency\nfor try await post in ghostingKit.postsStream(pageSize: 10) {\n    print(\"Processing post: \\(post.title)\")\n}\n```\n\n## Error Handling\n\nGhostingKit provides comprehensive error handling with detailed error types:\n\n```swift\ndo {\n    let posts = try await ghostingKit.getPosts()\n} catch GhostingKitError.invalidURL(let url) {\n    print(\"Invalid URL: \\(url)\")\n} catch GhostingKitError.httpError(let statusCode, let message) {\n    print(\"HTTP \\(statusCode): \\(message ?? \"Unknown error\")\")\n} catch GhostingKitError.resourceNotFound(let type, let identifier) {\n    print(\"\\(type) with ID \\(identifier) not found\")\n} catch GhostingKitError.networkError(let error) {\n    print(\"Network error: \\(error)\")\n} catch GhostingKitError.cancelled {\n    print(\"Request was cancelled\")\n} catch GhostingKitError.timeout {\n    print(\"Request timed out\")\n} catch {\n    print(\"Unknown error: \\(error)\")\n}\n```\n\n## SwiftUI Integration\n\nGhostingKit works seamlessly with SwiftUI. Check out the included example app for complete implementations of:\n\n- 📱 Posts list with navigation to detail views\n- 👤 Authors list with author detail views\n- 🏷️ Tags list with tag detail views\n- 📄 Pages list with page detail views\n- 🔍 Full-text search and filtering\n- ⚡ Async image loading\n- 🎨 Modern SwiftUI design patterns\n\n## Example Views\n\n### Posts List\n\n```swift\nstruct PostsView: View {\n    @State private var posts: [GhostPost] = []\n    let ghostingKit: GhostingKit\n    \n    var body: some View {\n        List(posts, id: \\.id) { post in\n            NavigationLink(destination: PostDetailView(post: post)) {\n                VStack(alignment: .leading) {\n                    Text(post.title)\n                        .font(.headline)\n                    Text(post.excerpt ?? \"\")\n                        .font(.subheadline)\n                        .foregroundColor(.secondary)\n                }\n            }\n        }\n        .task {\n            do {\n                let response = try await ghostingKit.getPosts(include: \"authors,tags\")\n                posts = response.posts\n            } catch {\n                print(\"Error loading posts: \\(error)\")\n            }\n        }\n    }\n}\n```\n\n## Contributing\n\nContributions 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.\n\n### Development Setup\n\n1. Clone the repository\n2. Open `Package.swift` in Xcode\n3. Run tests with ⌘+U\n4. Check out the example app in the `Ghosting` folder\n\n### Running Tests\n\n```bash\n# Run all tests\nswift test\n\n# Run only unit tests (no network required)\nswift test --filter MockGhostingKitTests\n\n# Run integration tests (requires network)\nswift test --filter integration\n```\n\n## License\n\nGhostingKit is available under the MIT license. See the [LICENSE](LICENSE) file for more info.\n\n## Ghost Content API\n\nThis library interacts with the Ghost Content API. For more information about Ghost and its API, visit:\n\n- [Ghost Official Website](https://ghost.org)\n- [Ghost Content API Documentation](https://ghost.org/docs/content-api/)\n- [Ghost Admin API Documentation](https://ghost.org/docs/admin-api/)\n\n## Changelog\n\n### 1.0.0\n- Initial release\n- Complete Ghost Content API coverage\n- SwiftUI example app\n- Comprehensive test suite\n- Modern Swift async/await support\n- Caching, retry logic, and request cancellation\n- Type-safe models with proper Date handling\n- Secure configuration management","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frryam%2Fghostingkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frryam%2Fghostingkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frryam%2Fghostingkit/lists"}