Making HTTP Request with header in Swift - ios

I am trying to make an HTTP request to the Imgur API. I am trying to retrieve all images associated with the tag "cats." The url, according to the Imgur API is: https://api.imgur.com/3/gallery/t/cats
the Imgur API states the following about the authorization needed to make get requests:
For public read-only and anonymous resources, such as getting image
info, looking up user comments, etc. all you need to do is send an
authorization header with your client_id in your requests. This also
works if you'd like to upload images anonymously (without the image
being tied to an account), or if you'd like to create an anonymous
album. This lets us know which application is accessing the API.
Authorization: Client-ID YOUR_CLIENT_ID
I've looked at the following questions and tried things suggested there, but none of them have helped.
JSON NSURLRequest with credentials
Swift GET request with parameters
How to make a Http get and set httpHeader in Swift?
My current code is this:
let string = "https://api.imgur.com/3/gallery/t/cats"
let url = NSURL(string: string)
let request = NSMutableURLRequest(URL: url!)
request.setValue("clientIDhere", forHTTPHeaderField: "Authorization")
//request.addValue("clientIDhere", forHTTPHeaderField: "Authorization")
request.HTTPMethod = "GET"
let session = NSURLSession.sharedSession()
let tache = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
if let antwort = response as? NSHTTPURLResponse {
let code = antwort.statusCode
print(code)
}
}
tache.resume()
But I continually get a status code of 403, meaning authorization is required. What am I doing wrong?

I think you need to prepend Client-ID string to your actual client ID as for the header value:
request.setValue("Client-ID <your_client_id>", forHTTPHeaderField: "Authorization")

Updated for swift 4 :
func fetchPhotoRequest(YOUR_CLIENT_ID: String) {
let string = "https://photoslibrary.googleapis.com/v1/albums"
let url = NSURL(string: string)
let request = NSMutableURLRequest(url: url! as URL)
request.setValue(YOUR_CLIENT_ID, forHTTPHeaderField: "Authorization") //**
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let session = URLSession.shared
let mData = session.dataTask(with: request as URLRequest) { (data, response, error) -> Void in
if let res = response as? HTTPURLResponse {
print("res: \(String(describing: res))")
print("Response: \(String(describing: response))")
}else{
print("Error: \(String(describing: error))")
}
}
mData.resume()
}

Related

How to access twitter filter search stream api on ios

This is the approach I am using to get the tweets via twitter new v2 filter search API after getting the bearer token.
static func callFilterSearch() {
let Url = String(format: "https://api.twitter.com/2/tweets/search/stream?place.fields=contained_within&user.fields=location&tweet.fields=geo")
guard let serviceUrl = URL(string: Url) else { return }
var request = URLRequest(url: serviceUrl)
request.httpMethod = "GET"
request.setValue("Bearer MY BEARER TOKEN", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("gzip, deflate, br", forHTTPHeaderField: "Accept-Encoding")
request.setValue("keep-alive", forHTTPHeaderField: "Connection")
request.setValue("*/*", forHTTPHeaderField: "Accept")
request.setValue("v2FilteredStreamPython", forHTTPHeaderField: "User-Agent")
let sessionConfig = URLSessionConfiguration.default
sessionConfig.networkServiceType = .responsiveData
let session = URLSession(configuration: sessionConfig)
session.dataTask(with: request) { (data, response, error) in
if let data = data {
do {
let teamJSON = try JSONSerialization.jsonObject(with: data, options: [.allowFragments, .fragmentsAllowed, .mutableContainers, .mutableLeaves])
print("teamJSON: \(teamJSON)")
} catch let error {
print("error: \(error)")
}
}
}.resume()
}
Unfortunately I am not successful in getting the tweets this way. However the python client that twitter has put in github repo seems to work just fine and is spewing tweets as expected.
Please help me out here

Convert CURL command to URLRequest

I'm trying to convert a curl command in order to use it within swift for an ios app i'm making. I'm using a playground project to try out this feature.
The curl command is as follows:
curl -L -X POST 'https://myurl.com/mydata' \-H 'x-api-key: xxx' \-H 'Content-Type: application/json' \-d '{"uniqueNumber": “F4”}’
When I enter this into terminal, my data is displayed.
I have browsed through stackoverflow and managed to find articles like this and this
I'm still fairly new to swift and from what I understand, curl does not work in swift and so you have to convert it to a URLRequest.
I have attempted this with my code below but keep getting a message that says "Missing Authentication Token". What am I doing wrong?
import PlaygroundSupport
import Foundation
let key = "xxx"
let url = URL(string: "https://myurl.com/mydata")
let contentType = "application/json"
let uniqueNumber = "F4"
var request = URLRequest(url: url!)
request.addValue("x-api-key: \(key)", forHTTPHeaderField: "-H")
request.addValue("Content-Type: \(contentType)", forHTTPHeaderField: "-H")
request.addValue("uniqueNumber: \(uniqueNumber)", forHTTPHeaderField: "-d")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard error == nil else {
print(error!)
return
}
guard let data = data else {
print("Data is empty")
return
}
let json = try! JSONSerialization.jsonObject(with: data, options: [])
print(json)
}
task.resume()
PlaygroundPage.current.needsIndefiniteExecution = true
update -
Found the issue. I had to include the requestHTTP method, as well as the httpBody. After doing this it was fully working. See below for the working code:
import PlaygroundSupport
import Foundation
let key = "xxx"
let url = URL(string: "https://myurl.com/mydata")
let contentType = "application/json"
//setting and converting the uniqueNumber (input) to a data item so it can be recognized by the API
var uniqueNumber: Data? = "{\"uniqueNumber\": \"F09\"}".data(using: .utf8) // non-nil
var request = URLRequest(url: url!)
request.httpMethod = "POST"
request.addValue(key, forHTTPHeaderField: "x-api-key")
request.addValue(contentType, forHTTPHeaderField: "Content-Type")
request.httpBody = uniqueNumber
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard error == nil else { print(error!.localizedDescription); return }
guard let data = data else { print("Empty data"); return }
if let str = String(data: data, encoding: .utf8) {
print(str)
}
}.resume()
PlaygroundPage.current.needsIndefiniteExecution = true
You need to set header like this...
request.addValue(key, forHTTPHeaderField: "x-api-key")
request.addValue(contentType, forHTTPHeaderField: "Content-Type")
request.addValue(uniqueNumber, forHTTPHeaderField: "uniqueNumber")
You were setting invalid headers for a request.
EDIT
You also need to add Authentication Token in header like below.
let authToken = "THIS IS AUTHENTICATION TOKEN TO BE PASSED ON SERVER"
request.addValue(authToken, forHTTPHeaderField: "authenticationToken")
//Please make sure to pass the authentication token the key "authenticationToken".
//Please change as per actual key to be passed

Sending a POST request in swift but getting a 405 response (method not allowed)

Im making a POST request to the API. I have tested the API using Postman and another third party tool and Im getting a 200 response. But when I make a request from swift I get a 405 response (method not allowed) and an error message saying that "GET" request is not allowed even though clearly Im making a POST request.
I have checked the httpBody which definitely contains the data. I just can't figure out what I'm doing wrong here. Here is my code:
let json : [Dictionary<String,Any>] = [["label" : "Misc", "ignored": true], ["label" : "Cash", "ignored": false]]
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.httpBody = try? JSONSerialization.data(withJSONObject: json)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let response = response {
print(response)
}
}
task.resume()
Try using
URLSession(configuration: URLSessionConfiguration.default)
instead of
URLSession.shared
I ran into the same problem and this worked for me.

Missing headers in uploadTask allHeaderFields. Doesn't include custom headers from Access-Control-Expose-Headers

My server is using CORS. When a user logs in successfully, the response includes the headers: access-token, uid, client
The server response headers include: Access-Control-Expose-Headers:access-token, uid, client
However, when I get a successful response from an uploadTask, and access allHeaderFields these keys/values are missing.
What do I need to do to access these headers?
Thanks!
EDIT Adding client code that works just fine now:
func postReq(url: URL) -> URLRequest{
var request: URLRequest = URLRequest.init(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "content-type")
return request
}
func login(){
let url:URL = baseEndpoint.appendingPathComponent(Endpoints.login.rawValue)
let request: URLRequest = postReq(url: url)
let body: [String : String] = ["email" : "test#test.com", "password": "loremipsum"]
let bodyData:Data = try! JSONSerialization.data(withJSONObject: body)
uploadTask = defaultSession.uploadTask(with: request, from: bodyData, completionHandler: { (responseData, response, error) in
if(error == nil){
let headers = (response as! HTTPURLResponse).allHeaderFields
}
})
uploadTask?.resume()
}
ANNNND Fixed my problem. There wasn't an issue, I was just missing the correct content type. Facepalm.

iOS : http Post using swift

I figured it out solution at the bottom
I am trying to make an HTTP post request to my server. Here's what I did
var request : NSMutableURLRequest = NSMutableURLRequest(URL : NSURL(string : "myURL")
let session : NSURLSession = NSURLSession.sharedSession()
request.allHTTPHeaderFields = (headers as [NSObject : AnyObject])
request.HTTPShouldHandleCookies = true
request.HTTPMethod = "POST"
var postData = "frontend=iOS"
request.HTTPBody = postData.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
NSHTTPCookieStorage.sharedHTTPCookieStorage().cookieAcceptPolicy = NSHTTPCookieAcceptPolicy.Always
println(request.allHTTPHeaderFields)
println(request.HTTPBody)
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
let json:JSON = JSON(data: data)
println(json)
onCompletion(json, error)
})
task.resume()
this is not setting the HTTPRequest.POST
I tried printing the request to the server on the server side. IT said post was empty
POST : [QueryDict : {}]
What am I missing here? Any help is appreciated
Solution :
I mistakenly set the content-value to application/json when in fact it
was not a json body. Removing it solved the problem
use https://github.com/Alamofire/Alamofire
easy networking :)
Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"])
.response { (request, response, data, error) in
println(request)
println(response)
println(error)
}
you can use all of the below.
public enum Method: String {
case OPTIONS = "OPTIONS"
case GET = "GET"
case HEAD = "HEAD"
case POST = "POST"
case PUT = "PUT"
case PATCH = "PATCH"
case DELETE = "DELETE"
case TRACE = "TRACE"
case CONNECT = "CONNECT"
}
Heres the method I used in my logging library: https://github.com/goktugyil/QorumLogs
var url = NSURL(string: urlstring)
var request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
request.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.HTTPBody = postData.dataUsingEncoding(NSUTF8StringEncoding)
var connection = NSURLConnection(request: request, delegate: nil, startImmediately: true)
See How to escape the HTTP params in Swift on the way to correctly encode key-value pairs into the data string.

Resources