How to merge many API call into one in swift - ios

func getCar(session: String, CarHandler: #escaping (Result<CarResponseModel, Error>) -> Void) {
let url = MAIN_URL + "/user/car"
AF.request(url, method: .post, encoding: JSONEncoding.default, headers: ["Content-Type":"application/json; charset=utf-8", "Accept":"application/json", "session":session])
.validate(statusCode: 200..<300)
.validate(contentType: ["application/json"])
.responseDecodable(of: CarResponseModel.self) { (response) in
switch response.result {
case .success(let response):
CarHandler(.success(response))
case let .failure(error):
CarHandler(error.localizedDescription)
}
}
}
func getHouse(session: String, HouseHandler: #escaping (Result<HouseResponseModel, Error>) -> Void) {
let url = MAIN_URL + "/user/house"
let parameters = ["name": "houseName"]
AF.request(url, method: .get, parameters: parameters, encoding: URLEncoding.queryString, headers: ["Content-Type":"application/json; charset=utf-8", "Accept":"application/json", "session":session])
.validate(statusCode: 200..<300)
.validate(contentType: ["application/json"])
.responseDecodable(of: HouseResponseModel.self) { (response) in
switch response.result {
case .success(let response):
HouseHandler(.success(response))
case let .failure(error):
HouseHandler(.failure(error))
}
}
}
Question
Use two functions to get car and house information. I wonder if it's possible to put this together.
Reason
The idea that if I receive information using only one communication function, I can handle the error at once.
My idea
The parameters or get, post information for handing over to the server are made by another function using communication and handed over to one communication function
Desired result
func getData(request, AllHandler: #escaping (Result<AnyModelStruct, Error>) -> Void) {
AF.request(request)
.validate(statusCode: 200..<300)
.validate(contentType: ["application/json"])
.responseDecodable(of: AnyModelStruct.self) { (response) in
switch response.result {
case .success(let response):
AllHandler(.success(response))
case let .failure(error):
AllHandler(.failure(error))
}
}
}
Problem
func getData(request, AllHandler: #escaping (Result<HouseResponseModel, Error>) -> Void) {
AF.request(request)
.validate(statusCode: 200..<300)
.validate(contentType: ["application/json"])
.responseDecodable(of: HouseResponseModel.self) { (response) in
switch response.result {
case .success(let response):
AllHandler(.success(response))
case let .failure(error):
AllHandler(.failure(error))
}
}
}
...
let url = URL(string: "http://www.stackoverflow.com")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
I know that url, method, parameters, encoding, header information can be generated and handed over as a request,
I don't know how to give and receive a model...
Model information is required for escape and response decoding. Is there a way to hand over the model information here? Or is it possible to set the Any type?
Others
Lastly, I would like to know a tip on how to proceed when I perform many API requests in other projects, if the method I'm trying now is not a popular method.

1. First, you can create a base service to generate AF requests
import Foundation
import Alamofire
class BaseService {
public static let shared = BaseService()
private var request = URLRequest(url: URL(string: Constant.API_BASE_URL)!)
private init() {}
public func generateRequest(url: String, method: HTTPMethod, body: Data?) -> URLRequest {
guard let formateUrl = URL(string: url) else {
fatalError("Invalid URL")
}
request.url = formateUrl
request.method = method
if let body_data = body {
request.httpBody = body_data
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
}
return request
}
}
2. You need to create a generic method for calling API requests
import Foundation
import Alamofire
struct API {
private static let decoder = JSONDecoder()
static func getRequest<T: Decodable>(urlPath: String, model: T.Type, completed: #escaping(Result<T, AFError>)-> Void) {
let request = BaseService.shared.generateRequest(url: urlPath, method: .get, body: nil)
AF.request(request).validate().responseDecodable(of: model.self, decoder: decoder) { (response) in
switch response.result {
case .success(let result):
completed(.success(result))
case .failure(let error):
completed(.failure(error))
}
}
}
3. After that, You can call the previous method anywhere with any JSON model
API.getRequest(urlPath: "YOUR API PATH", model: HouseResponseModel.self) { result in
switch result {
case .success(let res):
print(res)
case .failure(let error):
print(error)
}
}

Related

Alamofire generalize request

I am using Almofire for all my requests and works fine. I need to know how to generalize all requests to handle all errors at one place.
func updateSettingValue(group : String , value: String , callback: #escaping (SettingsResponseModel) -> Void, errorCallback: #escaping (Error) ->Void)
{
let url = BASE_URL_PROD + API_SETTINGS
let settingsParams : Parameters = ["Setting" : group , "Tag" : value]
Alamofire.request(url, method: .put, parameters: settingsParams, headers: getHeader()).responseObject {
(response: DataResponse< SettingsResponseModel>) in
switch response.result {
case .success:
print("response \(response)")
DispatchQueue.main.async {
callback(response.result.value!)
}
break
case .failure(let error):
print(error)
errorCallback(error)
}
}
}
func releaseKeys(mKey: String ,callback: #escaping (ReleaseKeyModel) -> Void
, errorCallback: #escaping (Error) -> Void){
let url = BASE_URL_PROD + API_RELEASE_KEY
let params: Parameters = ["mKey" : mKey]
Alamofire.request(url, method: .delete, parameters: params, encoding: URLEncoding.default, headers: getHeader()).responseObject{
(response : DataResponse< ReleaseKeyModel >) in
print("releaseKey: \(response) ")
switch response.result {
case .success:
DispatchQueue.main.async {
callback(response.result.value!)
}
break
case .failure(let error):
print(error)
errorCallback(error)
}
}
}
How can I generalize this to take parameters for Mapping Model class in DataResponse so that I don't have to handle success and failure case individually for all methods.
You can divide the work with the server into 2 classes:
1) class RestClient
import Foundation
typealias responseBlock = (_ swiftObj: Any?, _ error: Error?) -> Void
class RestClient: NSObject {
static let shared = RestClient()
private var http = HttpService()
func updateSettingValue(group: String, value: String, resp: #escaping responseBlock) {
let url = BASE_URL_PROD + API_SETTINGS
let params = ["Setting": group, "Tag": value]
http.reque(url, method: .put, parameters: params, headers: getHeader(), resp: { (value, error) in
if let err = error {
return resp(nil, err)
}
guard let data = value else {
return resp(nil, error)
}
//your method for parse data
self.parseData(respData: data,
modelCls: SettingsResponseModel.self,
response: resp)
})
}
func releaseKeys(mKey: String, resp: #escaping responseBlock) {
let url = BASE_URL_PROD + API_RELEASE_KEY
let params = ["mKey": mKey]
http.reque(url, method: .delete, parameters: params, encoding: URLEncoding.default, headers: getHeader(), resp: { (value, error) in
if let err = error {
return resp(nil, err)
}
guard let data = value else {
return resp(nil, error)
}
//your method for parse data
self.parseData(respData: data,
modelCls: ReleaseKeyModel.self,
response: resp)
})
}
}
2) class HttpService
class HttpService {
func reque(_ url: URLConvertible,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
encoding: ParameterEncoding = URLEncoding.default,
headers: HTTPHeaders? = nil,
queue: QueueQos = .defaultQos,
resp: #escaping responseBlock) {
Alamofire.request(url,
method: method,
parameters: parameters,
encoding: encoding,
headers: headers
).responseObject (queue: queue) { (response) in
switch response.result {
case .success:
if let jsonResp = response.result.value {
//You can also check out some error messages at this place.
resp(jsonResp, nil)
}
case .failure(let error):
resp(nil, error)
}
}
}
}
Try this, using generics
func releaseKeys<T: Codable>(parameters params: [String: Any], callback: #escaping (T) -> Void
, errorCallback: #escaping (Error) -> Void){
Alamofire.request(url, method: .delete, parameters: params, encoding: URLEncoding.default, headers: getHeader()).responseObject{
(response : DataResponse< T >) in
print("releaseKey: \(response) ")
switch response.result {
case .success:
DispatchQueue.main.async {
callback(response.result.value!)
}
break
case .failure(let error):
print(error)
errorCallback(error)
}
}
}

How can i use alamofire for post api [duplicate]

This question already has answers here:
POST request with a simple string in body with Alamofire
(12 answers)
Closed 5 years ago.
I am new in iOS development . I am using alamofire in swift 3 . How can i send post request in alamofire . It also gives extra argument in method.
Thanks in advance
First of all you add almofire library into your project then import almofire into your ViewController then below method apply in your button action.
func webServiceLogin(isFbLogin:Bool,email:String,password:String)
{
var parameters:[String:String]?
parameters = ["hash":email as String,"key":password ]
Alamofire.request("your url", method: .post, parameters: parameters,encoding: URLEncoding.default, headers: nil).responseJSON {
response in
hideHud(self.view)
switch response.result {
case .success:
if let dictSuccess:NSDictionary = response.value as! NSDictionary?
{
}
break
case .failure(let error):
Alert.showAlertWithTitle(strTitle: appTitle, strMessage: error.localizedDescription, onView: self)
print(response)
print(error)
}
}
}
Use like bellow and pass your parameter which you want to send in server. Better you write an Network layer class using this then It will be reusable throughout the whole application.
static func serverRequest(urlString: URL?, Parameter:NSDictionary?, completion: #escaping (_ serverResponse: AnyObject?,_ error:NSError?)->()){
// let parameters: Parameters = ["foo": "bar"]
//let headers = ["Authorization": "123456"]
Alamofire.request(urlString!, parameters:nil, headers: nil).responseJSON { response in
if(response.result.value != nil){
let serverResponse = JSON(response.result.value!)
//print("Array value is \(serverResponse.arrayValue)")
completion(serverResponse as AnyObject?, nil)
}
else{
completion(nil, response.result.error as NSError?)
}
}
}
You can use alamofire manager
var alamoFireManager = Alamofire.SessionManager
let request = URLRequest(url:_yourULR)
request.HTTPMethod = requestMethod.rawValue
request.timeoutInterval = //set yours
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("gzip", forHTTPHeaderField: "Accept-Encoding")
request.HTTPBody = "you_bodydataSTring".dataUsingEncoding(String.Ecoding.utf8)
alamoFireManager.request(request)
.validate()
.responseString { (response) -> Void in
let datastring = NSString(data:response.data!, encoding: String.Ecoding.utf8)
switch response.result {
case .Success:
if response.response?.statusCode == 200 {
//code for success
}else{
//others
}
case .Failure(let error):
//request failed
}
}
}

Expression type 'DataRequest' is ambiguous without more context Swift

I use Alamofire for my request in this function and I have this error if someone could help me please thank in advance.
Expression type 'DataRequest' is ambiguous without more context
func report(_ track: Track, completionHandler: #escaping (_ error: NSError?) -> Void) {
var headers:[String:String] = [:]
if AuthManager.defaultAuthManager().isLoggedIn() {
headers = ["Authorization": "Bearer " + AuthManager.defaultAuthManager().authToken.token!]
}
let params: [String: Any] = ["trackCode": track.code]
let urlString = Cizoo.APIBaseUrl + CizooScheme.report
CizooAPI.manager.request(urlString, method: .post, parameters: params, encoding: .JSONEncoding.default, headers: headers as HTTPHeaders)
.validate()
.responseJSON(completionHandler: { // Error at this line
response in
switch response.result {
case .success:
completionHandler(error: nil)
case .failure(let error):
completionHandler(error: error)
}
})
}
From the Alamofire source code you can see that the declaration of the method is:
#discardableResult
open func request(
_ url: URLConvertible,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
encoding: ParameterEncoding = URLEncoding.default,
headers: HTTPHeaders? = nil)
-> DataRequest
{
var originalRequest: URLRequest?
do {
originalRequest = try URLRequest(url: url, method: method, headers: headers)
let encodedURLRequest = try encoding.encode(originalRequest!, with: parameters)
return request(encodedURLRequest)
} catch {
return request(originalRequest, failedWith: error)
}
}
Which in your case probably the urlString is not conforming to the URLConvertible protocol.
Thanks !
Finally, It was a concern of type declaration
Here is the code solved :
func report(_ track: Track, completionHandler: #escaping (_ error: NSError?) -> Void) {
var headers:HTTPHeaders? = [:]
let params:Parameters? = ["trackCode": track.code]
let encoding:ParameterEncoding = JSONEncoding.default
let method:HTTPMethod = .post
let urlString:URLConvertible = (Cizoo.APIBaseUrl + CizooScheme.report)
if AuthManager.defaultAuthManager().isLoggedIn() {
headers = ["Authorization": "Bearer " + AuthManager.defaultAuthManager().authToken.token!]
}
CizooAPI.manager.request(urlString, method: method, parameters: params, encoding: encoding, headers: headers)
.validate()
.responseJSON(completionHandler: {
response in
switch response.result {
case .success:
completionHandler(nil)
case .failure(let error):
completionHandler(error as NSError?)
}
})
}

POST request with data in body with Alamofire 4

how is it possible to send a POST request with a data in the HTTP body with Alamofire 4? I used custom encoding at swift 2.3 it was working good. I converted my code swift 3 and I tried to paramater encoding but not working. This code :
public struct MyCustomEncoding : ParameterEncoding {
private let data: Data
init(data: Data) {
self.data = data
}
public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var urlRequest = try urlRequest.asURLRequest()
do {
urlRequest.httpBody = data
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
} catch {
throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error))
}
return urlRequest
}
and Alamofire request :
let enco : ParameterEncoding = MyCustomEncoding(data: ajsonData)
Alamofire.request(urlString, method: .post , parameters: [:], encoding: enco , headers: headers).validate()
.responseJSON { response in
switch response.result {
case .success:
print(response)
break
case .failure(let error):
print(error)
}
}
You need to send request like below in swift 3
let urlString = "https://httpbin.org/get"
Alamofire.request(urlString, method: .post, parameters: ["foo": "bar"],encoding: JSONEncoding.default, headers: nil).responseJSON {
response in
switch response.result {
case .success:
print(response)
break
case .failure(let error):
print(error)
}
}
Swift 5 with Alamofire 5:
AF.request(URL.init(string: url)!, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: headers).responseJSON { (response) in
print(response.result)
switch response.result {
case .success(_):
if let json = response.value
{
successHandler((json as! [String:AnyObject]))
}
break
case .failure(let error):
failureHandler([error as Error])
break
}
}
Alamofire using post method
import UIKit
import Alamofire
class ViewController: UIViewController {
let parameters = [
"username": "foo",
"password": "123456"
]
let url = "https://httpbin.org/post"
override func viewDidLoad() {
super.viewDidLoad()
Alamofire.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: [:]).responseJSON {
response in
switch (response.result) {
case .success:
print(response)
break
case .failure:
print(Error.self)
}
}
}
This will work better in Swift 4.
let url = "yourlink.php". // This will be your link
let parameters: Parameters = ["User_type": type, "User_name": name, "User_email": email, "User_contact": contact, "User_password": password, "from_referral": referral] //This will be your parameter
Alamofire.request(url, method: .post, parameters: parameters).responseJSON { response in
print(response)
}
Please find the code below
**
pod 'Alamofire', '~> 5.4'
**
**
pod 'ObjectMapper', '~> 4.2'
**
**
pod 'SwiftyJSON'
**
pod 'TPKeyboardAvoiding'
Use Model
import ObjectMapper
class LoginModel : Mappable{
var status : String?
var data : [DataModel]?
var message : String?
required init?(map: Map) {
}
func mapping(map: Map) {
status <- map["status"]
data <- map["data"]
message <- map["message"]
}
}
class DataModel : Mappable{
var access_token : String?
var isvideo : String?
required init?(map: Map) {
}
func mapping(map: Map) {
access_token <- map["access_token"]
isvideo <- map["isvideo"]
}
}
Call API
HTTPNetwork().getHTTPData("", parameters: LoginParameter, completion: {(successresponse) -> Void in
if let res = successresponse{
print("sucess token \(res["message"].string!)")
if let myuser = Mapper<DataModel>().map(JSONString: res["data"].rawString()!){
print("access_token \(myuser.access_token)")
}
}
}, error: {(errorresponse)-> Void in
if let res = errorresponse{
print("Error response token \(res)")
}
})
public func getHTTPData(_ request: String, parameters : Parameters?, completion: #escaping ( JSON?) -> Void, error: #escaping ( JSON?) -> Void){
AF.request(URL.init(string: "url")!, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: ["Content-Type":"application/json"]).responseJSON { (response) in
print(response.result)
switch response.result{
case .success:
if let json = response.value as? [String : Any]{
if let output:JSON = JSON(response.value!){
if json["isSuccess"] as? Int == 1{
completion(output)
}else{
error(output)
}
}
}else{
completion(nil)
}
case .failure:
completion(nil)
}
}
}
Alamofire for GET and POST method using Alamofire
1.Create a file named "GlobalMethod" for multiple use
import Alamofire
class GlobalMethod: NSObject {
static let objGlobalMethod = GlobalMethod()
func ServiceMethod(url:String, method:String, controller:UIViewController, parameters:Parameters, completion: #escaping (_ result: DataResponse<Any>) -> Void) {
var headers = Alamofire.SessionManager.defaultHTTPHeaders
headers["HeaderKey"] = "HeaderKey"
if method == "POST" {
methodType = .post
param = parameters
}
else {
methodType = .get
}
Alamofire.request(url, method: methodType, parameters: param, encoding: JSONEncoding.default, headers:headers
).responseJSON
{ response in
completion(response)
}
}
}
In the View Controller call "ServiceMethod" created in GlobalMethod by sending values to call API Service
let urlPath = "URL STRING"
let methodType = "GET" or "POST" //as you want
let params:[String:String] = ["Key":"Value"]
GlobalMethod.objGlobalMethod.ServiceMethod(url:urlPath, method:methodType, controller:self, parameters:params)
{
response in
if response.result.value == nil {
print("No response")
return
}
else {
let responseData = response.result.value as! NSDictionary
print(responseData)
}
}

Swift 2.0 Alamofire Completion Handler Return Json

My goal is to create a simple function where I pass in a url and it returns me JSON. I have looked around and found little examples of where a completion handler is implemented with Alamofire.
I am also using Swifty Json to help parse it out.
How do I turn what I have here to a function where it returns my Json.
func request() {
Alamofire.request(.GET, API_END_POINT)
.responseJSON {
response in
// swiftyJsonVar is what I would like this function to return.
let swiftyJsonVar = JSON(response.result.value!)
}
}
Swift 3+ and Alamofire 4+
// Call function
myFunction("bodrum") { response in
print(response["yourParameter"].stringValue)
}
// POST
func myFunction(_ cityName:String, completion: #escaping (JSON) -> ()) {
let token = "token"
let parameters = ["city" : cityName]
let headers = ["Authorization": "token"]
let url = URL(string: "url")!
let reqUrl = URLRequest(url: url)
Alamofire.request(reqUrl, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers)
.validate()
.responseJSON { response in
switch response.result {
case .Success:
let jsonData = JSON(data: response.data!)
completion(jsonData)
case .Failure(let error):
MExceptionManager.handleNetworkErrors(error)
completion(JSON(data: NSData()))
}
}
}
Swift 2 and Alamofire 3+
// POST
func myFunction(cityName:String, completion : (JSON) -> ()) {
Alamofire.request(.POST, "url", parameters: ["city" : cityName], encoding: ParameterEncoding.JSON, headers: ["Authorization": "token"])
.validate()
.responseJSON { response in
switch response.result {
case .Success:
let jsonData = JSON(data: response.data!)
completion(jsonData)
case .Failure(let error):
MExceptionManager.handleNetworkErrors(error)
completion(JSON(data: NSData()))
}
}
}
// GET
func myFunction(cityName:String, completion : (JSON) -> ()) {
Alamofire.request(.GET, "url", parameters: ["param1" : cityName], headers: ["Authorization": "token"])
.validate()
.responseJSON { response in
switch response.result {
case .Success:
let jsonData = JSON(data: response.data!)
completion(jsonData)
case .Failure(let error):
MExceptionManager.handleNetworkErrors(error)
completion(JSON(data: NSData()))
}
}
}
// Call function
myFunction("bodrum") { response in
print(response["yourParameter"].stringValue)
}

Resources