AnotherFuckingNetworkingSDK
A modern, lightweight Swift networking SDK built for iOS 15+ with async/await support. Type-safe API requests, built-in pagination, error handling, request logging with cURL commands, and mocking capabilities for testing. No dependencies, no bullshit, just clean API calls that actually work.
Install / Use
/learn @MikesHorcrux/AnotherFuckingNetworkingSDKREADME
🔥 AnotherFuckingNetworkingSDK 🔥
Yet another Swift networking library, but this one actually doesn't suck. It's lightweight, powerful, and built for modern Swift with async/await. No bullshit, just clean API calls. ✨
Is it missing functionality? Maybe. But it fucking works, and you can just email < Your email here > with your complaints or contribute. Or don't. Whatever. 🤷♂️
✨ Features
- ✅ 100% Swift, built for modern concurrency with async/await 🚀
- ✅ Type-safe API requests and responses (so you can stop guessing what the hell your API returns) 🧩
- ✅ Built-in pagination support that doesn't make you want to throw your laptop 💻🪟
- ✅ Clear error handling that actually tells you what went wrong 🚨
- ✅ Request logging with cURL command generation (inspect your requests like a grown-up) 🔍
- ✅ Mocking support that makes testing not completely suck 🧪
- ✅ Zero dependencies because who needs that fucking headache 🏝️
- ✅ Works on iOS 15+, macOS 12+, and other Apple platforms nobody cares about 🍎
📦 Installation
Swift Package Manager
Add the following to your Package.swift file, or don't, I'm not your mom: 👩👧
dependencies: [
.package(url: "https://github.com/MikesHorcrux/AnotherFuckingNetworkingSDK.git", from: "1.0.0")
]
Or in Xcode:
- Go to File → Add Packages... 📁
- Enter the repository URL:
https://github.com/MikesHorcrux/AnotherFuckingNetworkingSDK.git - Click "Add Package" and wait for Xcode to inevitably freeze for no reason ⏳❄️
🚀 Quick Start
1. Configure the client 🔧
import AnotherFuckingNetworkingSDK
// Set up the global shared client (the lazy way)
APIClient.shared.baseURL = URL(string: "https://api.example.com")
APIClient.shared.globalHeaders = ["Authorization": "Bearer YOUR_TOKEN"]
// Or be a fucking professional and create your own instance
let client = APIClient(baseURL: URL(string: "https://api.example.com"))
2. Define your models 📊
Make sure they conform to Decodable or you're gonna have a bad time: 💀
struct User: Decodable {
let id: Int
let name: String
let email: String
let isAdmin: Bool
// Handle snake_case if your backend devs hate camelCase
enum CodingKeys: String, CodingKey {
case id, name, email
case isAdmin = "is_admin"
}
}
3. Create request types 📝
This is where the magic happens. Each API endpoint gets its own request type: 🪄
// Simple GET request
struct GetUserRequest: Request {
typealias ReturnType = User // Tell it what you expect back
let userID: Int
var path: String { "users/\(userID)" } // Define the endpoint path
}
// POST request with a body
struct CreateUserRequest: Request {
typealias ReturnType = User
let name: String
let email: String
let password: String
var path: String { "users" }
var method: HTTPMethod { .post } // Override the default GET
// Define the request body
var body: Data? {
try? JSONEncoder().encode([
"name": name,
"email": email,
"password": password
])
}
}
// Request with query parameters
struct SearchUsersRequest: Request {
typealias ReturnType = [User]
let query: String
let limit: Int
var path: String { "users/search" }
var queryItems: [URLQueryItem]? {
[
URLQueryItem(name: "q", value: query),
URLQueryItem(name: "limit", value: "\(limit)")
]
}
}
// Request with custom headers
struct AuthenticateRequest: Request {
typealias ReturnType = AuthResponse
let username: String
let password: String
var path: String { "auth/login" }
var method: HTTPMethod { .post }
var headers: [String: String]? {
["Content-Type": "application/json"]
}
var body: Data? {
try? JSONEncoder().encode([
"username": username,
"password": password
])
}
}
4. Make API calls with async/await ⚡
func fetchUser(id: Int) async {
do {
let userRequest = GetUserRequest(userID: id)
let user = try await APIClient.shared.send(userRequest)
print("Got user: \(user.name), \(user.email)")
} catch let error as NetworkError {
handleNetworkError(error)
} catch {
print("Some other shit went wrong: \(error)")
}
}
5. Paginated requests that don't suck 📄📄📄
struct ListUsersRequest: PaginatedRequest {
typealias ReturnType = User
var path: String { "users" }
let page: Int
let pageSize: Int
}
func fetchAllUsers() async {
var currentPage = 1
var hasMorePages = true
var allUsers: [User] = []
while hasMorePages {
do {
let request = ListUsersRequest(page: currentPage, pageSize: 20)
let response = try await APIClient.shared.sendPage(request)
allUsers.append(contentsOf: response.items)
// Check if there's a next page
if let nextPage = response.nextPage {
currentPage = nextPage
} else {
hasMorePages = false
}
} catch {
print("Error fetching users: \(error)")
hasMorePages = false
}
}
print("Fetched a total of \(allUsers.count) users")
}
🧠 Advanced Usage
Setting up a proper service layer 🏢
Don't be a barbarian. Structure your API calls in service classes: 🏗️
class UserService {
private let client: APIClient
// Dependency injection for testability
init(client: APIClient = APIClient.shared) {
self.client = client
}
func getUser(id: Int) async throws -> User {
let request = GetUserRequest(userID: id)
return try await client.send(request)
}
func createUser(name: String, email: String, password: String) async throws -> User {
let request = CreateUserRequest(name: name, email: email, password: password)
return try await client.send(request)
}
func searchUsers(query: String, limit: Int = 20) async throws -> [User] {
let request = SearchUsersRequest(query: query, limit: limit)
return try await client.send(request)
}
func listUsers(page: Int = 1, pageSize: Int = 20) async throws -> PaginatedResponse<User> {
let request = ListUsersRequest(page: page, pageSize: pageSize)
return try await client.sendPage(request)
}
}
Error handling that actually makes sense 🚫
func handleNetworkError(_ error: NetworkError) {
switch error {
case .invalidURL:
// You fucked up the URL 🤦♂️
showAlert(title: "Invalid URL", message: "Contact the developer, they can't type URLs correctly")
case .requestFailed(let statusCode, let data):
// The server fucked up 💩
switch statusCode {
case 401:
// Token expired or invalid
refreshTokenAndRetry()
case 403:
showAlert(title: "Access Denied", message: "You're not allowed to do that, buddy")
case 404:
showAlert(title: "Not Found", message: "The thing you're looking for doesn't exist")
case 500..<600:
showAlert(title: "Server Error", message: "The server is having a bad day")
default:
if let data = data, let errorJson = try? JSONSerialization.jsonObject(with: data) as? [String: Any] {
print("Server said: \(errorJson)")
}
showAlert(title: "Error \(statusCode)", message: "Something went wrong")
}
case .decodingFailed(let decodingError):
// The JSON decoder fucked up 💥
print("Decoding error: \(decodingError)")
showAlert(title: "Data Error", message: "Could not understand the server response")
case .unknown(let underlyingError):
// Something else fucked up 🤷♂️
print("Unknown error: \(underlyingError)")
showAlert(title: "Unknown Error", message: underlyingError.localizedDescription)
}
}
🧪 Testing with Mock Responses
Because tests that hit real APIs are stupid and unreliable. 👎
1. Set up your test class 🏗️
import XCTest
@testable import YourAppModule
import AnotherFuckingNetworkingSDK
class UserServiceTests: XCTestCase {
var mockClient: MockAPIClient!
var userService: UserService!
override func setUp() {
super.setUp()
// Create a mock client instead of hitting real APIs
mockClient = MockAPIClient()
// Inject the mock into your service
userService = UserService(client: mockClient)
}
override func tearDown() {
mockClient.resetMocks()
mockClient = nil
userService = nil
super.tearDown()
}
2. Test a successful request ✅
func testGetUser() async throws {
// 1. Create fake data 🤥
let mockUser = User(id: 42, name: "Arthur Dent", email: "arthur@earth.com", isAdmin: false)
// 2. Tell the mock what to return
mockClient.mock(GetUserRequest.self, with: mockUser)
// 3. Call the API through your service
let user = try await userService.getUser(id: 42)
// 4. Verify you got what you expected
XCTAssertEqual(user.id, 42)
XCTAssertEqual(user.name, "Arthur Dent")
XCTAssertEqual(user.email, "arthur@earth.com")
// 5. Verify the correct request was made
XCTAssertTrue(mockClient.calledRequests.contains("users/42"))
}
3. Test with fake errors ❌
func testGetUserError() async {
// 1. Set up a mock error 💣
let mockError = NetworkError.requestFailed(statusCode: 404, data: nil)
mockClient.mockError(GetUserRequest.self, with: mockError)
// 2. Try to call the API and expect an error
do {
_ = try a
Related Skills
node-connect
352.9kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
111.5kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
352.9kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
352.9kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
