How api calls are done with headers in swift - ios

I want to securely provide my data from the API using JWT token.So Currently I have implemented security in the backend and each ajax call eith the header
url:"https://dataurl,
contentType : "application/json; charset=utf-8",
headers : TokenHeader(),
But now I want to send the same data to be consumed by an IOS App which is developed in swift.I am not a IOS mobile developer and when I look into how they make the rest calls I found that something like this can be done:
let todosEndpoint: String = "https://dataurl"
guard let todosURL = URL(string: todosEndpoint) else {
print("Error: cannot create URL")
return
}
var todosUrlRequest = URLRequest(url: todosURL)
todosUrlRequest.httpMethod = "GET"
let newTodo: [String: Any] = ["title": "My First todo", "completed": false, "userId": 1]
let jsonTodo: Data
do {
jsonTodo = try JSONSerialization.data(withJSONObject: newTodo, options: [])
todosUrlRequest.httpBody = jsonTodo
} catch {
print("Error: cannot create JSON from todo")
return
}
let session = URLSession.shared
let task = session.dataTask(with: todosUrlRequest) {
(data, response, error) in
guard error == nil else {
print("error calling POST on /todos/1")
print(error)
return
}
guard let responseData = data else {
print("Error: did not receive data")
return
}
So now my question is like ajax call in my web app how to consume rest service from the mobile app side.Any help is appreciated?

I suggest you to use headers like this
let request = NSMutableURLRequest(url: NSURL(string: urlString)! as URL)
request.addValue("application/json",forHTTPHeaderField: "Content-Type")
request.addValue("application/json",forHTTPHeaderField: "Accept")
request.cachePolicy = .reloadIgnoringLocalCacheData

You want something like (depending on what header values you need to send):
todosUrlRequest.setValue("token value", forHTTPHeaderField: "Authorization")

Related

iOS curl -X POST integration in swift

Hi I want to integrate the Curl POST api in my code I don't have any idea about this could any please guide me how to integrate this in swift language
The below web service call I have integrate in my code, Have tried but didn't get the result
curl -X POST http://stf.rortechnologies.com/api/session.js --data '{"user": {"email":"XXXXXX", "password":"XXXXXX"}}' -H "Content-Type:application/json"
let parameters = ["email":"admin.test#stf.com", "password":"password"]
let header = ["user": parameters]
//create the url with URL
let url = URL(string: "http://stf.rortechnologies.com/api/session.js")! //change the url
//create the session object
let session = URLSession.shared
//now create the URLRequest object using the url object
var request = URLRequest(url: url)
request.httpMethod = "POST" //set http method as POST
do {
request.httpBody = try JSONSerialization.data(withJSONObject: header, options: .prettyPrinted) // pass dictionary to nsdata object and set it as request body
} catch let error {
print(error.localizedDescription)
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
//create dataTask using the session object to send data to the server
let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
guard error == nil else {
return
}
guard let data = data else {
return
}
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
print(json)
// handle json...
}
} catch let error {
print(error.localizedDescription)
}
})
task.resume()
here am getting the null response
App Transport Security (ATS)
You are calling a http url and not a https url. In production always https should be used. This is enforced by iOS.
For testing purposes one can declare exceptions in the info.plist, the documentation can be found here:
https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW33
JSON Encoding/Decoding
In Swift there is a convenient way to encode/decode JSON with JSONEncode/JSONDecoder. A simple solution might look like the one below.
Define Parameter Structs
struct Login: Encodable {
let user: User
}
struct User: Encodable {
let email: String
let password: String
}
Define Return Struct
struct Result: Decodable {
//add expected JSON fields here
}
Rest Call
private func makeRestCall() {
let login = Login(user: User(email: "admin.test#stf.com", password: "password"))
guard let loginJson = try? JSONEncoder().encode(login) else { return }
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
guard let url = URL(string: "<add some valid url here>") else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = loginJson
let dataTask = session.dataTask(with: request) { (data, response, error) in
if let response = response as? HTTPURLResponse {
if response.statusCode == 200 {
guard let data = data else {
print ("call failed - no data returned")
return
}
guard let result = try? JSONDecoder().decode(Result.self, from: data) else {
print ("json decoding failed")
return
}
print ("call succesfully returned \(result)")
} else {
print ("call failed with status \(response.statusCode)")
}
} else {
print ("call failed: no http response")
}
}
dataTask.resume()
}
Check in a HTTPS Proxy
To make sure that you send the correct data, you could use a HTTPS proxy software. There it would look like this:

Swift HTTP Post Request returns HTML of site instead of JSON response

I am trying to reach a site that should take the username and password given and return a JSON which contains information stating whether or not the login data provided was valid or not.
However, all I'm getting back is the site's HTML code instead of a response. I've tried the request with the same parameters on https://www.hurl.it/ and have gotten the correct response so that does not seem to be the issue.
I use the following code:
private func uploadToAPI(username: String, password: String) {
guard let url = URL(string: "http://api.foo.com/login.php"),
let encodedUsername = username.addingPercentEncoding(withAllowedCharacters: CharacterSet.alphanumerics),
let encodedPassword = password.addingPercentEncoding(withAllowedCharacters: CharacterSet.alphanumerics) else {
self.loginButton.isLoading = false
return
}
let httpBodyParameters = ["user": encodedUsername, "password": encodedPassword, "client": "ios", "version": "5"]
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = try? JSONSerialization.data(withJSONObject: httpBodyParameters, options: JSONSerialization.WritingOptions.prettyPrinted)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
URLSession.shared.dataTask(with: request) { (data, response, error) in
if let response = response {
print(response.mimeType) // Prints "text/html"
}
if let data = data {
print(try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments)) // Prints nil
print(String(data: data, encoding: String.Encoding.utf8)) // Prints the site's HTML
}
}.resume()
}
I fail to see where the issue is. I've also tried not setting the HTTP headers but that makes no difference. Anyone got any ideas?
It seems like not setting the HTTP header fields and using a string literal instead of a Dictionary as HTTP body data did it for me.
For anyone interested this is the code that now receives the expected response:
guard let url = URL(string: "http://api.foo.com/login.php?"),
let encodedUsername = username.addingPercentEncoding(withAllowedCharacters: CharacterSet.alphanumerics),
let encodedPassword = password.addingPercentEncoding(withAllowedCharacters: CharacterSet.alphanumerics) else {
if let delegate = self.delegate {
delegate.viewModelDidRejectLogin(self)
}
return
}
let httpBodyString = "user=\(encodedUsername)&password=\(encodedPassword)&client=ios&version=5"
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = httpBodyString.data(using: String.Encoding.utf8)
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data, error == nil else {
print(error)
return
}
do {
if let json = try JSONSerialization.jsonObject(with: data) as? [String : AnyObject] {
self.readLoginResponse(json)
}
} catch {
print(error)
}
}.resume()

IOS url request issue

I want to send mobile number and password to the server in the ios app. Backend team has given postman API like below image.
Success when sent as form-data
Below Swift URL request failing, What I'm doing wrong here?
func sendReq() {
let Url = String(format: "http://xxxxxxx/mobile/request_otp")
guard let serviceUrl = URL(string: Url) else { return }
let parameterDictionary = ["mobile_number" : "xxxxxxxxxx", "password" : "12345678"]
var request = URLRequest(url: serviceUrl)
request.httpMethod = "POST"
request.cachePolicy = .useProtocolCachePolicy
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
// params dict as data
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameterDictionary, options: []) else {
return
}
request.httpBody = httpBody
// session
let session = URLSession.shared
//data task
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
print(json)
}
catch {
print(error)
}
}
}.resume()
}
But above API call throwing error like
{
error = TRUE;
message = "All fields Required!";
}
Set the Content-Type HTTP header:
request.allHTTPHeaderFields = ["Content-Type": "application/json"]
This way you inform the server that you are sending JSON.
Can you try:
{\"mobile_number\":xxxxxxxxxx,\"password\":12345678}
and select Application/Json instead of text.

My url is not responding

Hi there I'm trying to make a post request so I made a class, a simple class to test the url but is not responding, I mean I can use other url different to the url that I suppose to use and It's responding so the request it's ok what is not working is the url. The weird thing is that in postman the url is working the server response ok. I also enable the app transport security allow arbitrary load to yes and still not working could you have any idea why is this? Thanks in advance.
Here is my code
#IBAction func buton(_ sender: Any) {
let parameters: [String : Any] = ["acceptPrivacyNotice": true,
"name": "xxxx xxxx",
"email":"xxx#mail.com",
"password": "qwerty2012",
"passwordConfirm": "qwerty2012",
"deviceID": "",
"isProvider": false,
"idTypeProvider":1 ]
guard let url = URL(string: "https://www.apps-sellcom-dev.com/Engie/api/account/register") else {return}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("YOURAPIKEY==", forHTTPHeaderField: "Authorization")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: []) else {
return
}
request.httpBody = httpBody
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print("Response",response)
}
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
print(json)
} catch {
print(error)
}
}
}.resume()
}
The certificate of the domain is about to expire, so I guess thats why the URL wasn't found.
I enabled the app transport security and set the URL in the info.plist using LSApplicationQueriesSchemes, and now I'm getting a response from the server.

Access Magento Rest API in iOS - swift 3.0

I want to access the magenta REST API in my iOS application.
Following is my code to access the API:
func getCustomerTokenusingURLSEssion(){
let url = URL(string: "HTTPURL")!
var urlRequest = URLRequest(
url: url,
cachePolicy: .reloadIgnoringLocalAndRemoteCacheData,
timeoutInterval: 10.0 * 1000)
urlRequest.httpMethod = "POST"
urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")
let json1: [String: Any] = [
"username": "xyz#gmail.com",
"password":"xyz12345"]
let jsonData = try? JSONSerialization.data(withJSONObject: json1, options: .prettyPrinted)
urlRequest.httpBody = jsonData
let config = URLSessionConfiguration.default
let urlsession = URLSession(configuration: config)
let task = urlsession.dataTask(with: urlRequest){ (data, response, error) -> Void in
print("response from server: \(response)")
guard error == nil else {
print("Error while fetching remote rooms: \(error)")
return
}
guard let data = data,
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
print("Nil data received from fetchAllRooms service ")
return
}
print("JSON \(json)")
}
task.resume()
}
But I'm getting error message form the server as follow:
["message": Server cannot understand Content-Type HTTP header media type application/x-www-form-urlencoded]
Please help!
Thanks!
Here's working example of token-based authentication from iOS to magento2 using swift:
func restApiAuthorize(completionBlock: #escaping (String) -> Void) {
// Prepare json data
let json: [String: Any] = ["username": “yourusername”,
"password": “yourpassowrd”]
let jsonData = try? JSONSerialization.data(withJSONObject: json)
// Create post request
let url = URL(string: "http://yourmagentodomain.com/index.php/rest/V1/integration/customer/token")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("\(jsonData!.count)", forHTTPHeaderField: "Content-Length")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
// Insert json data to the request
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
return
}
// 1: Check HTTP Response for successful GET request
guard let httpResponse = response as? HTTPURLResponse
else {
print("error: not a valid http response")
return
}
print(httpResponse.statusCode)
switch (httpResponse.statusCode)
{
case 200:
let responseData = String(data: data, encoding: String.Encoding.utf8)!
print ("responseData: \(responseData)")
completionBlock(responseData)
default:
print("POST request got response \(httpResponse.statusCode)")
}
}
task.resume()
}
And usage is like that:
restApiAuthorize() { (output) in
// token data, I found it important to remove quotes otherwise token contains extra quotes in the end and beginning of string
let userToken = output.replacingOccurrences(of: "\"", with: "")
print ("userToken \(userToken)")
}
you can then write your userToken to userDefaults and make feature api calls.
Best Guest you forgot to set your Content-Type, so add this:
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")

Resources