Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AWS CloudFormation/API Gateway gives 'Invalid Resource identifier specified'

I have been trying to use CloudFormation to deploy to API Gateway, however, I constantly run into the same issue with my method resources. The stack deployments keep failing with 'Invalid Resource identifier specified'.

Here is my method resource from my CloudFormation template:

"UsersPut": {
        "Type": "AWS::ApiGateway::Method",
        "Properties": {
            "ResourceId": "UsersResource",
            "RestApiId": "MyApi",
            "ApiKeyRequired": true,
            "AuthorizationType": "NONE",
            "HttpMethod": "PUT",
            "Integration": {
                "Type": "AWS_PROXY",
                "IntegrationHttpMethod": "POST",
                "Uri": {
                    "Fn::Join": ["", ["arn:aws:apigateway:", {
                        "Ref": "AWS::Region"
                    }, ":lambda:path/2015-03-31/functions/", {
                        "Fn::GetAtt": ["MyLambdaFunc", "Arn"]
                    }, "/invocations"]]
                }
            },
            "MethodResponses": [{
                "StatusCode": 200
            }]
        }
    }

Is anyone able to help me figure out why this keeps failing the stack deployment?

UPDATE: I forgot to mention that I had also tried using references to add the resource ID, that also gave me the same error:

"UsersPut": {
        "Type": "AWS::ApiGateway::Method",
        "Properties": {
            "ResourceId": {
                "Ref": "UsersResource"
            },
            "RestApiId": "MyApi",
            "ApiKeyRequired": true,
            "AuthorizationType": "NONE",
            "HttpMethod": "PUT",
            "Integration": {
                "Type": "AWS_PROXY",
                "IntegrationHttpMethod": "POST",
                "Uri": {
                    "Fn::Join": ["", ["arn:aws:apigateway:", {
                        "Ref": "AWS::Region"
                    }, ":lambda:path/2015-03-31/functions/", {
                        "Fn::GetAtt": ["MyLambdaFunc", "Arn"]
                    }, "/invocations"]]
                }
            },
            "MethodResponses": [{
                "StatusCode": 200
            }]
        }
    }

Here is the full CloudFormation template:

{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
    "LambdaDynamoDBRole": {
        "Type": "AWS::IAM::Role",
        "Properties": {
            "AssumeRolePolicyDocument": {
                "Version": "2012-10-17",
                "Statement": [{
                    "Effect": "Allow",
                    "Principal": {
                        "Service": [
                            "lambda.amazonaws.com"
                        ]
                    },
                    "Action": [
                        "sts:AssumeRole"
                    ]
                }]
            },
            "Path": "/",
            "Policies": [{
                "PolicyName": "DynamoReadWritePolicy",
                "PolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [{
                        "Sid": "1",
                        "Action": [
                            "dynamodb:DeleteItem",
                            "dynamodb:GetItem",
                            "dynamodb:PutItem",
                            "dynamodb:Query",
                            "dynamodb:Scan",
                            "dynamodb:UpdateItem"
                        ],
                        "Effect": "Allow",
                        "Resource": "*"
                    }, {
                        "Sid": "2",
                        "Resource": "*",
                        "Action": [
                            "logs:CreateLogGroup",
                            "logs:CreateLogStream",
                            "logs:PutLogEvents"
                        ],
                        "Effect": "Allow"
                    }]
                }
            }]
        }
    },
    "MyFirstLambdaFn": {
        "Type": "AWS::Lambda::Function",
        "Properties": {
            "Code": {
                "S3Bucket": "myfirstlambdafn",
                "S3Key": "lambda_handler.py.zip"
            },
            "Description": "",
            "FunctionName": "MyFirstLambdaFn",
            "Handler": "lambda_function.lambda_handler",
            "MemorySize": 512,
            "Role": {
                "Fn::GetAtt": [
                    "LambdaDynamoDBRole",
                    "Arn"
                ]
            },
            "Runtime": "python2.7",
            "Timeout": 3
        },
        "DependsOn": "LambdaDynamoDBRole"
    },
    "MySecondLambdaFn": {
        "Type": "AWS::Lambda::Function",
        "Properties": {
            "Code": {
                "S3Bucket": "mysecondlambdafn",
                "S3Key": "lambda_handler.py.zip"
            },
            "Description": "",
            "FunctionName": "MySecondLambdaFn",
            "Handler": "lambda_function.lambda_handler",
            "MemorySize": 512,
            "Role": {
                "Fn::GetAtt": [
                    "LambdaDynamoDBRole",
                    "Arn"
                ]
            },
            "Runtime": "python2.7",
            "Timeout": 3
        },
        "DependsOn": "LambdaDynamoDBRole"
    },
    "MyApi": {
        "Type": "AWS::ApiGateway::RestApi",
        "Properties": {
            "Name": "Project Test API",
            "Description": "Project Test API",
            "FailOnWarnings": true
        }
    },
    "FirstUserPropertyModel": {
        "Type": "AWS::ApiGateway::Model",
        "Properties": {
            "ContentType": "application/json",
            "Name": "FirstUserPropertyModel",
            "RestApiId": {
                "Ref": "MyApi"
            },
            "Schema": {
                "$schema": "http://json-schema.org/draft-04/schema#",
                "title": "FirstUserPropertyModel",
                "type": "object",
                "properties": {
                    "Email": {
                        "type": "string"
                    }
                }
            }
        }
    },
    "SecondUserPropertyModel": {
        "Type": "AWS::ApiGateway::Model",
        "Properties": {
            "ContentType": "application/json",
            "Name": "SecondUserPropertyModel",
            "RestApiId": {
                "Ref": "MyApi"
            },
            "Schema": {
                "$schema": "http://json-schema.org/draft-04/schema#",
                "title": "SecondUserPropertyModel",
                "type": "object",
                "properties": {
                    "Name": {
                        "type": "string"
                    }
                }
            }
        }
    },
    "ErrorCfn": {
        "Type": "AWS::ApiGateway::Model",
        "Properties": {
            "ContentType": "application/json",
            "Name": "ErrorCfn",
            "RestApiId": {
                "Ref": "MyApi"
            },
            "Schema": {
                "$schema": "http://json-schema.org/draft-04/schema#",
                "title": "Error Schema",
                "type": "object",
                "properties": {
                    "message": {
                        "type": "string"
                    }
                }
            }
        }
    },
    "UsersResource": {
        "Type": "AWS::ApiGateway::Resource",
        "Properties": {
            "RestApiId": {
                "Ref": "MyApi"
            },
            "ParentId": {
                "Fn::GetAtt": ["MyApi", "RootResourceId"]
            },
            "PathPart": "users"
        }
    },
    "UsersPost": {
        "Type": "AWS::ApiGateway::Method",
        "Properties": {
            "ResourceId": {
                "Ref": "UsersResource"
            },
            "RestApiId": "MyApi",
            "ApiKeyRequired": true,
            "AuthorizationType": "NONE",
            "HttpMethod": "POST",
            "Integration": {
                "Type": "AWS_PROXY",
                "IntegrationHttpMethod": "POST",
                "Uri": {
                    "Fn::Join": ["", ["arn:aws:apigateway:", {
                        "Ref": "AWS::Region"
                    }, ":lambda:path/2015-03-31/functions/", {
                        "Fn::GetAtt": ["MyFirstLambdaFn", "Arn"]
                    }, "/invocations"]]
                }
            },
            "MethodResponses": [{
                "ResponseModels": {
                    "application/json": {
                        "Ref": "FirstUserPropertyModel"
                    }
                },
                "StatusCode": 200
            }, {
                "ResponseModels": {
                    "application/json": {
                        "Ref": "ErrorCfn"
                    }
                },
                "StatusCode": 404
            }, {
                "ResponseModels": {
                    "application/json": {
                        "Ref": "ErrorCfn"
                    }
                },
                "StatusCode": 500
            }]
        }
    },
    "UsersPut": {
        "Type": "AWS::ApiGateway::Method",
        "Properties": {
            "ResourceId": {
                "Ref": "UsersResource"
            },
            "RestApiId": "MyApi",
            "ApiKeyRequired": true,
            "AuthorizationType": "NONE",
            "HttpMethod": "PUT",
            "Integration": {
                "Type": "AWS_PROXY",
                "IntegrationHttpMethod": "POST",
                "Uri": {
                    "Fn::Join": ["", ["arn:aws:apigateway:", {
                        "Ref": "AWS::Region"
                    }, ":lambda:path/2015-03-31/functions/", {
                        "Fn::GetAtt": ["MySecondLambdaFn", "Arn"]
                    }, "/invocations"]]
                }
            },
            "MethodResponses": [{
                "ResponseModels": {
                    "application/json": {
                        "Ref": "SecondUserPropertyModel"
                    }
                },
                "StatusCode": 200
            }, {
                "ResponseModels": {
                    "application/json": {
                        "Ref": "ErrorCfn"
                    }
                },
                "StatusCode": 404
            }, {
                "ResponseModels": {
                    "application/json": {
                        "Ref": "ErrorCfn"
                    }
                },
                "StatusCode": 500
            }]
        }
    },
    "RestApiDeployment": {
        "Type": "AWS::ApiGateway::Deployment",
        "Properties": {
            "RestApiId": {
                "Ref": "MyApi"
            },
            "StageName": "Prod"
        },
        "DependsOn": ["UsersPost", "UsersPut"]
    }
},
"Description": "Project description"

}

like image 623
user3067870 Avatar asked Jun 07 '17 12:06

user3067870


2 Answers

ResourceId must be a reference to a cloudformation resource, not a simple string.

e.g.

  ResourceId:
    Ref: UsersResource
like image 100
jens walter Avatar answered Nov 03 '22 09:11

jens walter


I figured that actually it was the RestApiId which needed to be a reference too:

            "RestApiId": {
                "Ref": "MyApi"
            },
like image 36
user3067870 Avatar answered Nov 03 '22 11:11

user3067870