I have to create many AWS apigateway apis. All apis will use a Lambda function for invocation. These new apis will also include below common steps.
API type as Regional and a REST API
Add a POST Method
Method Execution Settings
Invocation Type=Lambda Function and also choose respective Lambda
Function.
CORS Settings
Lambda Permissions
Integration Response Settings
Deploy API
Include stage in API Usageplan
Redeploy API
Here is apigateway clone API SYNOPSIS.
SYNOPSIS
create-rest-api
--name <value>
[--description <value>]
[--clone-from <value>]
[--binary-media-types <value>]
[--minimum-compression-size <value>]
[--api-key-source <value>]
[--endpoint-configuration <value>]
[--policy <value>]
[--api-version <value>]
[--cli-input-json <value>]
[--generate-cli-skeleton <value>]
How to clone an apigateway API from existing apigateway API from CLI and avoid doing all the repeated steps mentioned above.
You could clone from existing API when creating new API by the console as well.
Use below commands as a shell script and execute the script with the mentioned parameters. Parameters names are self explanatory.
Here is the full script and every part is explained.
#!/bin/bash
APINAME=${1}
STAGENAME=${2}
LAMBDANAME=${3}
CLONEAPIID=${4}
USAGEPLANID=${5}
AWS_PROFILE=[PROFILENAME]
AWS_REGION=[AWSREGION]
AWS_ACCOUNT=[AWSACCOUNT]
METHOD=POST
Clone API from existing API
echo "Closing API ${APINAME} from API ${CLONEAPIID}"
RESTAPIID=`aws apigateway create-rest-api --name "${APINAME}" --description "${APINAME}" --clone-from ${CLONEAPIID} --endpoint-configuration '{"types":["REGIONAL"]}' --profile ${AWS_PROFILE} | grep '"id"' | sed 's/,//g;s/ //g;s/"//g;' | awk -F: '{ print $2 }'`
Display New Rest API ID
echo RESTAPIID: ${RESTAPIID}
Getting Resource
echo "Getting Resource"
RESOURCEID=`aws apigateway get-resources --rest-api-id ${RESTAPIID} --profile ${AWS_PROFILE} | grep '"id"' | sed 's/,//g;s/ //g;s/"//g;' | awk -F: '{ print $2 }'`
echo RESOURCEID: ${RESOURCEID}
Setting URI and Lambda as Invocation
echo "Setting Lambda ${LAMBDANAME}"
LAMBDA_URL="arn:aws:apigateway:${AWS_REGION}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS_REGION}:${AWS_ACCOUNT}:function:${LAMBDANAME}/invocations"
aws apigateway put-integration --rest-api-id ${RESTAPIID} --resource-id ${RESOURCEID} --http-method ${METHOD} --type AWS --integration-http-method ${METHOD} --uri "${LAMBDA_URL}" --profile ${AWS_PROFILE} | grep uri
Generating UUID as statement-id
SID=`uuidgen`
Adding permissions for API gateway to execute Lambda Function
aws lambda add-permission --function-name arn:aws:lambda:${AWS_REGION}:${AWS_ACCOUNT}:function:findPostcode --source-arn arn:aws:execute-api:${AWS_REGION}:${AWS_ACCOUNT}:${RESTAPIID}/*/*/* --principal apigateway.amazonaws.com --action lambda:InvokeFunction --statement-id ${SID} --profile ${AWS_PROFILE}
Setting Integration Response
aws apigateway put-integration-response --rest-api-id ${RESTAPIID} --resource-id ${RESOURCEID} --http-method ${METHOD} --status-code 200 --selection-pattern 200 --response-parameters '{"method.response.header.Access-Control-Allow-Origin": "'"'"'*'"'"'"}' --selection-pattern "" --response-templates '{"application/json": ""}' --profile ${AWS_PROFILE}
Creating Initial Deployment
echo "Creating Initial Deployment for ${APINAME} API and Stage ${STAGENAME}"
DEPLOYMENTID=`aws apigateway create-deployment --rest-api-id ${RESTAPIID} --stage-name '' --profile ${AWS_PROFILE} | grep '"id"' | sed 's/,//g;s/ //g;s/"//g;' | awk -F: '{ print $2 }'`
Creating Stage
aws apigateway create-stage --rest-api-id ${RESTAPIID} --stage-name ${STAGENAME} --description ${STAGENAME} --deployment-id ${DEPLOYMENTID} --profile ${AWS_PROFILE} | grep stageName
sleep 10
Adding API stage in Usageplan
echo "Adding Stage in Usageplan"
aws apigateway update-usage-plan --usage-plan-id ${USAGEPLANID} --patch-operations op="add",path="/apiStages",value="${RESTAPIID}:${STAGENAME}" --profile ${AWS_PROFILE} | grep name
sleep 10
Redeploying Stage
echo "Redeploying Stage"
aws apigateway create-deployment --rest-api-id ${RESTAPIID} --stage-name ${STAGENAME} --description ${STAGENAME} --profile ${AWS_PROFILE} | grep description
sleep 5
echo "REST API Endpoints configured and deployed successfully.."
Note: Proper time delay (wait) is needed in different steps ( as mentioned in seconds by sleep commands).
Here is an example of executing above shell script.(Assuming script name cloneapi.sh)
./cloneapi.sh MyAPI MyAPIStage MyLambdaFunction apxxxxx upxxxx
Where
MyAPI is New API Name
MyAPIStage is new API Stage Name
MyLambdaFunction is Lambda Function Name for New API
apxxxxx is the API ID (Cloning from)
upxxxx is Usage Plan ID
The above commands can be used with any AWS CLI version and on any Linux OS, but below is the CLI and OS version used.
aws --version
aws-cli/1.15.80 Python/2.7.14 Linux/4.14.94-89.73.amzn2.x86_64 botocore/1.10.79
cat /etc/os-release
NAME="Amazon Linux"
VERSION="2"
ID="amzn"
ID_LIKE="centos rhel fedora"
VERSION_ID="2"
PRETTY_NAME="Amazon Linux 2"
ANSI_COLOR="0;33"
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2"
HOME_URL="https://amazonlinux.com/"
From horse's mouth A.K.A AWS documentation
Export:
Go to API Gateway and click away as shown in the picture.
Creative Step:
Rename the API title: "title" and all the URI fields to something new "uri" in the exported JSON or YAML (depending which you selected)
Import
Just create new API and import what you had exported in the previous step.
Related
I'm trying to see usage of each API key in my usage plan. However when I run
aws apigateway get-usage --usage-plan-id ***** --start-date 2021-01-18 --end-date 2021-01-24 --profile prod --region ap-south-1 >> week04.txt
It returns usage of only few keys. When I try to do that from the AWS management console from here
It gives me the usage of the same few keys. I have to manually click every single key and generate the report which is very tedious. What am I doing wrong? Please help.
We can combine get-usage-plan-keys and get-usage with xargs to extract for every api key at once.
aws apigateway get-usage-plan-keys --usage-plan-id xx44ww | jq -r ".items[].id" | xargs -I {} aws apigateway get-usage --usage-plan-id xg4j0w --key-id {} --start-date 2021-01-01 --end-date 2021-01-24 --no-paginate > output.json
Breaking it down for better readability:
Getting usage plan keys:
aws apigateway get-usage-plan-keys --usage-plan-id xx44ww
Extracting plan keys
| jq -r ".items[].id"
loop for every api key id with xargs
aws apigateway get-usage --usage-plan-id xg4j0w --key-id {} --start-date 2021-01-01 --end-date 2021-01-24 --no-paginate
I want to have a form on my Jekyll website that visitors can fill out, and the form action should POST to an AWS Lambda function. No JavaScript is allowed on the website, so the POST must not require signing.
I want the simplest possible setup, and do not need high security. If there is a way to avoid using AWS API Gateway to create an HTTP API, and somehow have the Lambda function directly receive the POST from the user's web browser, that would be perfect. If API Gateway is required, then the simplest solution would be best.
I want to use command line commands exclusively (not a web browser) to work with the AWS API. This allows for a scripted solution.
I've spent some time on the problem, and here is what I've got. I've marked questions in the deploy script with TODO. There is some extra code in that script which might not be needed. Problem is, I'm unsure what to delete because I just can't figure out how to provide the POST to the lambda.
The scripts use jq and yq so the bash scripts can parse JSON and YAML, respectively.
_config.yml
aws:
cloudfront:
distributionId: "" # Provide value if CloudFront is used on this site
lambda:
addSubscriber:
custom: # TODO change these values to suit your website
iamRoleName: lambda-ex
name: addSubscriberAwsLambdaSample
handler: addSubscriberAwsLambda.lambda_handler
runtime: python3.8
computed: # These values are computed by the _bin/awsLambda setup and deploy scripts
arn: arn:aws:lambda:us-east-1:031372724784:function:addSubscriberAwsLambdaSample:3
iamRoleArn: arn:aws:iam::031372724784:role/lambda-ex
utils source bash script
#!/bin/bash
function readYaml {
# $1 - path
yq r _config.yml "$1"
}
function writeYaml {
# $1 - path
# $2 - value
yq w -i _config.yml "$1" "$2"
}
# AWS Lambda values
export LAMBDA_IAM_ROLE_ARN="$( readYaml aws.lambda.addSubscriber.computed.iamRoleArn )"
export LAMBDA_NAME="$( readYaml aws.lambda.addSubscriber.custom.name )"
export LAMBDA_RUNTIME="$( readYaml aws.lambda.addSubscriber.custom.runtime )"
export LAMBDA_HANDLER="$( readYaml aws.lambda.addSubscriber.custom.handler )"
export LAMBDA_IAM_ROLE_NAME="$( readYaml aws.lambda.addSubscriber.custom.iamRoleName )"
export PACKAGE_DIR="${GIT_ROOT}/_package"
export LAMBDA_ZIP="${PACKAGE_DIR}/function.zip"
# Misc values
export TITLE="$( readYaml title )"
export URL="$( readYaml url )"
export DOMAIN="$( echo "$URL" | sed -n -e 's,^https\?://,,p' )"
setup bash script
#!/bin/bash
# Inspired by https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-awscli.html
SOURCE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
GIT_ROOT="$( git rev-parse --show-toplevel )"
cd "${GIT_ROOT}"
source _bin/utils
# Define the execution role that gives an AWS Lambda function permission to access AWS resources.
read -r -d '' ROLE_POLICY_JSON <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
# If a role named $LAMBDA_IAM_ROLE_NAME is already defined then use it
ROLE_RESULT="$( aws iam get-role --role-name "$LAMBDA_IAM_ROLE_NAME" 2> /dev/null )"
if [ $? -ne 0 ]; then
ROLE_RESULT="$( aws iam create-role \
--role-name "$LAMBDA_IAM_ROLE_NAME" \
--assume-role-policy-document "$ROLE_POLICY_JSON"
)"
fi
LAMBDA_IAM_ROLE_ARN="$( jq -r .Role.Arn <<< "$ROLE_RESULT" )"
writeYaml aws.lambda.addSubscriber.computed.iamRoleArn "$LAMBDA_IAM_ROLE_ARN"
deploy bash script
# Call this script after the setup script has created the IAM role
# that gives the addSubscriber AWS Lambda function permission to access AWS resources
#
# 1) This script builds the AWS Lambda package and deploys it, with permissions.
# Any previous version of the AWS Lambda is deleted.
#
# 2) The newly (re)created AWS Lambda ARN is stored in _config.yml
#
# 3) An AWS Gateway HTTP API is created so static web pages can POST subscriber information to the AWS Lambda function.
# Because the web page is not allowed to have JavaScript, the POST is unsigned.
# *** The API must allow for an unsigned POST!!! ***
# Set cwd to the git project root
GIT_ROOT="$( git rev-parse --show-toplevel )"
cd "${GIT_ROOT}"
# Load configuration environment variables from _bin/utils:
# DOMAIN, LAMBDA_IAM_ROLE_ARN, LAMBDA_IAM_ROLE_NAME, LAMBDA_HANDLER, LAMBDA_NAME, LAMBDA_RUNTIME, LAMBDA_ZIP, PACKAGE_DIR, and URL
source _bin/utils
# Directory that this script resides in
SOURCE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
echo "Building the AWS Lambda and packaging it into a zip file"
"$SOURCE_DIR/package" "$PACKAGE_DIR" > /dev/null
# Check to see if the Lambda function already exists.
LAMBDA="$( aws lambda list-functions | jq ".Functions[] | select(.FunctionName | contains(\"$LAMBDA_NAME\"))" )"
if [ -z "$LAMBDA" ]; then
echo "The AWS Lambda function '$LAMBDA_NAME' does not exist yet, so create it"
LAMBDA_METADATA="$( aws lambda create-function \
--description "Add subscriber to the MailChimp list with ID '$MC_LIST_ID_MSLINN' for the '$DOMAIN' website" \
--environment "{
\"Variables\": {
\"MC_API_KEY_MSLINN\": \"$MC_API_KEY_MSLINN\",
\"MC_LIST_ID_MSLINN\": \"$MC_LIST_ID_MSLINN\",
\"MC_USER_NAME_MSLINN\": \"$MC_USER_NAME_MSLINN\"
}
}" \
--function-name "$LAMBDA_NAME" \
--handler "$LAMBDA_HANDLER" \
--role "arn:aws:iam::${AWS_ACCOUNT_ID}:role/$LAMBDA_IAM_ROLE_NAME" \
--runtime "$LAMBDA_RUNTIME" \
--zip-file "fileb://$LAMBDA_ZIP" \
| jq -S .
)"
LAMBDA_ARN="$( jq -r .Configuration.FunctionArn <<< "$LAMBDA_METADATA" )"
else
echo "The AWS Lambda function '$LAMBDA_NAME' already exists, so update it"
LAMBDA_METADATA="$( aws lambda update-function-code \
--function-name "$LAMBDA_NAME" \
--publish \
--zip-file "fileb://$LAMBDA_ZIP" \
| jq -S .
)"
LAMBDA_ARN="$( jq -r .FunctionArn <<< "$LAMBDA_METADATA" )"
fi
echo "AWS Lambda ARN is $LAMBDA_ARN"
writeYaml aws.lambda.addSubscriber.computed.arn "$LAMBDA_ARN"
echo "Attach the AWSLambdaBasicExecutionRole managed policy to $LAMBDA_IAM_ROLE_NAME."
aws iam attach-role-policy \
--role-name $LAMBDA_IAM_ROLE_NAME \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
#### Integrate with API Gateway for REST
#### Some or all of the following code is probably not required
GATEWAY_NAME="addSubscriberTo_$MC_LIST_ID_MSLINN"
API_GATEWAYS="$( aws apigateway get-rest-apis )"
if [ "$( jq ".items[] | select(.name | contains(\"$GATEWAY_NAME\"))" <<< "$API_GATEWAYS" )" ]; then
echo "API gateway '$GATEWAY_NAME' already exists."
else
echo "Creating API gateway '$GATEWAY_NAME'."
API_JSON="$( aws apigateway create-rest-api \
--name "$GATEWAY_NAME" \
--description "API for adding a subscriber to the Mailchimp list with ID '$MC_LIST_ID_MSLINN' for the '$DOMAIN' website"
)"
REST_API_ID="$( jq -r .id <<< "$API_JSON" )"
API_RESOURCES="$( aws apigateway get-resources --rest-api-id $REST_API_ID )"
ROOT_RESOURCE_ID="$( jq -r .items[0].id <<< "$API_RESOURCES" )"
NEW_RESOURCE="$( aws apigateway create-resource \
--rest-api-id "$REST_API_ID" \
--parent-id "$RESOURCE_ID" \
--path-part "{proxy+}"
)"
NEW_RESOURCE_ID=$( jq -r .id <<< $NEW_RESOURCE )
if false; then
# Is this step useful for any reason?
aws apigateway put-method \
--authorization-type "NONE" \
--http-method ANY \
--resource-id "$NEW_RESOURCE_ID" \
--rest-api-id "$REST_API_ID"
fi
# The following came from https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#set-up-lambda-proxy-integration-using-cli
# Instead of supplying an IAM role for --credentials, call the add-permission command to add resource-based permissions.
# I need an example of this.
# Alternatively, how to obtain IAM_ROLE_ID? Again, I need an example.
aws apigateway put-integration \
--credentials "arn:aws:iam::${IAM_ROLE_ID}:role/apigAwsProxyRole" \
--http-method ANY \
--integration-http-method POST \
--rest-api-id "$REST_API_ID" \
--resource-id "$NEW_RESOURCE_ID" \
--type AWS_PROXY \
--uri arn:aws:apigateway:`aws configure get region`:lambda:path/2015-03-31/functions/$LAMBDA_ARN
if [ "$LAMBDA_TEST"]; then
# Deploy the API to a test stage
aws apigateway create-deployment \
--rest-api-id "$REST_API_ID" \
--stage-name test
else
# Deploy the API live
aws apigateway create-deployment \
--rest-api-id "$REST_API_ID" \
--stage-name TODO_WhatNameGoesHere
fi
fi
echo "Check out the defined lambdas at https://console.aws.amazon.com/lambda/home?region=us-east-1#/functions"
Bash scripting infrastructure is bad. You might get it right eventually, but there are tools that make the process infinitely easier.
I prefer Terraform, and here's how an API Gateway + lambda would look like:
provider "aws" {
}
# lambda
resource "random_id" "id" {
byte_length = 8
}
data "archive_file" "lambda_zip" {
type = "zip"
output_path = "/tmp/lambda.zip"
source {
content = <<EOF
module.exports.handler = async (event, context) => {
// write the lambda code here
}
};
EOF
filename = "main.js"
}
}
resource "aws_lambda_function" "lambda" {
function_name = "${random_id.id.hex}-function"
filename = data.archive_file.lambda_zip.output_path
source_code_hash = data.archive_file.lambda_zip.output_base64sha256
handler = "main.handler"
runtime = "nodejs12.x"
role = aws_iam_role.lambda_exec.arn
}
data "aws_iam_policy_document" "lambda_exec_role_policy" {
statement {
actions = [
"logs:CreateLogStream",
"logs:PutLogEvents"
]
resources = [
"arn:aws:logs:*:*:*"
]
}
}
resource "aws_cloudwatch_log_group" "loggroup" {
name = "/aws/lambda/${aws_lambda_function.lambda.function_name}"
retention_in_days = 14
}
resource "aws_iam_role_policy" "lambda_exec_role" {
role = aws_iam_role.lambda_exec.id
policy = data.aws_iam_policy_document.lambda_exec_role_policy.json
}
resource "aws_iam_role" "lambda_exec" {
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow"
}
]
}
EOF
}
# api gw
resource "aws_apigatewayv2_api" "api" {
name = "api-${random_id.id.hex}"
protocol_type = "HTTP"
target = aws_lambda_function.lambda.arn
}
resource "aws_lambda_permission" "apigw" {
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.lambda.arn
principal = "apigateway.amazonaws.com"
source_arn = "${aws_apigatewayv2_api.api.execution_arn}/*/*"
}
output "domain" {
value = aws_apigatewayv2_api.api.api_endpoint
}
See that the last 2 resources are the API Gateway, all the previous ones are for the Lambda function.
Can anyone please provide CLI command to get the stack name and region that created a particular IAM role?
you will have to write a small looping script that goes through all the region and all the stack (with let's say 'CREATE_COMPLETE' status) and use the describe-stack-resources CLI command.
https://docs.aws.amazon.com/cli/latest/reference/cloudformation/describe-stack-resources.html
Here is a small example:
#!/bin/bash
for region in us-east-2 us-east-1 us-west-1 us-west-2 ap-east-1 ap-south-1 ap-northeast-3 ap-northeast-2 ap-southeast-1 ap-southeast-2 ap-northeast-1 ca-central-1 cn-north-1 cn-northwest-1 eu-central-1 eu-west-1 eu-west-2 eu-west-3 eu-north-1 me-south-1 sa-east-1
do
echo "Processing region $region ..."
for stack in $(aws cloudformation list-stacks --stack-status-filter CREATE_COMPLETE --output json --region $region | jq '.StackSummaries[] | .StackId' | sed -e 's/^"//' -e 's/"$//')
do
echo "Processing stack $stack ..."
aws cloudformation describe-stack-resources --stack-name $stack --output json --region $region | jq '.StackResources[] | select(.ResourceType=="AWS::IAM::Role") | select(.PhysicalResourceId=="PUT_YOUR_ROLE_NAME_HERE")'
done
done
Don't forget that if you have your role ARN you can easily get your account number and you role name. The format being
arn:aws:iam::account-id:role/role-name
I hope that helps, sorry about the oneliner, it's less readable.
aws cloudformation describe-stacks --stack-name myteststack
.net core serverless web api
I am trying to do proxy integration with lambda and api gateway, everything is working fine with aws console
but i am facing issues with aws cli commands
i tried integrating with cli but the lambda is not properly integrated
aws apigateway create-resource --rest-api-id id --parent-id id --path-part {proxy+}
aws apigateway put-method --rest-api-id id --resource-id id --http-method ANY --authorization-type "NONE"
aws apigateway put-integration --rest-api-id id --resource-id id --http-method ANY --type HTTP_PROXY --integration-http-method ANY --uri arn:aws:apigateway:us-east-2:lambda:path//2015-03-31/functions/arn:aws:lambda:us-east-2:account_id:function:helloworld/invocations
aws lambda add-permission --function-name helloworld --action lambda:InvokeFunction --principal apigateway.amazonaws.com --source-arn arn:aws:execute-api:us-east-2:account_id:apiid/*/*/* --statement-id 12345678
There are two problems with your commands -
Incorrect
aws apigateway create-resource --rest-api-id id --parent-id id --path-part {proxy+}
Correct: Notice the double quotes
aws apigateway create-resource --rest-api-id id --parent-id id --path-part "{proxy+}"
Incorrect
aws apigateway put-integration \
--rest-api-id id \
--resource-id id \
--http-method ANY \
--type HTTP_PROXY \
--integration-http-method ANY \
--uri arn:aws:apigateway:us-east-2:lambda:path//2015-03-31/functions/arn:aws:lambda:us-east-2:account_id:function:helloworld/invocations
Correct
type should be AWS_PROXY for Lambda Proxy Integrations.
integration-http-method should always be POST for Lambda Proxy integration, even if the http method is GET or ANY or anything else.
aws apigateway put-integration \
--rest-api-id id \
--resource-id id \
--http-method ANY \
--type AWS_PROXY \
--integration-http-method POST \
--uri arn:aws:apigateway:us-east-2:lambda:path//2015-03-31/functions/arn:aws:lambda:us-east-2:account_id:function:helloworld/invocations
I want to run this command: https://docs.aws.amazon.com/cli/latest/reference/apigateway/test-invoke-method.html
It requires these two fields, but I can't find any docs and where these are:
aws apigateway test-invoke-method --rest-api-id 1234123412 --resource-id avl5sg8fw8 --http-method GET --path-with-query-string '/'
My API gateway endpoint looks like this:
https://abc123.execute-api.us-east-1.amazonaws.com/MyStage/
I only see on unique identifier there - but this command seems to require two IDs. Where do I find them in the API Gateway console?
Your rest-api-id is the identifier before 'execute-api' in your endpoint URL.
In your example URL:
https://abc123.execute-api.us-east-1.amazonaws.com/MyStage/
The rest-api-id is abc123
The resource ID can be obtained with the CLI using the get-resources call and the rest-api-id:
> aws apigateway get-resources --rest-api-id abc123
{
"items": [
{
"id": "xxxx1",
"parentId": "xxxx0",
"pathPart": "foo",
"path": "/foo",
"resourceMethods": {
"GET": {}
}
},
{
"id": "xxxx0",
"path": "/"
}
]}
Each one of the records in the items attribute is a resource, and its id attribute is a resource ID you can use in your test-invoke-method in conjunction with a method that is associated with the resource.
Both values are visible at the top of the console when you select one of your endpoints/resources:
Here is a portion of a bash script that you could use, assuming you have jq installed to parse the json and only one API. It gets the first API ID from the items array, then looks up that Resource ID, then invokes the API using POST:
API_ID=`aws apigateway get-rest-apis | jq -r ".items[0].id"`
RESOURCE_ID=`aws apigateway get-resources --rest-api-id $API_ID | jq -r ".items[].id"`
aws apigateway test-invoke-method --rest-api-id $API_ID --resource-id $RESOURCE_ID --http-method POST