So I am trying to do a PUT request using Alamofire and I need an integer parameter (not an object).
The request sends an id to the database and the query makes an update to an object with that id in the database.
The Parameters object in alamofire seems to take only objects:
var parameters: Parameters = ["key" : "value"]
is there any way to just send an integer without using the object?
The error I keep getting when I use that method above is:
nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of int out of START_OBJECT token
and I am assuming this means I am passing an object when I should be passing an int instead.
This is my request :
Alamofire.request(url, method: .put, parameters: parameters, encoding: JSONEncoding.default, headers: nil).response{ response in
if response.response?.statusCode == 200 {
// pass
}else{
// fail
}
completionHandler((response.response?.statusCode)!)
}
I can't seem to find any examples that have to do with us online.
If you give more information about where you are sending the request, then I can test my solution to see if it works. But you can try this.
let url = "YOUR_URL"
let yourData = "WHATEVER CUSTOM VAL YOU WANT TO PASS"
var request = URLRequest(url: URL(string: url)!)
request.httpMethod = "PUT"
//request.setValue("application/json", forHTTPHeaderField: "Content-Type") //This is if you want to have headers. But it doesn't look like you need them.
request.httpBody = yourData
/*
do {
request.httpBody = try JSONSerialization.data(withJSONObject: yourData)
} catch {
print("JSON serialization failed: \(error)")
}
*/
Alamofire.request(request).responseJSON {(response) in
if response.response?.statusCode == 200 {
print ("pass")
}else{
print ("fail")
}
completionHandler((response.response?.statusCode)!)
/*
switch response.result {
case .success(let value):
print ("success: \(value)")
case .failure(let error):
print("error: \(error)")
}
*/
}
Related
I am using a asp.net back end with a login end point but no matter what I DO in the swift version of this code I get a 415 when I use it in .net and sharp the api works am not sure what am doing wrong here.
And yes I have enabled transport protocol but its not decoding the jwt token correctly for me in swift
Basically the end point returns the jet token used for accessing the api in an object
let jwtAccessToken: String = ""
let urlString = "http://url.com/login" *** hidden for security
purposes but is correct ****
func CallWebApi()
{
// create the url with URL
let url = URL(string: urlString)! // change server url accordingly
let parameters: [String: Any] = [ "username":
"user1#domain.com", "password": "pass1"]
var request = URLRequest(url: url)
request.setValue("application/x-www-form-urlencoded",
forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "Post"
do {
request.httpBody = try
JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
} catch let error {
print(error.localizedDescription)
return
}
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 ?? URLError(.badServerResponse))
return
}
guard (200 ... 299) ~= response.statusCode else {
// check for http errors
print("statusCode should be 2xx, but is \(response.statusCode)")
print("response = \(response)")
return
}
// do whatever you want with the `data`, e.g.:
do {
let responseObject = data
print(responseObject)
} catch {
print(error)
// parsing error
if let responseString = String(data: data, encoding: .utf8) {
print("responseString = \(responseString)")
} else {
print("unable to parse response as string")
}
}
}
task.resume()
}
MyModel is basically a string
import Foundation
class AuthenticationResponse: ObservableObject {
#Published var jwtToken: String
init(jwtToken: String) {
self.jwtToken = jwtToken
}
}
I think 20 years of c sharp in not helping and am doing things it way and not the swift way if someone could advice be great.
Also in csharp we were told its not great in keeping alive the http client as can degrade performance is this the same for swift and if any library's you can recommend makes the code a bit neater the api has swagger docs enabled.
Edit 3
Example response expected back
{
"id": "b181104e-ba3e-4dba-b124-4bb4a3873b17",
"firstName": "user1",
"lastName": "lastname",
"username": "user1lastname#domainname.com",
"playerId": 0,
"jwtToken": "token in is here",//hidden for security
"error": {
"eventName": null,
"errorMessage": null,
"errorDate": null,
"statusCode": null,
"json": null
},
"refreshToken": null
}
I typically send this to the end point from C sharp
{
"username": "user1#domain.com",
"password": "pass1"
}
What I found I had to do was this
let decoder = JSONDecoder()
let responseObject = try
decoder.decode(AuthenticationResponse.self, from: data)
print(responseObject)
And change my class to be off this
import Foundation
struct AuthenticationResponse: Codable {
var jwtToken: String
}
After I done that I got the expected string back but my question is how does one get this to run correctly its completing before I think I need await but also where is it best to stored the jwttoken?
I have an iOS app receiving json data from a google cloud function.
The data is retrieved and works perfectly when there is no error.
However, when the cloud function returns an error, the function below recognizes error as nil
Client:
func initialize() {
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try? JSONSerialization.data(withJSONObject: json)
let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, error) in
guard let response = response as? HTTPURLResponse,
response.statusCode == 200,
let data = data,
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any],
let clientSecret = json["clientSecret"] as? String,
let publishableKey = json["publishableKey"] as? String else {
///////////
//ERROR is not being recognized
/////////
let message = error?.localizedDescription ?? "Failed to decode response from server."
print("Error loading page: \(message)")
return
}
})
task.resume()
}
Client Output:
Failed to decode response from server.
Server:
firebase.functions().httpsCallable('myFunction')(message)
.then(result => {
// this works perfectly and is recognized by the swift function //
res.send({publishableKey: publishableKey, clientSecret: clientSecret});
})
.catch(err => {
// this is not recognized by the swift function //
console.log(err) // full of data
return res.status(400).send({error: err});
});
Logs(for error case):
Function execution took 240 ms, finished with status code: 400
If your requests fails I think that your error will come into the response parameter and you have to decode it. I think that the error parameter will be different than nil only if the server can't be reached or function does not exist. So basically in the else clause you will have to search into the response parameter for error.
I made this request:
func AlamofireGetCode()
{
let username: String = searchTextField.text!
var url:String!
url = "https:// ... "
AF.request(url, method: .get, encoding: JSONEncoding.default)
.responseJSON { response in
switch response.result {
case .success:
debugPrint(response)
case .failure(let error):
fatalError("\(error)")
}
}
}
And I'm getting this response with different fields:
[Result]: success({
"incomplete_results" = 0;
items = (
{
"username" = " ... "
...
How do I get some specific field like "username" in Swift?
I would like to have all the username of all the user and store them, could you help me?
You need to provide a type to parse the JSON response into. Using a site like quicktype.io can generate one from your JSON, but any Decodable type will do. Then you can use Alamofire's responseDecodable handler to parse your response.
AF.request(url).responseDecodable(of: TypeToParse.self) { response in
debugPrint(response)
}
Paste your response in https://jsonparseronline.com/ to see the structure of the object. It will show you all the keys and values that you can access using subscripts.
I can easily issue a GET request and it returns (as expected) JSON data that is decoded to myDataModel object:
class func getData(completionHandler: #escaping (myDataModel?, Error?) -> Void)
{
let url = "https://example.com/api/someResource?ws_key=ABC...XYZ"
if let myUrl = URL(string: url)
{
URLSession.shared.dataTask(with: myUrl)
{
(data, response, err) in
if let data = data
{
do
{
let result = try JSONDecoder().decode(myDataModel.self, from: data)
completionHandler(result, nil)
}
catch let JSONerr
{
completionHandler(nil, JSONerr)
}
}
}.resume()
}
}
This work fine, so GET is no problem. (PS. the above has been simplified and modified.)
Likewise, I can issue a POST request and it returns (as expected) JSON data, when I use parameters like key1=value1&key2=value2. (I read that the default POST Content-Type is application/x-www-form-urlencoded.)
However, in another application I need to POST a piece of XML. After many tries and getting many errors, the approach I'm using is to: Set the header Content-Type to text/xml; charset=utf-8; Have no parameters and send the XML as the request body. I use a refined method:
PostHTTP(url: "https://example.com/api/someResource?ws_key=ABC...XYZ",
parameters: nil,
headers: ["Content-Type": "text/xml; charset=utf-8", "Content-Length": "\(xml.count)"],
body: "\(xml)") { (result) in ... }
(I image that you can determine what happens behind the scenes.)
For the POST request, to send a piece of XML:
Do I need to set the Content-Length or is this automatic?
Can I send parameters with the XML?
What headers (like Content-Type) do I require?
What structure (eg. xml=<?xml...) and encoding (eg. addingPercentEncoding) do I require?
Also I need to PUT data and I have similar method. The response from my attempt has the error
String could not be parsed as XML, XML length: 0
For a PUT request:
What headers (like Content-Type) do I require?
What structure (eg. xml=<?xml...) and encoding (eg. addingPercentEncoding) do I require?
Since I have tried many ways, an example of both PUT and POST would be ideal.
If you want to send data of XML you can do this in both PUT and POST
It does not have to be determined Content-Length
But you must add Content-Type
let req = NSMutableURLRequest(url: URL(string:"myUrl")!)
req.httpMethod = "POST"
req.setValue("application/xml;charset=utf-8;", forHTTPHeaderField: "Content-Type")
req.setValue("application/xml;", forHTTPHeaderField: "Accept")
var postBody = Data()
if let anEncoding = ("<?xml version='1.0' encoding='UTF-8'?>").data(using: .utf8) {
postBody.append(anEncoding)
}
if let anEncoding = "<Request>".data(using: .utf8) {
postBody.append(anEncoding)
}
if let anEncoding = "<test>\(123)</test>".data(using: .utf8) {
postBody.append(anEncoding)
}
if let anEncoding = "</Request>".data(using: .utf8) {
postBody.append(anEncoding)
}
req.httpBody = postBody
req.setValue("\(postBody.count)", forHTTPHeaderField: "Content-Length")
URLSession.shared.dataTask(with: req as URLRequest) { (data, urlreq, error) in
}
I'm very new to Swift 3, and i have to do a GET request on my API. I'm using Alamofire, which uses Asynchronous functions.
I do exactly the same on my Android App, and the GET returns JSON data
This is my code in swift :
func getValueJSON() -> JSON {
var res = JSON({})
let myGroup = DispatchGroup()
myGroup.enter()
Alamofire.request(url_).responseJSON { response in
res = response.result.value as! JSON
print("first result", res)
myGroup.leave()
}
myGroup.notify(queue: .main) {
print("Finished all requests.", res)
}
print("second result", res)
return res
}
But i have a problem with the line "res = response.result.value" wich gives me the error : Thread 1 : signal SIGABRT
I really don't understand where the problem comes from, it was pretty hard to do a "synchronous" function, maybe i'm doing it wrong.
My objective is to store the result of the request in a variable that i return. Anyone can help ?
I'd recommend you to use Alamofire together with SwiftyJSON because that way you'll be able to parse JSON easier a lot.
Here's a classical example:
Alamofire.request("http://example.net", method: .get).responseJSON { response in
switch response.result {
case .success(let value):
let json = JSON(value)
print("JSON: \(json)")
case .failure(let error):
print(error)
}
}
If you need to pass parameters, or headers, just add it in the request method.
let headers: HTTPHeaders = [
"Content-Type:": "application/json"
]
let parameters: [String: Any] = [
"key": "value"
]
So your request will be something like this (this is POST request):
Alamofire.request("http://example.net", method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: headers).responseJSON { response in
switch response.result {
case .success(let value):
print(value)
case .failure(let error):
print(error)
}
}
I haven't tested it, but it should work. Also, you need to set allow arbitary load to yes (App Transport Security Settings in info.plist) if you want to allow requests over HTTP protocol.
This is NOT recommended, but it's fine for development.