TransWikia.com

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

Stack Overflow Asked by TJ D'Alessandro on November 4, 2021

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
HEADER SENT WITH DELETE REQUEST VIA POSTMAN

One Answer

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 payloadn(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).

Answered by Gero on November 4, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP