Set Cookies for URL Request - url

Currently I have an iOS app that pulls prices and data from websites. So far its been working well, but I want to make it more accurate. To do so, I need to set the cookies for the URL request that I'm currently using String(contentsOf: _) for.
Current Process
let requestUrl: URL = URL(string: "http://www.samsclub.com/sams/search/searchResults.jsp?searchTerm=Apple")!
var content: String?
do {
content = try String(contentsOf: requestUrl)
} catch {
print("Error while converting an NSURL to String: \(error)")
}
if content != "" {
// I do things with the content of the requestUrl...
}
Could Use?
I thought that maybe I should use Alamofire instead to pull those website, and then parse the data.
I need to set the cookie that changes the store number to search, but have been unable to find a way to do so. Bellow is the code I have for pulling the websites data without setting a cookie.
let requestUrl: String = "http://www.samsclub.com/sams/search/searchResults.jsp?searchTerm=Apple"
Alamofire.request(requestUrl, method: .post).responseString { response in
if let content: String = response.result.value {
// I do things with the content of the requestUrl...
}
}
Other Claims
I have found many different ways to set cookies through Alamofire that don't work, but if Alamofire isn't the way to do it, please inform me. I really need this to work, and I'm open to any and every suggestion.

It took four weeks to the day, but I figured it out! URLRequest and Alamofire were my glorious answers!
Create the URL to call.
let requestUrl: String = "http://www.samsclub.com/sams/search/searchResults.jsp?searchTerm=Apple"
Next make the URLRequest with the URL string, and set its http method.
var urlRequest = URLRequest(url: requestUrl)
urlRequest.httpMethod = "POST"
Then set the cookies for the URLRequest.
urlRequest.setValue("myPreferredClub=4969", forHTTPHeaderField: "Cookie")
urlRequest.httpShouldHandleCookies = true
Finally send the URLRequest with Alamofire, and use the response data in whatever way I wish.
Alamofire.request(urlRequest).responseString { response in
if let content: String = response.result.value {
// I do things with the content of the urlRequest...
}
}

Related

HTTP DELETE Works From Browser But Not From Postman or IOS App

When attempting an http request to my rest api, I continually get a 401 error when using the following code. I don not get this error making any other type of request. I have provided the function that makes the request below.
func deleteEvent(id: Int){
eventUrl.append(String(id))
let request = NSMutableURLRequest(url: NSURL(string: eventUrl)! as URL)
request.httpMethod = "DELETE"
print(eventUrl)
eventUrl.removeLast()
print(self.token!)
request.allHTTPHeaderFields = ["Authorization": "Token \(self.token)"]
let task = URLSession.shared.dataTask(with: request as URLRequest) { data, response, error in
if error != nil {
print("error=\(String(describing: error))")
//put variable that triggers error try again view here
return
}
print("response = \(String(describing: response))")
}
task.resume()
}
When sending the delete request with postman, the rest api just returns the data I want to delete but does not delete it. For reference I have posted the view and permissions classes associated with this request Any help understanding why this may be resulting in an error is greatly appreciated!
Views.py
class UserProfileFeedViewSet(viewsets.ModelViewSet):
"""Handles creating, reading and updating profile feed items"""
authentication_classes = (TokenAuthentication,)
serializer_class = serializers.ProfileFeedItemSerializer
queryset = models.ProfileFeedItem.objects.all()
permission_classes = (permissions.UpdateOwnStatus, IsAuthenticated)
def perform_create(self, serializer):
"""Sets the user profile to the logged in user"""
#
serializer.save(user_profile=self.request.user)
Permissions.py
class UpdateOwnStatus(permissions.BasePermission):
"""Allow users to update their own status"""
def has_object_permission(self, request, view, obj):
"""Check the user is trying to update their own status"""
if request.method in permissions.SAFE_METHODS:
return True
return obj.user_profile.id == request.user.id
HEADER SENT WITH DELETE REQUEST VIA POSTMAN
Preface: You leave out too much relevant information from the question for it to be properly answered. Your Swift code looks, and please don't be offended, a bit beginner-ish or as if it had been migrated from Objective-C without much experience.
I don't know why POSTMAN fails, but I see some red flags in the Swift code you might want to look into to figure out why your iOS app fails.
I first noticed that eventUrl seems to be a String property of the type that contains the deleteEvent function. You mutate it by appending the event id, construct a URL from it (weirdly, see below), then mutate it back again. While this in itself is not necessarily wrong, it might open the doors for racing conditions depending how your app works overall.
More importantly: Does your eventUrl end in a "/"? I assume your DELETE endpoint is of the form https://somedomain.com/some/path/<id>, right? Now if eventUrl just contains https://somedomain.com/some/path your code constructs https://somedomain.com/some/path<id>. The last dash is missing, which definitely throws your backend off (how I cannot say, as that depends how the path is resolved in your server app).
It's hard to say what else is going from from the iOS app, but other than this potential pitfall I'd really recommend using proper Swift types where possible. Here's a cleaned up version of your method, hopefully that helps you a bit when debugging:
func deleteEvent(id: Int) {
guard let baseUrl = URL(string: eventUrl), let token = token else {
// add more error handling code here and/or put a breakpoint here to inspect
print("Could not create proper eventUrl or token is nil!")
return
}
let deletionUrl = baseUrl.appendingPathComponent("\(id)")
print("Deletion URL with appended id: \(deletionUrl.absoluteString)")
var request = URLRequest(url: deletionUrl)
request.httpMethod = "DELETE"
print(token) // ensure this is correct
request.allHTTPHeaderFields = ["Authorization": "Token \(token)"]
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
print("Encountered network error: \(error)")
return
}
if let httpResponse = response as? HTTPURLResponse {
// this is basically also debugging code
print("Endpoint responded with status: \(httpResponse.statusCode)")
print(" with headers:\n\(httpResponse.allHeaderFields)")
}
// Debug output of the data:
if let data = data {
let payloadAsSimpleString = String(data: data, encoding: .utf8) ?? "(can't parse payload)"
print("Response contains payload\n\(payloadAsSimpleString)")
}
}
task.resume()
}
This is obviously still limited in terms of error handling, etc., but a little more swifty and contains more console output that will hopefully be helpful.
The last important thing is that you have to ensure iOS does not simply block your request due to Apple Transport Security: Make sure your plist has the expected entries if needed (see also here for a quick intro).

login user with GET request swift

I have created a screen with a text field called customer_number text field and another screen with a text field called password text field. I want to integrate my app with an existing API made by the backend developers. I am new to IOS Development and I don't know how to go about it. How do I make a get request and pass the login credentials for the user to login?
I want to get the customer number from the API and pass it to the app and enable the customer to log in.
I think this question is too big and complex to be replied exhaustively. You didn't tell us about the API. What kind of input does it take? What kind of response?
Supposing the simplest case. You API expects JSON objects as input and respond with another JSON object containing the information you request.
I usually do tasks like this using the NSURLRequest.
let js = ["Username":username, "Password":password]
let session = URLSession.init(configuration: .default)
let url = URL(...)
var req = URLRequest.init(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 10)
req.httpMethod = "POST"
// Add some header key-value pairs
req.addValue(..., forHTTPHeaderField: ...)
...
let task = session.dataTask(with: request) { (data, response, error) in
guard error == nil else { return }
guard let responseData = data else { return }
let code = (response as! HTTPURLResponse).statusCode
// Checking for code == 200 states for authorised user. Generally log-in APIs should return some 4xx code if not allowed or non-authorised user.
if code == 200 {
// Now we try to convert returned data as a JSON object
do {
let json = try JSONSerialization.jsonObject(with: responseData, options: [])
// use your json object here, for example checking if contains the user number...
} catch {
// handle errors
}
}
}
task.resume()
I coded this very quickly, please check the correctness of al mechanism!

STHTTPRequest returning null

I'm able to load this URL in a safari browser and see the JSON data I need, but this STHTTPRequest is returning null, making me not able to use the JSON, what is going wrong here? I am loading in safari
let url = "192.168.101.1:8080/api"
let request = STHTTPRequest.buildGET(URL(string: url), timeout: 15.0)!
First of all check you are using the latest STHTTPRequest from CocoaPods STHTTPRequest.
Then you can simply use the following to initialise and call a request to the url. The result is obtained through body in completionBlock
guard let request = STHTTPRequest(urlString: url) else {return}
request.timeoutSeconds = TimeInterval(floatLiteral: 15.0)
request.completionBlock = { (headers, body) in
print(body)
}
request.errorBlock = { (error) in
// ...
}
request.startAsynchronous()
needed to add http:// to the beginning of the url, giving http://192.168.101.1:8080/api/status

What is the best way to add data and upload files to Rest api

My iOS application allows a user to submit a complaint to an online REST API with the following parameters:
Data Fields: such as name, phone number, ...
Voice: recorded from microphone
Image/Video: selected from photo gallery
1- how can i do that with swift?
2- how to get back an ID field from the server after submission?
3- how to manage an upload progress for the voice and media files?
Regards
After few weeks working hardly on it, here is my experience using Swift 3.1 which is run smoothly:
//use POSTMAN plugin in Chrome browser to get the read header for your API (optional):
let headers = [
"cache-control": "no-cache",
"postman-token": "00000000-1111-2222-3333-444444444"]
//this is the important part:
let strQuery: String = "mobileNo=" + txtMobileNB.text! + "&fullname=" + txtName.text!
let request = try? NSMutableURLRequest(url: NSURL(string: "http://service.website.com/apiname/?" + strQuery)! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request?.httpMethod = "POST"
request?.allHTTPHeaderFields = headers
if request != nil {
let session = URLSession.shared
let dataTask = session.dataTask(with: request! as URLRequest) {data,response,error in
if let content = data
{
let responseData = String(data: content, encoding: String.Encoding.utf8)
//feedback from server:
print(responseData)
//call success function:
self.showDone()
} else {
//call error function:
self.showWrong()
}
}
dataTask.resume()
} else {
//call error function:
self.showWrong()
}
Regarding the other part "how to upload", i've found this framework is a good one (called rebekka) to start your upload project through iOS apps.
hope this helps someone :)

Alamofire: How to get parts of response JSON

I have a question about Alamofire.
I'm doing this:
var mutableURLRequest = NSMutableURLRequest(URL:url!)
mutableURLRequest.setValue(response!.allHeaderFields["TOKEN"] as! String, forHTTPHeaderField: "X-AUTH-TOKEN")
mutableURLRequest.HTTPMethod = "GET"
let manager = Alamofire.Manager.sharedInstance // or create a new one
let request = manager.request(mutableURLRequest)
request.responseJSON { (request, response, string, error) in
println(response!.statusCode)
println(string!)
}
When I print string the output is JSON. I want to search for a single element (f.e. username or something else) in that JSON response.
How can I do that?
Thank you and best regards,
Alban Veliu
You can do it in Swift, but IMHO it's a lot easier using the SwiftyJSON framework. It has an excellent tutorial and documentation and you should be up an running in no time : https://github.com/SwiftyJSON/SwiftyJSON

Resources