How to use POST request to Firebase Firestore from swift? - swift

I would like to use the Firestore REST API from Swift, because I am using Siri Shortcut Intents, where I am not able to use the native SDK.
What I have tried so far is to create an URLSession with "POST" httpmethod, but no luck. I have been able successfully to create document to use the form found on firestore website. But I could make successful Swift version of it.
Here is the code I have tried:
private func addTask() {
let parent = "projects/reality-kanban/databases/(default)/documents/l3VXrtTLoz11VGn60ott"
let collectionId = "A33XrtfL2ea3dG340era"
let urlString = "https://firestore.googleapis.com/v1/\(parent)/\(collectionId)"
let requestBody = DocumentBody(name: parent, fields: RequestTask(description: "test")) // it is a codable struct
let jsonData = try! JSONEncoder().encode(requestBody)
print(String(data: jsonData, encoding: .utf8)!)
let url = URL(string: urlString)!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = jsonData
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else {
print("Invalid Response received from the server") // this is what I get
return
}
}
task.resume()
}
This is the error I get: Invalid Response received from the server (400)

Add --debug to the command you are running to corroborate if you have set the right project.

Related

Swift POST to api

I have an odd issue and I am hoping you guys can help me.
The Task:
I want to post json to a API rest call.
And I am sure the rest API works - I have copied the json from print() in Swift and tried it in postman, and the works just fine.
When I try to post via Swift i get 400 Bad request.
The code:
func postMobileContacts(serverURL: String, jsonToPost: String){
// Prepare URL
let url = URL(string: serverURL)
guard let requestUrl = url else { fatalError() }
// Prepare URL Request Object
var request = URLRequest(url: requestUrl)
request.httpMethod = "POST"
// Set HTTP Request Body
request.httpBody = Data(jsonToPost.utf8);
// Set HTTP Request Header
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Authorization", forHTTPHeaderField: String(data: KeychainHelper.standard.read(service: "access-token", account: "store")!, encoding: .utf8)!)
// Perform HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
// Check for Error
if let error = error {
print("Error took place \(error)")
return
}
// Convert HTTP Response Data to a String
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print("Response data string:\n \(dataString)")
}
}
task.resume()
}
This line is definitely wrong:
request.setValue("Authorization", forHTTPHeaderField: String(data: KeychainHelper.standard.read(service: "access-token", account: "store")!, encoding: .utf8)!)
it should be the other way around.
request.setValue(String(data: KeychainHelper.standard.read(service: "access-token", account: "store")!, encoding: .utf8)!, forHTTPHeaderField: "Authorization")
You mixed up the value with the header name.
Made some edits to your code
Currently the data is not directly sent to the request as said in comments.
JSONEncodable can be send to the request after encoding to data.
func postMobileContacts(serverURL: String, jsonToPost: Encodable) { //<--here
// Prepare URL
let url = URL(string: serverURL)
guard let requestUrl = url else { fatalError() }
let data = try! JSONEncoder().encode(jsonToPost) //<-Changed here
// Prepare URL Request Object
var request = URLRequest(url: requestUrl)
request.httpMethod = "POST"
// Set HTTP Request Body
request.httpBody = data; //<-- and here
// Set HTTP Request Header
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Authorization", forHTTPHeaderField: String(data: KeychainHelper.standard.read(service: "access-token", account: "store")!, encoding: .utf8)!)
// Perform HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
// Check for Error
if let error = error {
print("Error took place \(error)")
return
}
// Convert HTTP Response Data to a String
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print("Response data string:\n \(dataString)")
}
}
task.resume()
}

Add a custom custom parameter to Multipart upload

Im trying to send an image to the server and it keeps throwing me a 400 error. My guess is its in the body. However the postman requests gets success.
Postman Request
My Code as bellow
/*****Multipart Upload*********/
func uploadImage(paramName: String, fileType: String, image: UIImage,id:String,comepletion:#escaping ()->Void,failure:#escaping (String)->Void) {
let url = URL(string: "https:someURL")
let boundary = UUID().uuidString
let session = URLSession.shared
var urlRequest = URLRequest(url: url!)
urlRequest.httpMethod = "POST"
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
urlRequest.setValue(id, forHTTPHeaderField: "some_id")
// Add the image data to the raw http request data
data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
//I guess the issue is in the bellow line since I'm
// supposed to send a param called "files" as per the postman screenshot
data.append("Content-Disposition: form-data; name=\"\(paramName)\"; filename=\"\(fileType)\"\r\n".data(using: .utf8)!)//Issue is here
data.append("Content-Type: image/png\r\n\r\n".data(using: .utf8)!)
data.append(image.pngData()!)
data.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)
// Send a POST request to the URL, with the data we created earlier
session.uploadTask(with: urlRequest, from: data, completionHandler: { responseData, response, error in
if error == nil {
let jsonData = try? JSONSerialization.jsonObject(with: responseData!, options: .allowFragments)
if let json = jsonData as? [String: Any] {
print(json)
}
// comepletion()
}else {
failure(error?.localizedDescription ?? "")
}
}).resume()
}
Seem you lost set Content Length for urlRequest
try add:
urlRequest.setValue(String(data.count), forHTTPHeaderField: "Content-Length")

How can I read the content of a form-data when the response is in html(Swift)

I'm building an iOS application and I need to access the information on a website. I've located the API endpoint, and was able to get a result in Postman
screenshot of API header and form data
So far I have this code which can allow me to make the request, but how do I parse the response(which is an HTML form, then display response in app
var urlRequest = URLRequest(url: url!)
urlRequest.setValue("application/form-data",forHTTPHeaderField: "Content-Type")
urlRequest.httpMethod = "POST"
let postString = "year=2021&season=Outdoor&province=ON&age_group=OPEN&age_sub_group_masters=ALL&age_sub_group_para=ALL&rankings_event=100m&best_by_athlete=1&rankings_event_spec_num=1&is_relay_EVENT=0&page=1"
urlRequest.httpBody = postString.data(using: .utf8)
urlRequest = .init(url: url!)```
I actually found a great resources that showed how to send POST Request with post body, and how to read the response
How To send POST Request
Now it's just a matter of parsing the HTML that is returned, and displaying it in app.
let url = URL(string: Constants.rankingAPI)
guard let requestUrl = url else {
fatalError()
}
var request = URLRequest(url: requestUrl)
request.httpMethod = "POST"
let postString = "year=2021&season=Outdoor&province=ON&age_group=OPEN&age_sub_group_masters=ALL&age_sub_group_para=ALL&rankings_event=100m&best_by_athlete=1&rankings_event_spec_num=1&is_relay_EVENT=0&page=1"
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
// Check for Error
if let error = error {
print("Error took place \(error)")
return
}
// Convert HTTP Response Data to a String
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print("Response data string:\n \(dataString.htmlToString)")
}
}
task.resume()
}

Post data using URLSession

When i try from Alamofire then it work fine but when i try to solve from URLSESSION Swift 4 then i got wrong response.
I checked in postman and it's response was right.
Parameter Description:
I have a key "data" whose value is another dictionary ["answer1":"1","answer2":"2","answer3":"3"]. Need to post this.
Wrong Reposnse = {"message = "Invalid data."; response = failure;}"
Right Reposnse = {"response":"success","message":"Data Inserted”}.
func postData()
{
let BASEURLS = "http://sebamedretail.techizer.in/babystore_api/question_data"
let parameter = ["data":["answer1":"1","answer2":"2","answer3":"3"]]
let session = URLSession.shared
var request = URLRequest.init(url: URL.init(string: BASEURLS)!)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
do
{
request.httpBody = try JSONSerialization.data(withJSONObject:parameter, options: [])
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
do{
let responseArr = try! JSONSerialization.jsonObject(with: data!, options: [])
}
})
task.resume()
}
catch
{}
}
Everything seems fine, maybe you should check the way you extract the JSON in your code, if it's PHP, here could be a solution: https://stackoverflow.com/a/18867369/7452015

NSURLSession parameters not recognized

Im attemping to make a HTTPRequest using NSURLSession. When I set the full url the request returns the correct data but when using parameters (NSJSONSerialization.dataWithJSONObject -> HTTPBody I get this error
error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost."
is there something im doing wrong here?
let json = ["api_key": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"]
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(json, options: .PrettyPrinted)
let url = NSURL(string: "https://api.themoviedb.org/3/discover/movie")!
let request = NSMutableURLRequest(URL: url)
request.HTTPBody = jsonData
request.HTTPMethod = "GET"
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
let task = NSURLSession.sharedSession().dataTaskWithRequest(request){ data, response, error in
if error != nil{
print("Error -> \(error)")
return
}
do {
let result = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [String:AnyObject]
print("Result -> \(result)")
} catch {
print("Error -> \(error)")
}
}
task.resume()
} catch {
print(error)
}
}
This is not a duplicate! I looked at the suggested answer (none of them worked) before asking this question
In your case that issue can be solved by changing the request.HTTPMethod = "GET" to request.HTTPMethod = "POST"
You should not send HTTP Body in the get request, to send the data with the body you should change HTTPMethod to post
Note: Please check if this api method supports POST requests, if it don't support post you can't use it with http body/post, as per doc i only find 'get' request for the discover/movie which can be like this:
let url = NSURL(string: "http://api.themoviedb.org/3/discover/movie?api_key=YOUR_API_KEY")!
let request = NSMutableURLRequest(URL: url)
request.addValue("application/json", forHTTPHeaderField: "Accept")
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) { data, response, error in
if let response = response, data = data {
print(response)
print(String(data: data, encoding: NSUTF8StringEncoding))
} else {
print(error)
}
}
task.resume()
Ref: You can check more information from this url: http://docs.themoviedb.apiary.io/#reference/discover/discovermovie/get