I am using Alamofire for api call. but not hit the API. And also how to set the header in Alamofire.
func signupApiASyncPostCall(_ url:String, params:[String: AnyObject]?, success successBlock :#escaping apiSuccess,failure failureBlock :#escaping apiFailure) {
let Auth_header = ["Content-Type" : "application/json", "application/json" : "Accept"]
Alamofire.request(url, method: .post, parameters: params, encoding: URLEncoding.default, headers: Auth_header)
.responseJSON { response in
print("\(response.request?.url)") // original URL request
//print(response.response) // URL response
//print(response.data) // server data
print(response.result) // result of response serialization
if response.result.isSuccess {
successBlock(response.result.value as? NSDictionary)
print(successBlock(response.result.value as? NSDictionary))
} else {
let httpError: NSError = response.result.error! as NSError
let statusCode = httpError.code
let error:NSDictionary = ["error" : httpError,"statusCode" : String(statusCode)]
failureBlock(error)
}
}
}
Related
New to swiftui and don't understand why the JSONDecoder() line in the first code throws
[SwiftUI] Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates.
This to me is not updating ui so why is this showing?
do {
// pass the request type, bearer token, and email / password ( which are sent as POST body params )
let request = L.getRequest(requestType:"POST", token: token, email: self.username, password: self.psw)
L.fetchData(from: request) { result in
switch result {
case .success(let data):
// covert the binary data to a swift dictionary
do {
let response = try JSONDecoder().decode(WpJson.self, from: data)
for (key, title) in response.allowedReadings {
let vimeoId = Int( key )!
let vimeoUri = self.buildVimeoUri(vimeoId: key)
self.addReadingEntity(vimeoUri: vimeoUri, vimeoId: vimeoId, title: title)
}
self.writeToKeychain(jwt:response.jwt, displayName: response.displayName)
readings = self.fetchReadings()
}
catch {
self.error = error.localizedDescription
}
case .failure(let error):
self.error = error.localizedDescription
}
}
}
I tried wrapping a main queue around the do-catch in the L.fetchData(from: request) { result in but this did not help
DispatchQueue.main.async { [weak self] in
Here is the Login protocol, again without any ui work:
import Foundation
import SwiftUI
struct Login: Endpoint {
var url: URL?
init(url: URL?) {
self.url = url
}
}
protocol Endpoint {
var url: URL? { get set }
init(url: URL?)
}
extension Endpoint {
func getRequestUrl() -> URLRequest {
guard let requestUrl = url else { fatalError() }
// Prepare URL Request Object
return URLRequest(url: requestUrl)
}
func getRequest(requestType:String="POST", token:String, email:String="", password:String="") -> URLRequest {
var request = self.getRequestUrl()
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
if ( "" != email && "" != password && requestType == "POST") {
let parameters:[String:String?] = [
"email": email,
"password": password
]
// Run the request
do {
// pass dictionary to nsdata object and set it as request body
request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
} catch let error {
print(error.localizedDescription)
}
}
return request;
}
func fetchData(from request: URLRequest, completion: #escaping (Result<Data, NetworkError>) -> Void) {
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
completion(.success(data))
} else if error != nil {
// any sort of network failure
completion(.failure(.requestFailed))
} else {
// this ought not to be possible, yet here we are
completion(.failure(.unknown))
}
}.resume()
}
}
extension URLSession {
func dataTask(with request: URLRequest, completionHandler: #escaping (Result<(Data, HTTPURLResponse), Error>) -> Void) -> URLSessionDataTask {
return dataTask(with: request, completionHandler: { (data, urlResponse, error) in
if let error = error {
completionHandler(.failure(error))
} else if let data = data, let urlResponse = urlResponse as? HTTPURLResponse {
completionHandler(.success((data, urlResponse)))
}
})
}
}
Do you have any idea on how to fix this?
Wrap it right in place of assignment
catch {
DispatchQueue.main.async {
self.error = error.localizedDescription
}
}
case .failure(let error):
DispatchQueue.main.async {
self.error = error.localizedDescription
}
}
I am using this Alamofire request and returning a json
let todoEndpoint: String = "https://api.abc.com/api/v3/products?pid=uid8225&format=json&&offset=0&limit=10"
Alamofire.request(todoEndpoint)
.responseJSON { response in
guard let json = response.result.value as? [String: Any] else {
print("didn't get todo object as JSON from API")
print("Error: \(response.result.error)")
return
}
print(json)
}
Now i have do loop where i want to use this json value but i am getting:
error : Use of unresolved identifier json ?
do {
for (index,subJson):(String, JSON) in json {
print("Index :\(index) Title: \(subJson)" )
} catch
{
print("there was an error")
}
As mentioned :
https://github.com/Alamofire/Alamofire#response-string-handler
" the result of a request is only available inside the scope of a response closure. Any execution contingent on the response or data received from the server must be done within a response closure."
How can i use this json value outside scope of response closure ?
Can you please suggest
Is there any completion handler i need to write and how can it be done ?
Thanks
Better use the SwiftyJson for easy json parsing with Almofire like bellow :
import Alamofire
import SwiftyJSON
static func getRequest(urlString: URL?, Parameter:NSDictionary?, completion: #escaping (_ serverResponse: AnyObject?,_ error:NSError?)->()){
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 write this function in a separate class like NetworkLayer and then call it from any class for the WebService call as given bellow :
let url = NSURL(string: yourWebServiceUrlString)
NetworkLayer.getRequest(urlString: url as URL?, Parameter: nil) { (serverResponse, error) in
if (error == nil){
print("Server response: \(serverResponse)")
}
}
Note: You can also pass the parameter dictionary in it.
I have APIManager singleton class and have a function to get data from server like this:
func scanOrder(order: String, completion:#escaping Handler){
let url = K.API_URL + "/api/containers/picking/" + order
Alamofire.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: getHeader()).responseJSON { (response) in
DispatchQueue.main.async {
completion(response)
}
}
}
and I call this function in other class like this:
apiMan.scanOrder(order: tfCode.text!) { (response) in
...
}
while waiting for server to response, my UI is blocked. I tried to wrap alamofire request call within DispatchQueue.global().async but it still blocks the UI.
Please help!
I never used Alamofire.request with DispatchQueue.main.async like you do. The reason is that Alamofire in combination with completion blocks already operates async and shouldn't block the UI, which is settled in the Main Thread.
Have you tried something like:
class NetworkManager {
func scanOrder(order: String, completion:#escaping (Any?) -> Void){
let url = "https://example.com/api/containers/picking/" + order
Alamofire.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: AppConfiguration.sharedInstance.defaultHeader())
.responseJSON { response in
guard response.result.isSuccess else {
Log.info("Error while fetching: \(response.result.error)")
completion(nil)
return
}
guard let responseJSON = response.result.value as? [String: AnyObject] else {
Log.info("Invalid information received from service")
completion(nil)
return
}
completion(responseJSON)
}
}
}
Call:
class CallingClass {
func scanOrder(order:String){
let manager = NetworkManager()
var result: Any?
manager.scanOrder(order: "example") { response in
result = response
}
print(result as Any)
}
}
I am using alamofire for networking in swift3.0 project. I need to get data from woocommerce rest apis e.g http://woocommerce.github.io/woocommerce-rest-api-docs/#product-properties
Below is the code I have added in my project. I think there is an authentication issue.
let params = ["oauth_consumer_key":consumerKey, "oauth_consumer_secret":consumerSecret, "oauth_timestamp":timeInterval, "oauth_nonce": nonce, "oauth_signature_method": "HMAC-SHA1", "oauth_version": "1.0"] as [String : Any];
Alamofire.request(url, parameters: params)
.responseJSON { response in
print(response.request) // original URL request
print(response.response) // HTTP URL response
print(response.data) // server data
print(response.result) // result of response serialization
if let JSON = response.result.value {
print("JSON: \(JSON)")
}
}
Response:
{
code = "woocommerce_rest_cannot_view";
data = {
status = 401;
};
message = "Sorry, you cannot view this resource.";
}
Got these errors with this code:
if let url = URL(string: "<valid web service url string>") {
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("Basic \(base64Authorization)", forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request, completionHandler: {(data, response, error) in
if error == nil {
The same code returns no error with Xcode 7.3 but errors in Xcode 8 after converting to Swift 3.
This happened because of the Swift 3 proposal SE-0054.
base64Authorization was declared this way:
static var base64Authorization:String! {
get {
if base64Auth == nil {
let keyString = "<my key string>"
let plainTextData = keyString.data(using: .utf8, allowLossyConversion: false) as Data!
base64Auth = plainTextData!.base64EncodedString(options: .endLineWithLineFeed) as String!
}
return base64Auth
}
}
base64Authorization returned an Optional which messed up the "Basic \(base64Authorization)" HTTP setting.
This declaration of base64Authorization fixed the problem:
static var base64Authorization:String {
get {
if base64Auth == nil {
let keyString = "<my key string>"
let plainTextData = keyString.data(using: .utf8, allowLossyConversion: false) as Data!
base64Auth = plainTextData!.base64EncodedString(options: .endLineWithLineFeed) as String
}
return base64Auth!
}
}