Swift REST Request PUT Optional(502 Bad Gateway: Registered endpoint failed to handle the request.) - swift

I'm trying to do a PUT request using Swift. In a REST client, when I try to do a REST request the following way:
In Body- x-www-form-urlencoded, I add vote=1 and with id being taken in the param for example: /user/:id, it works!
I try to do the same in Swift code, it does not work and I get responseString = Optional(502 Bad Gateway: Registered endpoint failed to handle the request.
Here is my code:
var baseURL = "http://<domain>/user"
let putURL = baseURL + "/\(id)"
print(putURL)
let request = NSMutableURLRequest(URL: NSURL(string: putURL)!)
request.HTTPMethod = "PUT"
let putString = "vote=1"
request.HTTPBody = putString.dataUsingEncoding(NSUTF8StringEncoding)
request.timeoutInterval = 1500
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
guard error == nil && data != nil else {
print("error=\(error)")
return
}
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(responseString)")
}
task.resume()

You forgot to set the content type, e.g.
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
Without that, the server won't know what to do with the blob of random data that you just sent it.
I'm not saying that this is necessarily the only problem, but it is definitely a problem, and one big enough to cause the error you're seeing.

Related

Why response is always {"detail":"Unsupported media type \"text/plain\" in request."} in swift?

I have created a sample app in Django which deletes a question from App. And provides a correct output when consumed using POSTMAN.
class Questions(APIView):
def delete(self,request):
received_id = request.POST["id"]
print(received_id)
place = Question.objects.get(pk=received_id)
place.delete()
questions = Question.objects.all()
seriliazer = QuestionSerializer(questions,many = True)
return Response({'Orgs': seriliazer.data})
However, when I am trying to achieve it from iOS app, it's returning {"detail":"Unsupported media type "text/plain" in request."}
func deleteQuestion( id: Int){
guard let url = URL(string: "http://127.0.0.1:8000/V1/API/questions/") else {
return
}
var request = URLRequest(url: url)
let postString = "id=15"
request.httpBody = postString.data(using: String.Encoding.utf8);
request.httpMethod = "DELETE"
URLSession.shared.dataTask(with: request) { data, response, error in
let str = String(decoding: data!, as: UTF8.self)
print(str)
if error == nil {
self.fetcOrganizatinData()
}
}.resume()
}
Could not really understand where exactly the problem is ?
If the api is expecting Json, the body you are sending is not Json, it’s encoded plain text. If it should be Json you can change the body string into the Json format like:
“{\”id\”:15}”
// you may want to tell it what you’re sending
request.setValue("application/json", forHTTPHeaderField: "Accept-Encoding")
Another thing it could be is the request is missing the Accept-Encoding header which tells the api what you’re sending up where Content-Type is what the api typically sends down.
I’ve experienced header injection when I’ve sent requests through specific gateways that aren’t always right. I’d the header isn’t present, something along the way could try to help you out and add the header. This has caused me problems on the past. I still don’t know exactly where in our stack it was occurring, but adding the header fixed my problem.
You can add the header like:
request.setValue("charset=utf-8", forHTTPHeaderField: "Accept-Encoding")
DELETE request's body will be ignored, I could guess from the Is an entity body allowed for an HTTP DELETE request? post. HENCE Better to send the complete URL or in header itself,
so I made the function as below
def delete(self,request):
received_id = request.headers['id']
place = Question.objects.get(pk=received_id)
place.delete()
return HttpResponse("DELETE view is working fine ")
and swift
func deleteQuestion( id: Int){
guard let url = URL(string: "http://127.0.0.1:8000/V1/API/questions/") else {
return
}
var request = URLRequest(url: url)
//let postString = "id=\(id)"
// request.httpBody = postString.data(using: String.Encoding.utf8);
request.httpMethod = "DELETE"
request.setValue("charset=utf-8", forHTTPHeaderField: "Accept-Encoding")
request.setValue("charset=utf-8", forHTTPHeaderField: "Content-Type")
request.setValue("\(id)", forHTTPHeaderField: "id")
URLSession.shared.dataTask(with: request) { data, response, error in
let str = String(decoding: data!, as: UTF8.self)
print(str)
if error == nil {
self.fetcOrganizatinData()
}
}.resume()
}
Shortly add Content-Type application/json in your headers
Reason
this happens because the postman has some default headers usually 8.
One of them is
Content-Type text/plain
and by writing "Content-Type": "application/json" we can overwrite that rule.
So whenever you want to pass your data like JSON do that.
to learn more what is by default in postman
I recommend you to read this official documentation of postman.
It happens with me I solved this with overwriting default Content-Type

Swift Alamofire can not parse the response JSON string in POST request

A POST http request:
task.request = sessionManager?.request(url!, method: method, parameters: paramters, encoding: JSONEncoding.prettyPrinted, headers: nil).responseJSON { response in
task.handleResponse(response: response)
}
The response is a JSON string like this:
{\"Data\":{\"ArrayOfItems\":[{\"ActualQty\":\"5.0\",\"BatchManaged\":true,\"ArrayOfBatches\":[{\"BatchNumber\":1,\"Counted\":\"ADD\", \"Quantity\":10},{\"BatchNumber\":2,\"Counted\":\"ADD\", \"Quantity\":10}],\"LineNum\":\"1\",\"ItemCode\":\"M1001-L\",\"WarehouseCode\":\"Store\"}],\"Comments\":\"Ht\",\"DocEntry\":\"1\",\"Quantiry\":\"123\",\"Initials\":\"RT\"},\"PromptAnswerValue\":[]}
The Alamofire can not parse the response JSON string. Errors is flonwing:
responseSerializationFailed(reason: Alamofire.AFError.ResponseSerializationFailureReason.jsonSerializationFailed(error: Error Domain=NSCocoaErrorDomain Code=3840 "No string key for value in object around character 40." UserInfo={NSDebugDescription=No string key for value in object around character 40.}))
Debuged, the failed in 'let json = try JSONSerialization.jsonObject(with: validData, options: options)' line. See attached file flowing:
The validData is valuable. Why is this happening?
I write a demo and I can receving the response json string, the code like this:
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("\(jsonData.length)", forHTTPHeaderField: "Content-Length")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData as Data
let session = URLSession.shared
let task = session.dataTask(with: request as URLRequest) {(
data, response, error) in
guard let data = data, let _:URLResponse = response, error == nil else {
print("error")
return
}
let dataString = String(data: data, encoding: String.Encoding.utf8)
let dict = self.getDictionaryFromJSONString(jsonString: dataString!)
print(dict)
}
task.resume()
Used the URLSession can do this, but why the Alamofire can not? Is it the problem I use? Please advise.
Thanks.
The issues I had solved. This is caused by the invalid JSON string in response.
Debug as flowing:
Debug here and do this in the console
po String(data: validData, encoding: String.Encoding.utf8)
Check if the JSON string is valid.
Besides, note: Use JSONEncoding.prettyPrinted.

Can timeout function be added when getting a string from a URL?

Sometimes I fetch information from a specific site.
But when the response is slow I would like to add a timeout function. I would like to know how.
Can I add a timeout function to the code below?
html = try String(contentsOf: url, encoding: String.Encoding.ascii)
You are not really supposed to use init(contentsOf:encoding:) to read from a remote URL. This initialiser is synchronous so while it is doing that your app's UI will freeze and the user won't be able to do anything, as you may have noticed.
You are supposed to use URLSession and URLRequest to fetch data from remote URLs. They are asynchronous so you get your data in a completion handler.
You can set a timeout in seconds when you create the URLRequest, and you will get an NSError in the completion handler if it timed out (among other reasons).
var request = URLRequest(url: URL(string: "https://example.com")!,timeoutInterval: 10)
request.addValue("text/plain", forHTTPHeaderField: "Content-Type")
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
print(String(describing: error))
return
}
let result = String(data: data, encoding: .ascii)
// do something with result
}
task.resume()

My swift HTTP POST request is not being processed properly by a PHP api

I am trying to get a post request to a PHP api. I need to be able to send the request in Json format. The PHP file collects the post request like so:
$postBody = $_POST ['request'];
$signature = $_POST ['signature'];
$rpcRequest = json_decode ( $postBody, true );
I need to build a request that is formatted so the api can read my information. I am building my request like so:
//Here I am building the request as a string. This string is used to get the signature.
var params =
"""
{"method":"phoneNumberVerificationStart","params":{"number":"\(PhoneNumber)"},"id":1}
"""
//here I build the request by using a dictionary.
var jsonParams = ["request": ["method": "phoneNumberVerificationStart","id": 1, "params": ["number": "\(PhoneNumber)"] ]] as NSMutableDictionary
let urlString = "******************************"
//below is just hashing the params into sha256
let hashedParams = sha256(request: params)
let signature = hashedParams.hexEncodedString()
//Take what was just hashed and put it into the signature variable
jsonParams["signature"] = signature
//jsonData takes my built dictionary and turns it into a json format to be sent.
let jsonData = try? JSONSerialization.data(withJSONObject: jsonParams, options: .prettyPrinted)
guard let requestURL = URL(string:urlString) else{return}
let session = URLSession.shared
// Set up the post request to send to the server.
let request = NSMutableURLRequest(url:requestURL)
request.httpMethod = "POST"
// Add the jsonData to the body of the http request. This data is json and when printed out in string form it looks like this:
// ( {"request":{"id":1,"method":"phoneNumberVerificationStart","params":{"number":"**********"}},"signature":"2ebdd87bdc66a04419bfd60e7c9b257039bf66dacd1623a1995c971e7cb68ed6"}
//For some odd reason Id shifts up to the front of the json file?
request.httpBody = jsonData
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
print(String(data: request.httpBody!, encoding: .utf8)!)
//After this I send the request the server does not understand my post request
let task = session.dataTask(with: request as URLRequest){
(data,respone, error) in
if error != nil {
print(error?.localizedDescription)
//print(String(data:myData!,encoding: .utf8)!)
}
do{
print (String(data: data!, encoding: .utf8)!)
}
I am thinking my problem is the request not being sent as a json object but rather raw data. I am receiving an error from the server that it cannot find the fields 'request' or 'signature'.

How to Call HTTP Get and Save in Variable In Swift?

My question is simple: how do you call a HTTP GET Request in Swift?
I am trying to retrieve specific data from server (I have the URL string), the problem is that the previous answers I saw, doesn't explain thoroughly how to request an HTTP Get and save the retrieved information in a variable to be used later? Thanks in advance!
Here's what I have so far:
let myURL = NSURL(string:"https://api.thingspeak.com/channels/CHANNEL_ID/last_entry
_id.txt");
let request = NSMutableURLRequest(url:myURL! as URL);
request.httpMethod = "GET"
Not sure what do following requesting the GET.
In your post you are missing the part that does the actual getting to of the data.
Your code should look something like this to get the value out of the text file.
var lastID: String?
let myURL = NSURL(string:"https://api.thingspeak.com/channels/1417/last_entry_id.txt");
let request = NSMutableURLRequest(url:myURL! as URL);
//request.httpMethod = "GET" // This line is not need
// Excute HTTP Request
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
// Check for error
if error != nil
{
print("error=\(error)")
return
}
// Print out response string
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("responseString = \(responseString!)")
lastID = "\(responseString!)" // Sets some variable or text field. Not that its unwrapped because its an optional.
}
task.resume()