mixja
mixja

Reputation: 7467

Parse raw string as object using JMESPath

I have an object that I am parsing using JMESPath where the value of a property is a JSON object encoded as a string. I want to be able to parse that string property as a JSON Object and work with it using JMESPath only (I'm aware I could parse the value using a JSON encoder).

Here is the object:

{
    "ARN": "arn:aws:secretsmanager:us-east-1:xxxxx:secret:todobackend/db/credentials-AP57Kn",
    "Name": "todobackend/db/credentials",
    "VersionId": "c95fae54-e7b4-4c7f-80d6-2c5649f86570",
    "SecretString": "{\"MYSQL_USER\":\"todobackend\",\"MYSQL_PASSWORD\":\"password\"}",
    "VersionStages": [
        "AWSCURRENT"
    ],
    "CreatedDate": 1523276277.046
}

So I want to parse the SecretString property as a JSON object.

Any ideas on whether or not this is possible?

Upvotes: 20

Views: 4414

Answers (3)

dossy
dossy

Reputation: 1679

The correct answer per OP's request to do this strictly in JMESPath is to use to_array():

array to_array(any $arg)

  array - Returns the passed in value.
  number/string/object/boolean - Returns a one element array containing the passed in argument.

The linked page gives examples, but to illustrate what you're looking for:

to_array(SecretString)[0].MYSQL_USER
# => `todobackend`

to_array(SecretString)[0].MYSQL_PASSWORD
# => `password`

For anyone who wants to use this with Azure CLI's JMESPath --query functionality, at least as of version 2.33.1 in May 2022, to_array() does not work as documented and this is a bug in their implementation. Instead of returning an array containing an object, it will return an array containing a string of the node value, without parsing it.

Upvotes: 1

Mike Patnode
Mike Patnode

Reputation: 471

jq will save you:

aws secretsmanager get-secret-value --secret-id todobackend/db/credentials-AP57K | jq -r '.SecretString|fromjson|.MYSQL_USER,.MYSQL_PASSWORD'

Upvotes: 4

bosskay972
bosskay972

Reputation: 993

If you use JMESPath only you can try to do it with your hand with this request:

merge(@,{SecretString: {MYSQL_USER: 'todobackend', MYSQL_PASSWORD: 'password'}})

it's work well. But if you can do it in other language include jmespath like js you can do it this way:

let jsonString = JSON.stringify(JSON.parse("{\"MYSQL_USER\":\"todobackend\",\"MYSQL_PASSWORD\":\"password\"}")).split('"').join("'").replace("{'","{").split(",'").join(",").split("':").join(":");
let mainObject = {
   "ARN": "arn:aws:secretsmanager:us-east-1:xxxxx:secret:todobackend/db/credentials-AP57Kn",
   "Name": "todobackend/db/credentials",
   "VersionId": "c95fae54-e7b4-4c7f-80d6-2c5649f86570",
   "SecretString": "{\"MYSQL_USER\":\"todobackend\",\"MYSQL_PASSWORD\":\"password\"}",
   "VersionStages": [
       "AWSCURRENT"
   ],
   "CreatedDate": 1523276277.046
}
var data = jmespath.search(mainObject, `merge(@,{SecretString:${jsonString}})`)

the split/join permit that the code could be used for another string like this

Upvotes: -3

Related Questions