I have a very simple http request which will return a JSON data. Here is my code:
let query = NSString(format: "http://glosbe.com/gapi/translate?from=eng&dest=eng&format=json&phrase=test",src, dest, phrase )
let url = NSURL(string: query)
let task = NSURLSession.sharedSession().dataTaskWithURL(url) {(data, response, error) in
if let httpRes = response as? NSHTTPURLResponse {
println("status code=",httpRes.statusCode)
if httpRes.statusCode == 200 {
println(NSString(data: data, encoding: NSUTF8StringEncoding))
// parse data
let phrase = Phrase.parse(data)
println(phrase.description)
}
}
}
task.resume()
Sometimes the completionHandler isn't called at all. I suspect it's the problem of the server. But when I input the same url into my browser and tried a dozens times. There was no problem at all. The data was returned everything when I refresh the browser.
Is there anything wrong in my code? Thanks
The code works OK for me. I suggest you can make this change to your code (an else clause):
if let httpRes = response as? NSHTTPURLResponse {
println("status code=",httpRes.statusCode)
if httpRes.statusCode == 200 {
println(NSString(data: data, encoding: NSUTF8StringEncoding))
// parse data
let phrase = Phrase.parse(data)
println(phrase.description)
}
} else {
println("error \(error)") // print the error!
}
So you will have a better idea if anything goes wrong
Related
I have a function that fetches data from a URL:
private func fetch(url: URL) -> String? {
var htmlString: String?
let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard error == nil, let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
return
}
if let mimeType = httpResponse.mimeType, mimeType == "text/html",
let data = data,
let string = String(data: data, encoding: .utf8) {
htmlString = string
}
}
task.resume()
return htmlString
}
This function works in a playground, when I test it as part of a package in XCode, it doesn't seem to run past the let task... statement. How do I fix this?
The dataTask rendition that returns the result immediately would only work if your device happened to have a cached response ready to deliver. Otherwise, it would return before the dataTask had a chance to complete.
One needs to wait for the response from the server before returning the result. In Swift concurrency, we would await:
enum WebError: Error {
case notSuccess(Int)
case notHtml
}
private func fetch(url: URL) async throws -> String? {
let (data, response) = try await URLSession.shared.data(from: url)
guard let response = response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
guard 200...299 ~= response.statusCode else {
throw WebError.notSuccess(response.statusCode)
}
guard
response.mimeType == "text/html",
let string = String(data: data, encoding: .utf8)
else {
throw WebError.notHtml
}
return string
}
Note, I also throw errors, so that if something goes wrong, the caller can catch the error and successfully diagnose what went wrong.
See WWDC 2021 video Use async/await with URLSession.
I'm performing a post request over my rest api that I built in node. Then the data are stored in a mongodb collection.
This is my code that I use to post the request:
// create dataTask using the session object to send data to the server
let task = session.dataTask(with: request) { data, response, error in
if let error = error {
print("Post Request Error: \(error.localizedDescription)")
return
}
// ensure there is valid response code returned from this HTTP response
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode)
else {
print("Invalid Response received from the server")
return
}
// ensure there is data returned
guard let responseData = data else {
print("nil Data received from the server")
return
}
do {
// create json object from data or use JSONDecoder to convert to Model stuct
if let jsonResponse = try JSONSerialization.jsonObject(with: responseData, options: .mutableContainers) as? [String: ErrorHandler] {
print(jsonResponse)
DispatchQueue.main.async {
self?.isLoading = false
self?.signedIn = true
}
} else {
print("data maybe corrupted or in wrong format")
throw URLError(.badServerResponse)
}
} catch let error {
print(error.localizedDescription)
}
}
task.resume()
The problem is that the responseJson is always nil. I tried to perform the same request with postman and I get the response correctly. What is the problem? Also because the data are correctly uploaded everywhere.
This is my postman result of the same post request.
I have some issues with converting data.
My code looks like:
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data,
let response = response as? HTTPURLResponse,
error == nil else {
// check for fundamental networking error
print("error", error ?? "Unknown error")
return
}
guard (200 ... 299) ~= response.statusCode else {
// check for http errors
print("statusCode should be 2xx, but is \(response.statusCode)")
print("response = \(response)")
return
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(responseString ?? "")")
DispatchQueue.main.async {
let webVC = WebViewController(urlString: responseString!)
self.navigationController?.pushViewController(webVC, animated: true)
}
} task.resume()
responseString prints: "html page code"
Need I convert data to urlString or something similar to url?
How can I solve it? Thank you for your time
Loading a HTML string in a WKWebview (just import WebKit)
let webView = WKWebView()
webView.loadHTMLString("<html><body><p>Hello!</p></body></html>", baseURL: nil)
Loading a HTML string in a UIWebview
let webView = UIWebView()
webView.loadHTMLString("<html><body><p>Hello!</p></body></html>", baseURL: nil)
If this is not what you are looking for, add more points to make your question understandable, thanks :)
What does your 'redirect' mean?
If just a 302 HTTP response use WKWebView: https://developer.apple.com/documentation/webkit/wkwebview instead of URLSession
If you have to parse URLSession response, you have to obtain the result and discuss with your server-side programmer about the response. responseString prints: "html page code" is obviously incorrect URL
Alamofire.request(NEWS_FEED_URL).responseJSON { response in
guard let newsResponse = response.result.value as? [[String:String]] else{
print("Error")
return
}
print("JSON: \(newsResponse)")
This is my alamofire code to get response from server. Most of the time it is working fine but sometime it goes failure and print Error. Even if I paste print("JSON:", newsResponse) in failure block it shows the response but it is not going to the success block. I also print the status code once. Its giving me 200. My Internet is working good, the related url is giving response in postman. But sometimes it is not working why?
Try this method
func apiRequest(method:String, urlMethod:String, parametersDictionary:NSMutableDictionary, success:#escaping successDictionaryBlock, failure: #escaping failBlockErrorMessage){
let requestUrl = "Request URL"
Alamofire.request(requestUrl, method: .post, parameters: (parametersDictionary as NSDictionary) as? Parameters , encoding: JSONEncoding.default, headers: nil).responseJSON { response in
print(response)
print(requestUrl)
if(response.result.error == nil){
if((response.response?.statusCode)! < 500){
if(response.response?.statusCode == 200){
if let JSON = response.result.value {
print(JSON)
let dict = JSON as! NSDictionary
let status :Bool = dict["status"] as! Bool
if(status){
success(dict)
}else{
failure(dict["message"] as! String)
}
}
}else{
failure("Something went wrong please try again")
}
}else{
failure("Something went wrong please try again")
}
}
}
}
Why would my code below successfully return with data, with a statusCode of 200 but fail to convert the returned NSData to an NSString?
var session: NSURLSession
func init() {
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
session = NSURLSession(configuration: config)
}
func getStatic(url:NSURL) {
let request = NSMutableURLRequest(URL: url)
let dataTask = session.dataTaskWithRequest(request) {(data, response, error) in
if error != nil {
// handle error
} else {
// data has a length of 2523 - the contents at the url
if let httpRes = response as? NSHTTPURLResponse {
// httpRes is 200
let html = NSString(data:data, encoding:NSUTF8StringEncoding)
// **** html is nil ****
}
}
}
dataTask.resume()
}
The code is indeed correct.
The URL I was trying to load had non-UTF8 characters and so the encoding attempted by NSString(data:data, encoding:NSUTF8StringEncoding) failed.
Removing none UTF8 characters fixed the problem.
Or selecting an appropriate encoding, NSISOLatin1StringEncoding for my content, also worked.
It looks like it should be fine, to me at least. I'm just dabbling in Swift, but I've done my enclosures (not sure if thats the right name) slightly changed like below. Did you try converting data to NSString prior to your if let httpRes = response as? NSHTTPURLResponse line? Maybe the data variable doesn't actually have the html in it. I have code written almost exactly the same with the changes below that I'm able to successfully convert data to a NSString.
let dataTask = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
if error != nil {
// handle error
} else {
if let httpRes = response as? NSHTTPURLResponse {
let html = NSString(data:data, encoding:NSUTF8StringEncoding)
}
}
})
Hope it somehow helps.