swiftalamofire

Alamofire request returning no results


Trying to fetch JSON data from an external website for two ISBN numbers and the Curl from that site is shown below. When using the AF.request it works fine for one isbn but when trying the string in the curl request with isbn numbers separated by a common it returns no results. Instead of a comma I have also tried & and &20 and + and nothing seems to work. The website lets you plug in both ISBN numbers and will show you results and gives you the curl statement so I know the curl statement works. Any help is appreciated!

/* curl from ISBNdb
     curl -X 'POST' \
       'https://api2.isbndb.com/books' \
       -H 'accept: application/json' \
       -H 'Authorization: mykey' \
       -H 'Content-Type: application/json' \
       -d 'isbns=9781250178633,9781501110368'
     */
    func fetchAPIDataISBN() {
    
        let headers: HTTPHeaders =  ["accept": "application/json","Authorization": "mykey","Content-Type": "application/json"]
        
        //let parameters1 = ["isbns": "9781250178633,9781501110368"]
        let parameters = ["isbns": "9781250178633"]
        AF.request("https://api2.isbndb.com/books", method: .post, parameters: parameters, headers: headers)

Solution

  • I think the problem is mainly on the API being very picky about what it accepts. It seems to accept a URL encoded form with a key isbns, followed by a comma-separated list of numbers. (Note that this contradicts the Content-Type header.) So theoretically, declaring parameters as the following should work

    let parameters = ["isbns": "9781250178633,9781501110368"]
    

    However, the API doesn't seem to like this because the comma is percent-encoded as %2C.

    You can force Alamofire to not percent encode the , by adding it in the allowedCharacters set in a URLEncodedFormEncoder:

    AF.request(
        "https://api2.isbndb.com/books",
        method: .post, 
        parameters: parameters,
        encoder: URLEncodedFormParameterEncoder(encoder: .init(
            // feel free to use a larger character set than 'alphanumerics' here if the 
            // request body has other characters that you don't want to be encoded
            allowedCharacters: .alphanumerics.union([","])
        )),
        headers: headers
    )
    

    If you don't need to pass any other parameters, also consider just writing the parameters as a single string:

    let parameters = "isbns=9781250178633,9781501110368"
    

    and setting httpBody directly in the interceptor parameter:

    let request = AF.request(
        "https://api2.isbndb.com/books",
        method: .post,
        headers: headers
    ) {
        $0.httpBody = Data(parameters.utf8)
    }