STHTTPRequest returning null - ios

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

Related

Vapor: How to get response URL using Vapor Client or async-http

Something I'm running into when using Vapor to crawl sites is if I enter a url like http://website(dot)com and it redirects to https://www.website(dot)com, I need to grab that final response URL to know what the final page URL is.
I can do this with URLSession but I'm not seeing something similar in the Vapor client. I tried using the Vapor client and the async-http package it's built on and I can't find the page URL listed in the response.
Any pointers would be appreciated, thank you.
Example getting this info using URLSession
if let url = URL(string: self) {
do {
let(_, response) = try await URLSession.shared.data(from: url)
if let responseURL = response.url {
result = responseURL.description
return result
}
} catch {
}
}
Where this is the first line of the response, and you can easily use response.url to grab the below "URL" value:
<NSHTTPURLResponse: 0x600000210c00> { URL: https://github.com/ } { Status Code: 200, Headers {

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!

URLSession.Datatask returns 0 bytes of data

Trying to figure this one out, I'm stumped. When making a REST call to get json data back from a response (GET or POST, each should return data) I get back 0 bytes.
This is pre-serialization. The POST successfully creates a message on the backend, and the backend shows a response being sent; with charles proxy on, I've confirmed that there is a response with valid JSON data.
Any ideas why this would be failing ONLY in iOS? Postman/Charles proxy (from the iOS calls!) shows valid data in the response, but the debugger picks up nothing.
Thanks in advance for anything thoughts.
let components = URLComponents(string: "mysuperValidURL.com")
guard let url = components?.url else {
return
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
setUrlRequestToken(request: &request)
let message = ChatMessage(content: message, group: group, userId: userId)
let jsonEncoder = JSONEncoder()
guard let data = try? jsonEncoder.encode(message) else {
return
}
URLSession.shared.uploadTask(with: request, from: data) { (data, response, error) in
// Here there be 0 bytes
}.resume()
}
Data will sometimes come back as 0 bytes in the debugger; add a print with debug description to ensure you're getting data. In this case it was a failure of the debugger mixed with a later serialization error that caused it to appear to be broken.
TLDR; don't trust the realtime debugger, use some prints to sanity check.

Set Cookies for URL Request

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...
}
}

Resources