How to print result from alamofire response using codable - ios

New to codable and i have tried to create a class for alamofire with codable and tried to make an api request. I have getting some Swift.DecodingError.typeMismatch error and i figured it out it because of my model class. Now what i need is i want to print alamofire response in JSON(String) formate before it decoding so that i can identify the typeMismatch
static func performRequest<T:Decodable>(route:APIRouter, decoder: JSONDecoder = JSONDecoder(), completion:#escaping (Result<T,Error>)->Void) -> DataRequest {
return AF.request(route)
.responseDecodable (decoder: decoder){ (response: DataResponse<T>) in
print(response.result)
completion(response.result)
}
}
i want some code to print the actual result from alamofire

You can print the raw Data in your responseDecodable closure by grabbing it from the DataResponse:
print(response.data.map { String(decoding: $0, as: UTF8.self) } ?? "No data.")
You can also add a separate serializer just to see the String:
.responseDecodable { }
.responseString { }
If you just want to see the response for debugging, you can debugPrint the response in the closure. This will print the request and response body datas as Strings.
.responseDecodable(of: T.self) { response in
debugPrint(response)
}

Related

Alamofire publish decodable

I have a HTTP request to my server like this.
func loginUser( username: String, password: String )->AnyPublisher<UserModel, Error>{
let url = URL( string: "\(Credentials.BASE_URL)auth/login")!
let userSignInModel = SignInModel(username: username, password: password)
return AF.request(url,
method: .post,
parameters: userSignInModel,
encoder: JSONParameterEncoder.default)
.validate()
.publishDecodable(type: UserModel.self)
.value()
.mapError{$0 as Error}
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
and get response like this
self.dataManager.loginUser(username: self.logInUsername, password: self.logInPassword)
.sink { (response) in
print( response )
switch response {
case .failure( let error ):
self.createAlert(with: error.localizedDescription,
for: .loginAlert,
responseCode: error.asAFError?.responseCode)
case .finished:
break
}
} receiveValue: { (userModel) in
self.token = userModel.token
self.userID = userModel.user.id
}.store(in: &cancellableSet)
but the problem is that I am not able to get error message from the server, how it can be done?
There are several different approaches to parsing responses which return success or response values. Perhaps the simplest is to map any initial failures to your own error type which parses the information you need. For example, given this error type:
struct NetworkError: Error {
let initialError: AFError
let backendError: BackendError?
}
Where BackendError encapsulates the information returned from the backend. Then you can map the response from Alamofire.
AF.request(url,
method: .post,
parameters: userSignInModel)
.validate()
.publishDecodable(type: UserModel.self)
.map { response in
response.mapError { error in
// Check to see if it's an error that should have backend info.
// Assuming it is, parse the BackendError.
let backendError = response.data.flatMap { try? JSONDecoder().decode(BackendError.self, from: $0) }
return NetworkError(initialError: error, backendError: backendError)
}
}
Other alternatives include an enum-based response type that separates your success and failures, or your own response serializer which does the error parsing internally.

Extract response data from api call in alamofire

i've read many documents about getting the response object from the api , but cant derive how to extract the data. I've used alamofire for api call . The api call is like
AF.request("http://10.177.41.163:9000/signup",
method: .post,
parameters: parameters,
encoder: JSONParameterEncoder.default).responseJSON{ response in
print(response.result)
in my print statement i get the responses as
`success({
error = {
code = PC05;
message = "User already exsists";
};
payload = {
};
success = 0;
})`
which is fine , but i want to extract suppose the error code, how to achieve that? and in general how to extract data from responses in swift.
You need to decode the jSON response, so create a Model to decode this, of course also check the response if it was successful before, you'll set an example:
Declare yourself a model:
struct RootResponse : Decodable {
var error: ErrorStruct
var payload: PayloadStruct
var success: Int
}
struct ErrorStruct: Decodable {
var code: String
var message: String
}
struct PayloadStruct : Decodable {
var ?
}
Once you've declared your model based on your jSON response, then you can switch to the function that makes the request to you:
AF.request("http://10.177.41.163:9000/signup",
method: .post,
parameters: parameters,
encoder: JSONParameterEncoder.default).responseJSON{ response in
print(response.result)
switch response.result {
case .success:
if let data = response.data {
print(data)
// Convert This in JSON
do {
let responseDecoded = try JSONDecoder().decode(RootResponse.self, from: data)
print("USER: ", responseDecoded.error.code, "Etc...")
}catch let error as NSError{
print(error)
}
}
case .failure(let error):
print("Error:", error)
}
}
I hope that's been helpful.
AF.request("http://10.177.41.163:9000/signup",
method: .post,
parameters: parameters,
encoder: JSONParameterEncoder.default).responseJSON{ response in
print(response.result)
let responseJSON = JSON(response.result) // response converted in json format
let statusCode = responseJSON["error"]["code"].stringValue // You can get status code
Note : Install pod 'SwiftyJSON' to convert response.result in JSON format.

Alamofire - Bad request

I am afraid I cannot share the API url. But I have checked on Postman, it works. It is a POST request and following is the response :
{
"user_key": "b0aebdedb15e2beaaf479ca3c4f8227e8e970681"
}
Postman screenshot :
In code, this is the request I am making using Alamofire :
Alamofire.request("some url", method: .post, parameters: params, encoding: URLEncoding.httpBody, headers: ["Content-Type":"application/json"])
.responseObject { (response: DataResponse<User>) in
let userResponse = response.result.value
print("")
}
But userResponse comes to be nil. This is the User object :
import ObjectMapper
class User: Mappable {
var authToken: String?
required init?(map: Map) {
}
func mapping(map: Map) {
self.authToken <- map["user_key"]
}
}
I am using ObjectMapper here.
Assuming the it is not a JSON object, I tried to handle it as a String :
Alamofire.request("some url", method: .post, parameters: params, encoding: URLEncoding.httpBody, headers: ["Content-Type":"application/json"])
.responseString { (response: DataResponse<String>) in
let dataUser = response.data as! Any
let dataUser1 = response.data as! AnyObject
let error = response.error
let code = response.response?.statusCode
print(response.value)
print(response.result.value)
}
Still, nothing. I am not able to retrieve the value. The status code however comes out to be 400 (bad request).
What exactly is it ? JSON object or String ? How do I fix this ?
Just try to replace
this URLEncoding.httpBody to JSONEncoding.default
JSONEncoding.default
Uses JSONSerialization to create a JSON representation of the parameters object, which is set as the body of the request. The Content-Type HTTP header field of an encoded request is set to application/json.
Alamofire reference

Swift extension method for Alamofire to return SwiftyJSON result

I migrated an app from Swift 2.2 to 3.0 which used an extension method from the Alamofire-SwiftyJSON project on GitHub. Alamofire-SwiftyJSON allows receiving the response from an Alamofire network request converted to a SwiftyJSON instance like this:
Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"])
.responseSwiftyJSON({ (request, response, json, error) in
print(json) // json is a SwiftyJSON 'JSON' instance
print(error)
})
The Alamofire-SwiftyJSON project was not updated for Swift 3 as of writing this question. I'm looking for an equivalent implementation of the responseSwiftyJSON extension method that works with Swift 3+ and Alamofire 4+.
Extension Methods
This solution incorporates a suggestion for working with Alamofire from the SwiftyJSON readme.
It is based on similar extensions included with Alamofire in ResponseSerialization.swift:
DataRequest.responseJSON(queue:options:completionHandler:)
DataRequest.jsonResponseSerializer(options:)
This solution works with Swift 3 and above. It was tested with Alamofire 4.2+ and SwiftyJSON 3.1.3+.
import Alamofire
import SwiftyJSON
extension DataRequest {
/// Adds a handler to be called once the request has finished.
///
/// - parameter options: The JSON serialization reading options. Defaults to `.allowFragments`.
/// - parameter completionHandler: A closure to be executed once the request has finished.
///
/// - returns: The request.
#discardableResult
public func responseSwiftyJSON(
queue: DispatchQueue? = nil,
options: JSONSerialization.ReadingOptions = .allowFragments,
completionHandler: #escaping (DataResponse<JSON>) -> Void) -> Self {
return response(
queue: queue,
responseSerializer: DataRequest.swiftyJSONResponseSerializer(options: options),
completionHandler: completionHandler
)
}
/// Creates a response serializer that returns a SwiftyJSON instance result type constructed from the response data using
/// `JSONSerialization` with the specified reading options.
///
/// - parameter options: The JSON serialization reading options. Defaults to `.allowFragments`.
///
/// - returns: A SwiftyJSON response serializer.
public static func swiftyJSONResponseSerializer(
options: JSONSerialization.ReadingOptions = .allowFragments) -> DataResponseSerializer<JSON> {
return DataResponseSerializer { _, response, data, error in
let result = Request.serializeResponseJSON(options: options, response: response, data: data, error: error)
switch result {
case .success(let value):
return .success(JSON(value))
case .failure(let error):
return .failure(error)
}
}
}
}
Example Use:
Alamofire.request("https://httpbin.org/get").validate().responseSwiftyJSON {
response in
print("Response: \(response)")
switch response.result {
case .success(let json):
// Use SwiftyJSON instance
print("JSON: \(json)")
case .failure(let error):
// Handle error
print("Error: \(error)")
}
}

How to change an NSData to an NSDictionary or JSON

I have a swift app that calls api and recieves back a JSON.
self.get(url).responseJSON { (response) -> Void in
self.notify(FetchCompletion, response: response.response, result: response.result)
print("response: ")
print(response.response)
print("data: ")
let dataExample = response.data
print(dataExample)
let dictionary:NSDictionary? = NSKeyedUnarchiver.unarchiveObjectWithData(dataExample!)! as? NSDictionary
}
And it prints out:
...
data:
Optional(<7b227374 61747573 223a2234 3034222c 22657272 6f72223a 224e6f74 20466f75 6e64227d>)
fatal error: unexpectedly found nil while unwrapping an Optional value
I want to just print out the data is some readable form by converting to a dictionary.
EDIT 1
My get() function is defined as such:
func get(path: String) -> Request {
return self.get(path, data: NSDictionary())
}
EDIT 2
I am using
import UIKit
import Alamofire
import SwiftyJSON
EDIT 3
I attempted to follow the example here:How to parse JSON in Swift using NSURLSession
But get the error "unresolved identifier 'JSONSerialization'"
EDIT 4 / probable answer
var newdata = JSON(data: dataExample!)
print(newdata)
outputted:
{
"status" : "404",
"error" : "Not Found"
}
I believe that this is a json and I am properly printing the readable data, so i believe this is the answer. I was led to this by the comment suggesting to use swiftJSON
A very standard way to convert to JSON from NSData, feel free to ask a question
self.get(url).responseJSON { (response) -> Void in
self.notify(FetchCompletion, response: response.response, result: response.result)
print("response: ")
print(response.response)
print("data: ")
let dataExample = response.data
print(dataExample)
do {
let dictionary = try NSJSONSerialization.JSONObjectWithData(dataExample!, options: NSJSONReadingOptions()) as! NSDictionary
}
catch {
// catch error.
}
}

Resources