Renato Parreira
Renato Parreira

Reputation: 858

POST requests in Alamofire Parameter Encoding returning GET responses

I'm trying to make a Route Builder in swift using Alamofire (3.0) and I have succeded for all my GET requests, but when I try to make a POST request, for example, I still get the same responses of the GET method.

My API Routes are:

/users //GET -> return list of users
/users //POST -> create new user with the parameters sent

When I use Postman everything works fine.

Here is my Router code:

import Foundation
import Alamofire


enum UserRouter: URLRequestConvertible{

    static let baseURL = NSURL(string: "http://192.168.0.106/users")!

    case Users
    case CreateUser([String: AnyObject])
    case ReadUser(Int)
    case UpdateUser(Int, [String: AnyObject])
    case DestroyUser(Int)

    var URL: NSURL { return UserRouter.baseURL.URLByAppendingPathComponent(route.path) }

    var route: (path: String, parameters: [String: AnyObject]?) {

        switch self{

        case .Users:
            return ("/", nil)
        case .ReadUser(let userID):
            return ("/\(userID)", nil)
        case .CreateUser(let userInfo):
            return ("/", userInfo)
        case .UpdateUser(let userID, let userInfo):
            return ("/\(userID)", userInfo)
        case .DestroyUser(let userID):
            return ("/\(userID)", nil)
        }

    }

    var method: Alamofire.Method{

        switch self{

        case .Users:
            return .GET
        case .ReadUser:
            return .GET
        case .CreateUser:
            return .POST
        case .UpdateUser:
            return .PUT
        case .DestroyUser:
            return .DELETE

        }

    }

    var URLRequest: NSMutableURLRequest {

        let httpRequest = NSMutableURLRequest(URL: URL)
        httpRequest.HTTPMethod = method.rawValue

        switch self{

        case .CreateUser (let userInfo):
            print("creating")
            print(httpRequest.HTTPMethod) //Print: POST on CreateUser, like it should.
            return Alamofire.ParameterEncoding.JSON.encode(httpRequest, parameters: userInfo).0
        default:
            return Alamofire.ParameterEncoding.URL.encode(httpRequest, parameters: (route.parameters ?? [ : ])).0

        }

    }

}

func testRoute(){

   Alamofire.request(UserRouter.CreateUser(["name":"test"])).responseJSON{ (response) in

        switch response.result{

        case .Success(let data):
            print (data) //Error here, printing GET response instead of my API response for creating users (POST).
        case .Failure:
            print("fail")
        }

    }

}

Upvotes: 1

Views: 2505

Answers (2)

Renato Parreira
Renato Parreira

Reputation: 858

Turned out that the problem was a combination of the command that Alamofire.request() generates (curl -i -X POST...) and how my Apache was handling trailing slashes of the URL. So when I tried to POST "http://192.168.0.106/users" I was being redirect (301) to a GET "http://192.168.0.106/users".

So I had to include this line of command in my .htaccess:

# Redirect Trailing Slashes...
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)/$ /$1 [L,R=301]

and change my Router's code, always appending a trailing slash at the end:

var route: String {

        switch self{

        case .Users:
            return ""
        case .ReadUser(let userID):
            return "/\(userID)/"
        case .CreateUser:
            return "/"
        case .UpdateUser(let userID):
            return "/\(userID)/"
        case .DestroyUser(let userID):
            return "/\(userID)/"
        }

    }

Upvotes: 1

Rob
Rob

Reputation: 437452

This will generate a JSON POST request. Are you sure your web service is expecting a JSON request? Make sure you don't conflate the fact that your web service returns a JSON response with the format of the request.

If your web service is expecting a standard POST request (i.e. a request with a Content-Type of application/x-www-form-urlencoded), you'd use URL for the .CreateUser, too:

var URLRequest: NSMutableURLRequest {

    let httpRequest = NSMutableURLRequest(URL: URL)
    httpRequest.HTTPMethod = method.rawValue

    switch self {
    case .CreateUser (let userInfo):
        return Alamofire.ParameterEncoding.URL.encode(httpRequest, parameters: userInfo).0
    default:
        return Alamofire.ParameterEncoding.URL.encode(httpRequest, parameters: (route.parameters ?? [ : ])).0
    }

}

If you ever have questions about whether the request was created correctly, I find that tools like Charles can be useful in confirming the precise request that was sent to the web service.

Upvotes: 0

Related Questions