من توی این قسمت می خوام Router در Alamofire پیاده کنم اگه با این کتابخونه آشنایی داشته باشید باید بدونید برای فراخوانی API ها استفاده میشه و کتابخونه خیلی محبوبی هست و میشه به راحتی ازش استفاده کرد اما مشکلی که هست اینه که برای فراخونی API داخل کنترلر ها کدهای زیادی زده میشه که هم باعث هدر رفتن وقت برنامه نویس به خاطر یک کار تکراری میشه هم کنترلرهامون به شدت حجیم می کنه بهترین راه حل برا این مشکل Router هست متاسفانه توی خود گیتهاب Alamofire توضیحات ناقصی ارائه شده و خیلی از نیازها رو پوشش نمیده من توی خیلی از سایت های خارجی چرخیدم و تونستم یه Router جامع پیاده کنم که تمامی نیازهامون پوشش بده از متد ها get و post و ... تا ست کردن توکن در هدر درخواست و فرستادن پارامتر و حتی کوئری استرینگ درخواست get
اول از همه ما به یک enum احتیاج داریم که همون Router ما هست که از URLRequestConvertible ارث بری می کنه من هر بخشی کدهاش جدا می ذارم اما همشون داخل همین enum هستند در ضمن یه خطا اینجا نشون میده که بهش اهمیت ندید بعدا فیکسش می کنیم
import Alamofire
enum Router: URLRequestConvertible {
static let baseURLString = ""
}
توی کد بالا فقط baseURLString با آدرس سرورتون ست کنید
در ادامه کد های زیر داخل enum می ذاریم
case get(apiName: String)
case getWhithQuery(apiName: String, query:String)
case getWhithToken(apiName: String, token:String)
case post(apiName: String, parameters: [String: Any])
case postWithToken(apiName: String, parameters: [String: Any], tokenValue: String)
case put(apiName: String, parameters: [String: Any], tokenValue: String)
case patch(apiName: String, parameters: [String: Any], tokenValue: String)
case delete(apiName: String, tokenValue: String)
من تمام متدهایی که فکر می کردم برای یک پروژه نیازه اینطوری تعریف کردم حالا با خودتونه عشقتون کشید از اینها کمتر کنید یا بهش اضافه کنید فقط در صورت اضافه یا کم کردن بخشهای مختلفش باید تغییر بدید که پای خودتونه
بخش های بعدی هم زیر همین کدهای بالا بذارید تا زمانی که بهتون بگم
// MARK: - Method
var method: HTTPMethod {
switch self {
case .get, .getWhithQuery, .getWhithToken:
return .get
case .post, .postWithToken:
return .post
case .put:
return .put
case .patch:
return .patch
case .delete:
return .delete
}
}
تو این بخش نوع متد هامون تعریف کردیم که get باشن یا ...
// MARK: - Path
var path: String {
switch self {
case .get(let apiName), .getWhithQuery(let apiName, _), .getWhithToken(let apiName, _), .post(let apiName, _), .postWithToken(let apiName, _, _), .put(let apiName, _, _), .patch(let apiName, _, _), .delete(let apiName, _):
return apiName
}
}
توی اینجا آدرس کامل API می سازیم که برای هر متد چی باشه که از ورودی متد ها به اسم apiName می گیریم
// MARK: - Parameters
private var parameters: [String: Any]? {
switch self {
case .get, .getWhithToken, .delete :
return nil
case .post(_, let parameters), .postWithToken(_, let parameters, _), .put(_, let parameters, _), .patch(_, let parameters, _):
return parameters
case .getWhithQuery(_, let query):
return (["filter": query])
}
}
تو این بخش برای متد هایی که پارامتر دارن پارامتر ست می کنیم برای اونهایی که پارامتری ندارن nil و برای کوئری استرینگ هم جدا
// MARK: - token
private var token: String?{
switch self {
case .get, .getWhithQuery, .post:
return nil
case .getWhithToken(_, let tokenValue ), .postWithToken(_, _, let tokenValue ), .put(_, _, let tokenValue ), .patch(_, _, let tokenValue ), .delete(_, let tokenValue):
return (tokenValue)
}
}
تو این بخش برای متد هایی که نیاز هست token ست می کنیم که این مقدار هم از ورودی متد می گیریم
func asURLRequest() throws -> URLRequest {
let url = try Router.baseURLString.asURL()
var urlRequest = URLRequest(url: url.appendingPathComponent(path))
urlRequest.httpMethod = method.rawValue
if let t = token {
urlRequest.setValue(t, forHTTPHeaderField: "access_token")
}
let encoding: ParameterEncoding = {
switch method {
case .get:
return URLEncoding.default
default:
return JSONEncoding.default
}
}()
return try encoding.encode(urlRequest, with: parameters)
}
حالا رسیدیم به بخش اصلی با گذاشتن کدهای بالا اون خطایی که اولش گفتم رفع میشه توی اینجا براساس اینکه پارامتر داره یا نه توکن داره یا نه یه درخواست می سازه که همون چیزی هست که ما می خوایم
خوب بخش Router تموم شد حالا یه کلاس می سازیم با کد های زیر
class ApiHelper : NSObject {
static let sharedInstants = ApiHelper()
func getMainData(_ completionHandler: @escaping(Any, Bool) -> Void) {
Alamofire.request(Router.get(apiName: "/api/v1/Categories/getAppMainData")).responseJSON { response in
switch response.result {
case .success(_):
if let Json = response.result.value as? NSDictionary {
if let hasError = Json["hasError"] as? Bool {
if hasError {
if let error = Json["error"] as? NSDictionary {
completionHandler(error, hasError)
}
} else {
if let data = Json["response"] {
completionHandler(data, hasError)
}
}
}
}
case .failure(_):
completionHandler(response.error.debugDescription,true)
}
}
}
}
به ازای هر API یه متد می سازیم و بعد به جای گذاشتن آدرس API متد های Router می ذاریم و مقادیر ورودیش با توجه به نیازمون پر می کنیم و بعدش می تونیم توی کنترلرمون این متد ها رو درخواست بدیم کدهای کاملش توی github خودم گذاشتم اگه قسمتیش متوجه نشدید یه نگاه بندازید مشکلتون حل میشه امیدوارم خوشتون اومده باشه