I am trying to call API in postman and its working fine, But If I am trying to call API in swift Alamofire, Its give me error-
My Code is-
func sendToServer(){
let urlString = "https://xxxxxxxxxx/TempService/SaveBarCodes"
let data: Parameters = ["SerialNo": "T8180399","Status":101]
Alamofire.request(urlString, method: .post, parameters: data,encoding: JSONEncoding.default, headers: nil).responseJSON {
response in
switch response.result {
case .success:
print(response)
break
case .failure(let error):
print(error)
}
}
}
Error is-
The JSON value could not be converted to System.Collections.Generic.List`1[BreakBulkModels.Model.WebapiModels.DtoInventoryApi]. Path: $ | LineNumber: 0 | BytePositionInLine: 1.
Your API accepts as parameters an array of JSON objects but you are currently sending a JSON object:
{
"SerialNo": "T8180399",
"Status": 101
}
Because Parameters is a typealias to Dictionary<String, Any> (what you need is Array<Dictionary<String, Any>>) you have to do your parameter encoding yourself and then call request(_:) function of Alamofire passing your URLRequest:
do {
let urlString = "https://xxxxxxxxxx/TempService/SaveBarCodes"
let url = try urlString.asURL()
var request = URLRequest(url: url)
let data = [["SerialNo": "T8180399", "Status": 101]]
request = try JSONEncoding.default.encode(request, withJSONObject: data)
Alamofire.request(request).responseJSON { response in
switch response.result {
case .success:
print(response)
break
case .failure(let error):
print(error)
}
}
} catch {
print(error)
}
Edit: With Alamofire v5 there is a more elegant way by using Encodable protocol:
struct BarCode: Encodable {
var SerialNo: String
var Status: Int
}
func sendToServer(){
let urlString = "https://xxxxxxxxxx/TempService/SaveBarCodes"
let data = [BarCode(SerialNo: "T8180399", Status: 101)]
AF.request(
urlString,
method: .post,
parameters: data,
encoder: JSONParameterEncoder.default
).responseJSON { response in
switch response.result {
case .success:
print(response)
break
case .failure(let error):
print(error)
}
}
}
Related
I want a diffrerent responseDecodable on the httpStatusCode
server return
if statusCode == 200
resonseBody
{id: number}
if statusCode 400..<500
resonseBody
{
code: String
timestamp: String
message: String
}
so now my code is
AF.request(url, method: .post, headers: header).responseData { response in
switch response.result {
case .success(let data) :
guard let response = response.response else {return}
let json = try? JSONSerialization.jsonObject(with: data)
switch response.statusCode {
case 200:
if let json = json as? [String: Any] , let message = json["id"] as? Int{print(message)}
case (400..<500):
if let json = json as? [String: Any] , let message = json["message"] as? String{print(message)}
default:
return
}
case .failure(let err) :
print(err)
}
}
I try this code convert responseDecodable
struct a: Codable {var id: Int}
struct b: Codable{
var code: String
var timestamp: String
var message: String
}
AF.request(url, method: .post, headers: header).responseDecodable(of: a.self) { response in
guard let data = response.value else {return}
print(data)
}
.responseDecodable(of: b.self) { response in
guard let data = response.value else {return}
print(data)
}
but this way Regardless statusCode return both a and b
I want
stautsCode == 200 return a or
statusCode 400..<500 return b
What should I Do?
AFAIK, Alamofire does not have a “decode one object for success and another for failure” implementation. You'll have to do this yourself.
If you really want a one distinct object for 2xx responses and another for 4xx responses, there are a few approaches:
Use validate to handle the 2xx responses, and manually decode 4xx responses in the error handler.
AF.request(url, method: .post, parameters: parameters, headers: header)
.validate(statusCode: 200 ..< 300) // only 2xx are auto-decoded for us; handle 4xx responses in `failure` handler
.responseDecodable(of: Foo.self) { response in
switch response.result {
case .failure(let error):
guard
let statusCode = response.response?.statusCode,
400 ..< 500 ~= statusCode,
let data = response.data,
let apiError = try? JSONDecoder().decode(ApiErrorResponse.self, from: data)
else {
print("other error:", error) // didn't parse `ApiErrorResponse` object, so obviously some other error
return
}
print("apiError:", apiError) // this is our parsed API error object
case .success(let foo):
print("success:", foo)
}
}
If you want, you could write your own ResponseSerializer to parse 2xx and 4xx responses differently:
struct ApiErrorResponse: Decodable, Error {
let code: String
let timestamp: String
let message: String
}
final class ApiResponseSerializer<T: Decodable>: ResponseSerializer {
lazy var decoder = JSONDecoder()
private lazy var successSerializer = DecodableResponseSerializer<T>(decoder: decoder)
private lazy var errorSerializer = DecodableResponseSerializer<ApiErrorResponse>(decoder: decoder)
public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> T {
if let error = error { throw error }
guard let response = response else { throw URLError(.badServerResponse) }
switch response.statusCode {
case 400 ..< 500:
let apiErrorObject = try errorSerializer.serialize(request: request, response: response, data: data, error: nil)
throw apiErrorObject
default:
return try successSerializer.serialize(request: request, response: response, data: data, error: nil)
}
}
}
And then you can do:
AF.request(url, method: .post, parameters: parameters, headers: header)
.response(responseSerializer: ApiResponseSerializer<Foo>()) { response in
switch response.result {
case .failure(.responseSerializationFailed(reason: .customSerializationFailed(error: let apiErrorObject))):
print("api response error:", apiErrorObject)
case .failure(let error):
print("some other error:", error)
case .success(let foo):
print("success:", foo)
}
}
I find the nesting of the parsed error object to be a little tedious, but it does abstract the 2xx vs 4xx logic out of the response/responseDecoder completion handler.
In both of these, I'm considering all 2xx responses as success, not just 200. Some servers return 2xx codes other than just 200.
i am trying to get a response that contain json from openweathermap api,
but from the debugger it seems that when he get to the code block of alamofire its just skips it
here is the block of code that i am using for this task
func printJson(){
Alamofire.request("https://api.openweathermap.org/data/2.5/find?appid=6ad1f143546b8c6d761ecbda6a34a005&q=yavne", method: .get).responseJSON { response in
if response.data != nil {
var json : JSON
do{
json = try JSON(data: response.data!)
print(json)
}catch{}
}
}
}
Use this helper class to make API calls.
class NetworkHandler {
static let shared = NetworkHandler()
func sendRequest(withUrl url:String,andBody body:[String:Any]? = [:],
completionHandler: #escaping ((_ status: Bool,_ response:Any) -> Void)) {
DispatchQueue.global(qos: .userInitiated).async {
Alamofire.request(url, method: .post, parameters: body,encoding: JSONEncoding.default, headers: nil).responseJSON {
response in
guard response.response?.statusCode == 200 else{
completionHandler(false,"Service Temporarily Unavailable.\nPlease check your internet connection or contact your Service provider.")
return
}
switch response.result {
case .success:
completionHandler(true,response.value!)
break
case .failure(let error):
completionHandler(false,error.localizedDescription)
}
}
}
}
}
The POST-parameters are not passed. Why?
Is there another possibility to make POST-API-Calls?
let parameters: [String: String] = ["username" : "test", "password" : "test"]
Alamofire.request("http://192.168.2.117/evk-ph/api/verify_user.api.php",
method: .post,
parameters: parameters,
encoding: JSONEncoding.default,
headers: nil).responseJSON { response in
switch response.result {
case .success:
print(response)
case .failure(let error):
print(error)
}
}
Here is a code that maybe work for use just do a simple changes in your code
func postJSON() {
let param = ["username":tFusername.text!,"password":tFpassword.text!] as NSDictionary //GET TEXTFIELD VALUE
let url = "YOUR URL HERE"
Alamofire.request(url, method: .post, parameters: (param as! Parameters), encoding: JSONEncoding.default).responseJSON { response in
switch response.result{
case .success(let json):
print(json)
DispatchQueue.main.async {
print(param)
//HANDLE YOUR CODE HERE
}
case .failure(let error):
print(error)
}
}
Use this Function in your viewDidLoad() or as you required.
Working on my first Alamofire request and a code that is updated to Alamofire 4 . Can't get this Alamofire.request .responseJSON properly updated. I am looking at the Migration documentation: but not clever enough. Any suggestions how it should look?
let APIKey = "myAPIkey"
func retrieveCurrentWeatherAtLat(lat: CLLocationDegrees, lon: CLLocationDegrees,
block: (_ weatherCondition: WeatherCondition) -> Void) {
let url = "http://api.openweathermap.org/data/2.5/weather?APPID=\(APIKey)"
let params = ["lat": lat, "lon": lon]
// Send the request
Alamofire.request(url, method: .get, parameters: params)
.responseJSON { request, response, result in
switch result {
case .Success(let json):
let json = JSON(json)
block(weatherCondition: self.createWeatherConditionFronJson(json))
case .Failure(_, let error):
print("Error: \(error)")
}
}
}
maybe can help you
Alamofire.request(url, method: .get, parameters: params, encoding: JSONEncoding.default).responseJSON { (response) in
switch response.result {
case .Success(let json):
let json = JSON(json)
block(weatherCondition: self.createWeatherConditionFronJson(json))
case .Failure(_, let error):
print("Error: \(error)")
}
}
let APIKey = "YourApiKeyComesHere"
// Sending the request to Open Weather
func retrieveCurrentWeatherAtLat(lat: CLLocationDegrees, lon: CLLocationDegrees,
block: #escaping (_ weatherCondition: WeatherCondition) -> Void) {
let url = "https://api.openweathermap.org/data/2.5/weather?APPID=\(APIKey)"
let params = ["lat": lat, "lon": lon]
print("Sending request... \(url)")
let request = Alamofire.request(url, method: .get, parameters: params, encoding: URLEncoding(destination: .queryString)).responseJSON { (response) in
print("Got response from server: \(response)")
switch response.result {
case .success(let json):
let json = JSON(json)
block(self.createWeatherConditionFronJson(json: json))
print("Success: \(json)") //test
case .failure(let error):
print("Error: \(error)")
}
}
request.resume()
}
When send GET request with parameters, url encoded in a different way
http://someurl/search-ads?attributes[elevator]=1&attributes[ranges][square][]=20.0&attributes[ranges][square][]=170.0&cities[]=somecity¤cy=kgs&has_images=0¬_first_floor=1¬_last_floor=1&order_type=sale&rating__gte=5&rating__lte=10000&specialty=2
but it should be
http://someurl/search-ads?specialty=7&order_type=sale&attributes={"ranges":"{\"square\":[2450,8190]}"}&cities=somecity&page=1
Is there any settings to change, to force Alamofire to encode in second way?
I am using Alamofire 3
Here is my method
func makeSearch(search: GeneralSearch) {
let request = Alamofire.request(.GET, SearchURL, parameters: Mapper().toJSON(search), encoding: .URL).validate().responseJSON {
response in
switch response.result {
case .Success:
if let responseValue = response.result.value {
print(responseValue)
}
break
case .Failure(let error):
print("Error: " + error.localizedDescription)
break
}
}
}