One request - Two responses. Which end is creating the problem (Front / Back) - swift3

Problem:
When I call a request from iOS swift based app, then the server is responding two responses.
Inputs:
In my request, am sending some user values including one base64 image string. I already ensure that my app is calling request only one time.
Outputs:
When we opened the server log, it printed two set of request and response. But, difference that the first one is not having base64 image string and second one is having it. Thats why am receiving two different responses.
Questions:
What end is causing this problem - Front / back end?
Note:
I given front code below but I can’t provide back end code.
let task = urlSession.dataTask(with: urlRequest, completionHandler: {
(data, response, error) in
if error != nil
{
print("Error ==",error!.localizedDescription);
onFailure(error!.localizedDescription)
}
else
{
let httpResponse = response as! HTTPURLResponse
let statusCode = httpResponse.statusCode
// For some critical cases:
//print("Status code: ", statusCode)
//print("http Response: ", httpResponse)
// JSON serialize
do {
let jsonResponse = try JSONSerialization.jsonObject(with: data!, options: .allowFragments)
print("Server Response == ",jsonResponse)
onSuccess(statusCode, jsonResponse)
}
catch
{
onFailure("JSON Parser Error")
}
}
})`

Related

Fatal error: Session manager did not return a task: file

I am currently playing around with the Vimeo API and following the setup process and the guided readme found here:
(https://github.com/vimeo/VimeoNetworking)
All I am doing is pulling down publicly available videos from Vimeo except I have been receiving
Fatal error: Session manager did not return a task: file
everything else works and I am able to use my own token for authentication.
Here is the code I have right now that throws this error:
What am I doing wrong or missing?
let queryURL = URL(string: "/channels/staffpicks/videos")
let videoRequest = Request<[VIMVideo]>(path: queryURL!.absoluteString)
guard let sessionClient = _client else {
return []
}
let _ = sessionClient.request(videoRequest, completion: {
results in
switch results {
case .success(let response):
let videos: [VIMVideo] = response.model
for video in videos
{
print("retrieved video: \(video)")
}
vVideo = videos
break
case .failure(let error):
print(error.localizedDescription)
break
}
})
Sorry I am late but this worked for me (using Swift 4.2):
let appConfiguration = AppConfiguration(
clientIdentifier: Constants.VIMEO_CLIENT_IDENTIFIER,
clientSecret: Constants.VIMEO_CLIENT_SECRET,
scopes: [.Public], keychainService: "")
let vimeoSessionManager = VimeoSessionManager.defaultSessionManager(
baseUrl: VimeoBaseURL,
accessToken: Constants.VIMEO_ACCESS_TOKEN,
apiVersion: "3.4")
let vimeoClient = VimeoClient(
appConfiguration: appConfiguration,
sessionManager: vimeoSessionManager)
let videoRequest = Request<[VIMVideo]>(path: "/videos?query=dragon+ball")
vimeoClient.request(videoRequest) {
result in
switch result {
case .success(let response):
let videos: [VIMVideo] = response.model
print("\n\n retrieved videos: \(videos) \n\n")
case .failure(let error):
print("\n\n error retrieving videos: \(error) \n\n")
}
}
I'am almost sure you needed to add a session manager, but not 100% because haven't seen how you initialize the client and the other variables, so I am just adding this example.
Remember to get clientIndentifier, clientSecret and accessToken in [https://developer.vimeo.com/apps][1] (after you've created your app).
This is using a public accessToken, if you need authenticated access just add the .Private and .Interact scopes to the scopes array in appConfiguration, and to get an 'Authenticated' accessToken.
Also, please notice that I am using "/videos?query=dragon+ball" as an example.

Issue retrieving http header -file path value

I'm trying to retrieve a custom header that is returned from an HTTP Get request. I'm able to retrieve all the other header values.
Alamofire.request(
apiURL,
parameters: ["UserID": post.userID]
)
.responseData { response in
guard response.result.isSuccess else {
print("Error while fetching Data: \(String(describing: response.result.error))")
return
}
if let headers = response.response?.allHeaderFields as? [String: String]{
if let myHeader = headers["profileImageURL"] as? String {
print(myHeader)
}
Using the developer tool in Chrome I can see the Header is being returned. Perhaps I'm casting incorrectly? The Header name is profileImageURL
The userID parameter that I was passing to the HTTP Get was incorrect.

AWS API Gateway error response generates 502 "Bad Gateway"

I have an API Gateway with a LAMBDA_PROXY Integration Request Type. Upon calling context.succeed in the Lambda, the response header is sent back with code 302 as expected (shown below). However, I want to handle 500 and 404 errors, and the only thing I am sure about so far, is that I am returning the error incorrectly as I am getting 502 Bad Gateway. What is wrong with my context.fail?
Here is my handler.js
const handler = (event, context) => {
//event consists of hard coded values right now
getUrl(event.queryStringParameters)
.then((result) => {
const parsed = JSON.parse(result);
let url;
//handle error message returned in response
if (parsed.error) {
let error = {
statusCode: 404,
body: new Error(parsed.error)
}
return context.fail(error);
} else {
url = parsed.source || parsed.picture;
return context.succeed({
statusCode: 302,
headers: {
Location : url
}
});
}
});
};
If you throw an exception within the Lambda function (or context.fail), API Gateway reads it as if something had gone wrong with your backend and returns 502. If this is a runtime exception you expect and want to return a 500/404, use the context.succeed method with the status code you want and message:
if (parsed.error) {
let error = {
statusCode: 404,
headers: { "Content-Type": "text/plain" } // not sure here
body: new Error(parsed.error)
}
return context.succeed(error);
I had the same problem, in my case the issue was that my function was not returning anything in context.done(). So instead of context.done(null), I did context.done(null, {});
I've gotten 502's from multiple things. Here are the ones I have figured out so far.
Answer 1:
claudia generate-serverless-express-proxy --express-module {src/server?}
If you are not using claudia and express, this answer won't help you.
Answer 2:
Lambda function->Basic Settings->Timeout. Increase it to something reasonable. It defaults to 3 seconds. But the first time building it typically takes longer.
I had a problem like this, I was returning JSON as a JavaScript Object in the body, but you are supposed to return it as a string. All I had to do was do a JSON.stringify(dataobject) to convert the JSON into a string before returning it.
https://aws.amazon.com/premiumsupport/knowledge-center/malformed-502-api-gateway/

swift 3 alamofire - get request gives response serialization failed

I'm using devise on ruby on rails for authentication. Taking it one step at a time, I have disabled the cookie authentication in order to test retrieving results prior to authentication.
If I go to my browser and navigate to the url that Alamofire is visiting, I get results in JSON format like this :
{"id":250,"name":null,"username":"walker","bio":null,"gender":null,"birth_date":null,"profile_image_url":null}
I'm requesting the alamofire request like this:
Alamofire.request(requestPath, method: .get, parameters: [:], encoding: JSONEncoding.default, headers: [:]).responseJSON { (response) in
if (response.result.isFailure) {
completion(false, "")
} else {
if let result = response.result.value {
completion(true, result)
}
}
}
This is all inside of another method which simply provides with a completion handler as you can see inside of the completion handler of the Alamofire request.
I get an error every single time.
The error says:
responseSerializationFailed : ResponseSerializationFailureReason
What am i doing wrong?
This error indicates that your response is not a JSON formatted data(or something wrong with your API Response), try to use something like post man to check your API response and to make sure every thing is ok before requesting with to swift

How to make synchronous url requests with swift 3

I know the question has been asked before and I agree with most answers that claim it is better to follow the way requests are made async with URLSession in Swift 3. I haver the following scenario, where async request cannot be used.
With Swift 3 and the ability to run swift on servers I have the following problem.
Server Receives a request from a client
To process the request the server has to send a url request and wait for the response to arrive.
Once response arrives, process it and reply to the client
The problem arrises in step 2, where URLSession gives us the ability to initiate an async data task only. Most (if not all) server side swift web frameworks do not support async responses. When a request arrives to the server everything has to be done in a synchronous matter and at the end send the response.
The only solution I have found so far is using DispatchSemaphore (see example at the end) and I am not sure whether that will work in a scaled environment.
Any help or thoughts would be appreciated.
extension URLSession {
func synchronousDataTaskWithURL(_ url: URL) -> (Data?, URLResponse?, Error?) {
var data: Data?
var response: URLResponse?
var error: Error?
let sem = DispatchSemaphore(value: 0)
let task = self.dataTask(with: url as URL, completionHandler: {
data = $0
response = $1
error = $2 as Error?
sem.signal()
})
task.resume()
let result = sem.wait(timeout: DispatchTime.distantFuture)
switch result {
case .success:
return (data, response, error)
case .timedOut:
let error = URLSessionError(kind: URLSessionError.ErrorKind.timeout)
return (data, response, error)
}
}
}
I only have experience with kitura web framework and this is where i faced the problem. I suppose that similar problems exist in all other swift web frameworks.
In Vapor, you can use the Droplet's client to make synchronous requests.
let res = try drop.client.get("https://httpbin.org")
print(res)
Additionally, you can use the Portal class to make asynchronous tasks synchronous.
let res = try Portal.open { portal in
asyncClient.get("https://httpbin.org") { res in
portal.close(with: res)
}
}
Your three-step problem can be solved via the use of a completion handler, i.e., a callback handler a la Node.js convention:
import Foundation
import Kitura
import HeliumLogger
import LoggerAPI
let session = URLSession(configuration: URLSessionConfiguration.default)
Log.logger = HeliumLogger()
let router = Router()
router.get("/test") { req, res, next in
let datatask = session.dataTask(with: URL(string: "http://www.example.com")!) { data, urlResponse, error in
try! res.send(data: data!).end()
}
datatask.resume()
}
Kitura.addHTTPServer(onPort: 3000, with: router)
Kitura.run()
This is a quick demo of a solution to your problem, and it is by no means following best Swift/Kitura practices. But, with the use of a completion handler, I am able to have my Kitura app make an HTTP call to fetch the resource at http://www.example.com, wait for the response, and then send the result back to my app's client.
Link to the relevant API: https://developer.apple.com/reference/foundation/urlsession/1410330-datatask