Search code examples
node.jsaws-api-gatewayaws-cdk

AWS CDK Api Gateway Models Ref Dependency - Model reference must be in canonical form


I am trying to add multiple models in the same time using aws CDK when one of the models is referencing the other one. Ex:

  "Gender": {
    "contentType": "application/json",
    "modelName": "GenderModel",
    "schema": {
      "type": "string",
      "enum": [
        "Not Specified",
        "Male",
        "Female",
        "Non-Binary"
      ],
      "schema": "http://json-schema.org/draft-04/schema#",
      "title": "GenderModel"
    }
  },

and

"Requirements": {
    "contentType": "application/json",
    "modelName": "RequirementsModel",
    "schema": {
      "type": "object",
      "properties": {
        "gender": {
          "ref": "https://apigateway.amazonaws.com/restapis/${Token[TOKEN.791]}/models/GenderModel"
        }
      },
      "required": [
        "gender",
      ],
      "additionalProperties": false,
      "schema": "http://json-schema.org/draft-04/schema#",
      "title": "RequirementsModel"
    }
  },

When i deploy this fails with

Model reference must be in canonical form

From what i can see this fails because the GenderModel does not exists. If i first add the GenderModel in the stack and then i add the RequirementsModel and deploy again it works just fine because the GenderModel was previously created. If i want to create both of the models in the same time it will fail. I tried to make sure the order of addModel call is correct but it seems it does not work.

Solution Found

Seems like you have to add explicitly specify the dependency.

modelB.node.addDependency(modelA)

This will avoid the error and add the models in the correct order


Solution

  • The problem is https://apigateway.amazonaws.com/restapis/${Token[TOKEN.791]}/models/GenderModel, specifically the ${Token[TOKEN.791]} part. When the API is not created, at CloudFormation synthetisation time, id is not known and placeholder value used - https://docs.aws.amazon.com/cdk/latest/guide/tokens.html

    You can use the Ref intristic function to compose model by the reference

    const getModelRef = (api: RestApi, model: Model): string => 
        Fn.join(
            '',
            ['https://apigateway.amazonaws.com/restapis/',
            api.restApiId,
            '/models/',
            model.modelId]);