Search code examples
iosjsongoogle-apihttp-postgoogle-vision

request with Google Vision API - Invalid JSON payload received and INVALID_ARGUMENT


Trying to follow the instruction in link to create a request from my iOS app but get Invalid JSON payload received and INVALID_ARGUMENT error messages. Any suggestions?

Here is the example I am trying to use.

{
  "requests":[
    {
      "image":{
        "source":{
          "imageUri":
            "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png"
        }
      },
      "features":[
        {
          "type":"LOGO_DETECTION",
          "maxResults":1
        }
      ]
    }
  ]
}

In my iOS app, I create the para

let feature1 = ["type": "LOGO_DETECTION", "maxResults": 1] as [String : Any]
let features = [feature1]
let source = ["imageUri": "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png"]
let image = ["source": source]
let request = ["image": image, "features": features] as [String : Any]
let requests = ["requests": [request]]

if let data = try? JSONSerialization.data(withJSONObject: requests, options: .prettyPrinted),
    let str = String(data: data, encoding: .utf8) {
    print(str)
}

let privateKey = "my............key"

let requestString = "https://vision.googleapis.com/v1/images:annotate?key=\(privateKey)"
Alamofire.request(requestString, method: .post, parameters: requests).responseString { (response) in
    switch response.result {
    case .success(let data):
        print("data", data)
        print(response.result)
    case .failure(let error):
        print(error)
    }
}

I can see that I have same thing in my print log.

{
  "requests" : [
    {
      "features" : [
        {
          "type" : "LOGO_DETECTION",
          "maxResults" : 1
        }
      ],
      "image" : {
        "source" : {
          "imageUri" : "https:\/\/www.google.com\/images\/branding\/googlelogo\/2x\/googlelogo_color_272x92dp.png"
        }
      }
    }
  ]
}

But I receive the below error message

[BoringSSL] Function boringssl_context_get_peer_sct_list: line 1754 received sct extension length is less than sct data length
data {
  "error": {
    "code": 400,
    "message": "Invalid JSON payload received. Unknown name \"requests[][features][][maxResults]\": Cannot bind query parameter. Field 'requests[][features][][maxResults]' could not be found in request message.\nInvalid JSON payload received. Unknown name \"requests[][image][source][imageUri]\": Cannot bind query parameter. Field 'requests[][image][source][imageUri]' could not be found in request message.\nInvalid JSON payload received. Unknown name \"requests[][features][][type]\": Cannot bind query parameter. Field 'requests[][features][][type]' could not be found in request message.",
    "status": "INVALID_ARGUMENT",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.BadRequest",
        "fieldViolations": [
          {
            "description": "Invalid JSON payload received. Unknown name \"requests[][features][][maxResults]\": Cannot bind query parameter. Field 'requests[][features][][maxResults]' could not be found in request message."
          },
          {
            "description": "Invalid JSON payload received. Unknown name \"requests[][image][source][imageUri]\": Cannot bind query parameter. Field 'requests[][image][source][imageUri]' could not be found in request message."
          },
          {
            "description": "Invalid JSON payload received. Unknown name \"requests[][features][][type]\": Cannot bind query parameter. Field 'requests[][features][][type]' could not be found in request message."
          }
        ]
      }
    ]
  }
}

CORRECT ANSWER

1.Remove

if let data = try? JSONSerialization.data(withJSONObject: requests, options: .prettyPrinted),
    let str = String(data: data, encoding: .utf8) {
    print(str)
}

2.change

Alamofire.request(requestString, method: .post, parameters: requests).responseString { (response) in

to

Alamofire.request(requestString, method: .post, parameters: requests, encoding: JSONEncoding.default, headers: [:]).responseJSON { (response) in

Solution

  • At first glance, the errors are pretty obvious:

    • Unknown name requests[][features][][maxResults]: Cannot bind query parameter. Field could not be found in request message.
    • Unknown name requests[][image][source][imageUri]: Cannot bind query parameter. Field could not be found in request message.
    • Unknown name requests[][features][][type]: Cannot bind query parameter. Field could not be found in request message."

    But comparing your console output to the example in the docs, it matches up. My guess is that the problem is one of two possibilities:

    1. Either your payload is missing from the request entirely, or
    2. You're not encoding the payload correctly.

    To help you next time this happens, I'd recommend debugging by constructing a working payload and sending it via Curl or Postman, just to eliminate your app as the culprit.

    Once you have a valid payload, point your Swift app to http://requestb.in and send your request there instead. This will allow you to inspect what you're sending and compare it to the working example.

    Now on to fixing it:

    Turns out the problem is #2 - you're not encoding it correctly. Or rather, you are, but you're not sending the encoded string.

    See this line:

    let requests = ["requests": [request]]
    
    if let data = try? JSONSerialization.data(withJSONObject: requests, options: .prettyPrinted),
        let str = String(data: data, encoding: .utf8) {
        print(str)
    }
    

    And then you do:

    Alamofire.request(requestString, method: .post, parameters: requests).responseString { (response) in
    

    Notice how you've used requests in your payload, not your encoded str? You've buried the encoded string in an if-statement, making it unusable. I'd use guard instead here - it's less code, and doesn't bury the encoded string (it's also safer):

    let requests = ["requests": [request]]
    
    guard let data = try? JSONSerialization.data(withJSONObject: requests, options: .prettyPrinted),
          let encodedStr = String(data: data, encoding: .utf8) else { return }
    
    Alamofire.request(requestString, method: .post, parameters: encodedStr).responseString { (response) in
                                                                // ^ use the right var here!