这个库是用来进行网络请求,带有扑克牌、轮盘赌和骰子的刺激体验!
使用它,您可以将大量的 API 层代码转化为极易使用的控制器,进行简单且可维护的网络请求!
使用 Codable 模型处理所有与 API 请求相关的事务
- json 有效载荷
- url 编码有效载荷
- multipart 有效载荷
- 纯文本和 json 响应
- url 查询
- 头部信息
这只是您从这个库中可以获得的一小部分!
APIRequest<ResponseModel>("endpoint").onSuccess { model in
//here's your decoded model!
//no need to check http.statusCode, I already did it for you! By default it's 200 OK
//of course you can choose which statusCode is equal to success (look at the `POST` and `DELETE` examples below)
}
APIRequest<ResponseModel>("endpoint", payload: payloadModel)
.method(.post)
.desiredStatusCode(.created) //201 CREATED
.onSuccess { model in
//here's your decoded model!
//success was determined by comparing desiredStatusCode with http.statusCode
}
APIRequest<Nothing>("endpoint")
.method(.delete)
.desiredStatusCode(.noContent) //204 NO CONTENT
.onSuccess { _ in
//here's empty successful response!
//success was determined by comparing desiredStatusCode with http.statusCode
}
如何发送多个请求?
您可以依次运行多达10个请求!
API.employee.all()
.and(API.office.all())
.and(API.car.all())
.and(API.event.all())
.and(API.post.all())
.onError { error in
print(error.description)
}.onSuccess { employees, offices, cars, events, posts in
// do what you want with received results!!! 🍻
}
或者,如果您只需要完成处理程序,您可以逐个或同时运行无限数量的请求。
[API.employee.all(), API.office.all(), API.car.all()].flatten().onError {
print(error.description)
}.onSuccess {
print("flatten finished!")
}
要并发运行它们,只需添加 .concurrent(by: 3)
以同时运行3个
当然,您还可以发送PUT和PATCH请求,上传带有进度回调的多部分可编码结构,捕获错误,甚至为每个端点重新定义错误描述。有什么想法吗?
如何安装
CodyFire通过CocoaPods和SPM提供。
要安装,只需在您的Podfile中添加以下行
pod 'CodyFire', '~> 1.15.0'
或者您在寻找反应式代码支持?我可以做!
pod 'RxCodyFire', '~> 1.1.0'
# no need to install `CodyFire` cause it's in dependencies
使用此pod,您应该始终导入RxCodyFire
,并且每个APIRequest都将有.observable
- 对于ReactiveCocoa https://github.com/MihaelIsaev/ReactiveCodyFire
pod 'ReactiveCodyFire', '~> 1.1.0'
# no need to install `CodyFire` cause it's in dependencies
使用此pod,您应该始终导入ReactiveCodyFire
,并且每个APIRequest都将有.signalProducer
如何设置
CodyFire会自动检测您处于什么环境,所以我建议您尽量使用这个酷炫的功能
import CodyFire
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
let dev = CodyFireEnvironment(baseURL: "https://:8080")
let testFlight = CodyFireEnvironment(baseURL: "https://stage.myapi.com")
let appStore = CodyFireEnvironment(baseURL: "https://api.myapi.com")
CodyFire.shared.configureEnvironments(dev: dev, testFlight: testFlight, appStore: appStore)
//Also if you want to be able to switch environments manually just uncomment the line below (read more about that)
//CodyFire.shared.setupEnvByProjectScheme()
return true
}
}
cool 吧?
或者为每个APIRequest设置不同的服务器URL
let server1 = ServerURL(base: "https://server1.com", path: "v1")
let server2 = ServerURL(base: "https://server2.com", path: "v1")
let server3 = ServerURL(base: "https://server3.com")
然后初始化您的APIRequest
如下
APIRequest(server1, "endpoint", payload: payloadObject)
APIRequest(server2, "endpoint", payload: payloadObject)
APIRequest(server3, "endpoint", payload: payloadObject)
在某些情况下,您甚至可以这样做
APIRequest("endpoint", payload: payloadObject).serverURL(server1)
创建您的API控制器
我保证,这是您梦想成真的API代码架构!
API
文件夹并在其中创建一个 API.swift
文件
创建一个 class API {
typealias auth = AuthController
typealias task = TaskController
}
API
文件夹内创建一个名为 Controllers
的文件夹,并为每个控制器创建一个文件夹
在 API/Controllers/Auth/Auth.swift
class AuthController {}
API/Controllers/Task/Task.swift
class TaskController {}
为每个控制器的端点创建一个扩展文件
Auth登录作为简单的POST请求
API/Controllers/Auth/Auth+Login.swift
import CodyFire
extension AuthController {
struct LoginRequest: JSONPayload {
let email, password: String
init (email: String, password: String) {
self.email = email
self.password = password
}
}
struct LoginResponse: Codable {
var token: String
}
static func login(_ request: LoginRequest) -> APIRequest<LoginResponse> {
return APIRequest("login", payload: request).method(.post).addCustomError(.notFound, "User not found")
}
}
Auth登录为基本认证
API/Controllers/Auth/Auth+Login.swift
import CodyFire
extension AuthController {
struct LoginResponse: Codable {
var token: String
}
static func login(email: String, password: String) -> APIRequest<LoginResponse> {
return APIRequest("login").method(.post).basicAuth(email: email, password: password)
.addCustomError(.notFound, "User not found")
}
}
Task REST端点
通过ID获取任务或通过偏移和限制获取任务列表
API/Controllers/Task/Task+Get.swift
import CodyFire
extension TaskController {
struct Task: Codable {
var id: UUID
var name: String
}
struct ListQuery: Codable {
var offset, limit: Int
init (offset: Int, limit: Int) {
self.offset = offset
self.limit = limit
}
}
static func get(_ query: ListQuery? = nil) -> APIRequest<[Task]> {
return APIRequest("task").query(query)
}
static func get(id: UUID) -> APIRequest<Task> {
return APIRequest("task/" + id.uuidString)
}
}
创建任务
API/Controllers/Task/Task+Create.swift
import CodyFire
extension TaskController {
struct CreateRequest: JSONPayload {
var name: String
init (name: String) {
self.name = name
}
}
static func create(_ request: CreateRequest) -> APIRequest<Task> {
return APIRequest("post", payload: request).method(.post).desiredStatusCode(.created)
}
}
编辑任务
API/Controllers/Task/Task+Edit.swift
import CodyFire
extension TaskController {
struct EditRequest: JSONPayload {
var name: String
init (name: String) {
self.name = name
}
}
static func create(id: UUID, request: EditRequest) -> APIRequest<Task> {
return APIRequest("post/" + id.uuidString, payload: request).method(.patch)
}
}
删除任务
API/Controllers/Task/Task+Delete.swift
import CodyFire
extension TaskController {
static func delete(id: UUID) -> APIRequest<Nothing> {
return APIRequest("post/" + id.uuidString).method(.delete).desiredStatusCode(.noContent)
}
}
轻松使用您的API端点!
发送登录请求
API.auth.login(email: "[email protected]", password: "qwerty").onError { error in
switch error.code {
case .notFound: print("User not found")
default: print(error.description)
}
}.onSuccess { token in
print("Received auth token: "+ token)
}
获取任务列表
API.task.get().onError { error in
print(error.description)
}.onSuccess { tasks in
print("received \(tasks.count) tasks")
}
创建一个任务
API.task.create(TaskController.CreateRequest(name: "Install CodyFire")).onError { error in
print(error.description)
}.onSuccess { task in
print("just created new task: \(task)")
}
删除一个任务
let taskId = UUID()
API.task.delete(id: taskId).onError { error in
print(error.description)
}.onSuccess { _ in
print("just removed task with id: \(taskId)")
}
多部分示例
//declare a PostController
class PostController()
extension PostController {
struct CreateRequest: MultipartPayload {
var text: String
var tags: [String]
var images: [Attachment]
var video: Data
init (text: String, tags: [String], images: [Attachment], video: Data) {
self.text = text
self.tags = tags
self.images = images
self.video = video
}
}
struct PostResponse: Codable {
let id: UUID
let text: String
let tags: [String]
let linksToImages: [String]
let linkToVideo: String
}
static func create(_ request: CreateRequest) -> APIRequest<PostResponse> {
return APIRequest("post", payload: request).method(.post)
}
}
//then somewhere send creation request!
let videoData = FileManager.default.contents(atPath: "/path/to/video.mp4")!
let imageAttachment = Attachment(data: UIImage(named: "cat")!.jpeg(.high)!,
fileName: "cat.jpg",
mimeType: .jpg)
let payload = PostController.CreateRequest(text: "CodyFire is awesome",
tags: ["codyfire", "awesome"],
images: [imageAttachment],
video: videoData)
API.post.create(payload).onProgress { progress in
print("tracking post uploading progress: \(progress)")
}.onError { error in
print(error.description)
}.onSuccess { createdPost in
print("just created post: \(createdPost)")
}
简单吧?
详细信息
Authorization Bearer
" 令牌放入每一次请求中?
如何将 "为此,我们有一个全局头部封装器,它在每次请求时都会调用。
您需要声明它,例如在AppDelegate中。
有两种选择
- 使用可编码的模型进行头部 (推荐)
CodyFire.shared.fillCodableHeaders = {
struct Headers: Codable {
var Authorization: String? //NOTE: nil values will be excluded
var anythingElse: String
}
return Headers(Authorization: nil, anythingElse: "hello")
}
- 使用 [String: String] 字典
CodyFire.shared.fillHeaders = {
guard let apiToken = LocalAuthStorage.savedToken else { return [:] }
return ["Authorization": "Bearer \(apiToken)"]
}
未授权
处理程序?
如何设置全局的 同样,在AppDelegate中声明它,如下所示:CodyFire.shared.unauthorizedHandler = { //踢出用户 }