Пытаюсь использовать API функций Яндекс.Облака из bash и cURL.
Для этого я составляю JSON следующим образом:
#Make header
IAM_TOKEN = "myToken"
HEADER = "Authorization: Bearer ${IAM_TOKEN}"
#Make data JSON
DATA = ""
for ELEMENT in \
"'"\
'{"runtime":"dotnetcore31", "entrypoint": "Function.Handler",'\
'"resources":{"memory":"134217728"}, "content": "PLACEHOLDERFORCONTENT",'\
'"ServiceAccountId":"accId", '\
'"function_id": "funcId"}'\
"'"; do
DATA+ = "${ELEMENT}"
done
Затем мне нужно предоставить содержимое пакета развертывания внутри JSON, как предлагает API:
В моем случае это zip-архив с кодом функции. Итак, я читаю файл как байты и ввожу результат в строку JSON. И отправить запрос.
#Read file content
FILE_LOC = "/Users/Constantine/Downloads/archiveName.zip"
FILE_BYTES=`(xxd -b ${FILE_LOC}) | base64`
#Inject content into JSON
DATA=${DATA/PLACEHOLDERFORCONTENT/$FILE_BYTES}
#Send the request
eval "$(echo curl -H \"$HEADER\" --data-binary $DATA https://serverless-functions.api.cloud.yandex.net/functions/v1/versions)"
Здесь я получаю -bash: /usr/bin/curl: слишком длинный список аргументов. Я подозреваю, что это происходит потому, что cURL интерпретирует двоичное содержимое как имя файла для чтения, но я не уверен, как это решить.
Как я могу передать двоичный контент из файла в строку JSON?
Вы отправляете запрос, используя вызов cURL под bash. И оболочка имеет максимальную длину строки, которую вы во многом превосходите. Самый простой обходной путь — сохранить данные JSON в файл и предоставить cURL указатель на этот файл, чтобы длина строки оставалась включенной:
#Make data JSON
data_file = "data.json"
> "${data_file}"
for ELEMENT in \
"'"\
'{"runtime":"dotnetcore31", "entrypoint": "Function.Handler",'\
'"resources":{"memory":"134217728"}, "content": "PLACEHOLDERFORCONTENT",'\
'"ServiceAccountId":"accId", '\
'"function_id": "funcId"}'\
"'"; do
echo "${ELEMENT}"
done >> "${data_file}"
#Read file content
FILE_LOC = "/Users/Constantine/Downloads/archiveName.zip"
FILE_BYTES=$(xxd -b "${FILE_LOC}" | base64)
#Inject content into JSON
sed -i "s/PLACEHOLDERFORCONTENT/${FILE_BYTES}/" "${data_file}"
#Send the request
eval "$(echo curl -H \"$HEADER\" --data-binary "@${data_file}" https://serverless-functions.api.cloud.yandex.net/functions/v1/versions)"
Кроме того, ваш код кажется довольно сложным для этой цели. Можно немного упростить. Избегайте циклов, создавайте файл за один раз и избегайте eval
:
#Make data JSON
data_file = "data.json"
FILE_LOC = "/Users/Constantine/Downloads/archiveName.zip"
cat <<-EOF > "${data_file}"
{
"runtime": "dotnetcore31",
"entrypoint": "Function.Handler",
"resources": {
"memory": "134217728"
},
"content": "$(xxd -b "${FILE_LOC}" | base64)",
"ServiceAccountId": "accId",
"function_id": "funcId"
}
EOF
#Send the request
curl -H "$HEADER" --data-binary "@${data_file}" https://serverless-functions.api.cloud.yandex.net/functions/v1/versions
Спасибо! Удалите апострофы перед инициалами и после закрывающих фигурных скобок. В противном случае он выдает ошибку «Корневой элемент должен быть сообщением».
JSON — это текстовый формат; строки являются Unicode по определению. В самом JSON нет возможности для двоичных данных. Обычный обходной путь — преобразовать ваши данные в base64 и развернуть их во всех функциях, которые их используют. Другой вариант — переключиться с JSON на формат, который поддерживает ваш вариант использования. Возможно, посмотрите на протобуферы. Но здесь API просто плохо определен.