How to provision APIgateway StageVariables and Deployment using AWS CDK?
Tags: aws, serverless, python, cloudskills
Published: 2021-05-08 01:54:11

In [previous post](https://dev.to/upupkenchoong/concept-to-use-apigateway-stagevariables-lambda-version-alias-environment-variable-all-together-h8j), you know all the basic concept about how APIGateway, Lambda, Lambda version, alias, environment work together. 

Now, we start provision the APIgateway using the CDK python. 

[In this post](https://dev.to/upupkenchoong/how-to-provision-lambda-and-lambda-layer-with-cdk-2ff4), we already learned that provision Lambda and Lambda Layer, so we will use back the code here, if you new here, just read the post, cause I mention a lot details about Lambda and Lambda Layer [here](https://dev.to/upupkenchoong/how-to-provision-lambda-and-lambda-layer-with-cdk-2ff4)

Now your MySampleAppStack file look like this: 

```python

from aws_cdk.aws_lambda_python import PythonFunction, PythonLayerVersion


class MySampleStack(core.Stack):

        def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
           super().__init__(scope, id, **kwargs)

           # All the aws resources define here

            # Here define a Lambda Layer 
            boto3_lambda_layer = PythonLayerVersion(
               self, 'Boto3LambdaLayer',
               entry='lambda/boto3Folder',
               compatible_runtimes=[lambda_.Runtime.PYTHON_3_8],
               description='Boto3 Library',
               layer_version_name='Whatever name you want'
           )

          my_first_lambda_function=PythonFunction(
                 self, 'MyFirstLambda',
                 entry='lambda/MyFirstLambdaFunction',
                 index='app.py',
                 runtime=lambda_.Runtime.PYTHON_3_8,
                 layers=[boto3_lambda_layer], 
                 handler='MyFirstLambdaHandler',
                timeout=core.Duration.seconds(10)
          )


```

Alright, the Lambda already done, continue from here, we provision our API first. 

**First**
```
pip install aws_cdk.aws_apigateway
```
This install all the necessary package. 

[As mention in this post](https://dev.to/upupkenchoong/concept-to-use-apigateway-stagevariables-lambda-version-alias-environment-variable-all-together-h8j), we need 2 API stage named`dev` and `prod`,

`dev` is for us to develop and testing 
`prod` is for our production user 

Then we need to set the StageVaribles for each API stage which is 

`dev` stage have Stage Variables of `"lambdaAlias": "dev"`
`prod` stage have stage variables of `"lambdaAlias": "prod"` 

As you can see both API stage also have `lambdaAlias`, just the value is different. Therefore we will use this value to differentiate the API call from frontend is either developer or production user.

Again, I talk a lot of details [here](https://dev.to/upupkenchoong/concept-to-use-apigateway-stagevariables-lambda-version-alias-environment-variable-all-together-h8j), I strongly recommend you read it, this will help you better understand throughout the whole series. 

In order to achieve that, we do the code below, then I explain step by step. 

```python
from aws_cdk import (
    aws_lambda as lambda_,
    aws_apigateway as apigateway, #add this
    core
)

class MySampleStack(core.Stack):

        def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
           super().__init__(scope, id, **kwargs)

           # ... all the lambda code above 

           # define a dev deployment
           dev_deployment = apigateway.StageOptions(
              stage_name="dev",
              variables={
                "lambdaAlias": "dev" # this is stage variable 
            })

           # define an API 
           api = apigateway.LambdaRestApi(
               self, "MyAPI", # give it a name
               handler=my_first_lambda_function, # the lambda above
               deploy_options=dev_deployment
           )
         
           #define a prod deployment
           prod_deployment = apigateway.Deployment(
              self, "ProdDeployment08052021", # change the date here
              api=api,
              retain_deployments=True,
              # Change the description here as well for our reference
              description="Production API deployment as 08-05-2021 Live version"
        )

          # Production stage
          prod_stage = apigateway.Stage(
            self, "ProdStage",
            deployment=prod_deployment,
            stage_name="prod",
            variables={
                "lambdaAlias": "prod"
          })
```
**Some explanation for our code above**

**Dev deployment**
`dev_deployment`: This is our dev deployment. We define a stage named `dev` and the stage variable key value `"lambdaAlias": "dev"` 

**API**
`api` : This is our main API object, it will use `my_first_lambda_function` that we define above as `handler`. Means that, when this API endpoint is hit, it will trigger `my_first_lambda_function` by default(Lambda is not specially set to a method). We specify `deploy_options` to `dev_deployment` which means everytime we deploy our CDK, it will only update the `dev` stage and effect to `prod` stage, which is what we want. In other words, `dev` stage is the default stage of our API. 

**Prod deployment**
`prod_deployment` : This is our `prod` stage deployment. The ID `ProdDeployment08052021` in the code above, after we make sure everything is ok, and we like to push the stack the our production user, we change the date `08052021`, by this, CDK will create a brand new deployment for all the code your define in your stack. 

Remember, we only want update `dev_deployment` for testing, then everything ok then only push to production? 

This is exactly what we do, let's say we 3 new method to the API, at the meantime, we just testing in `dev_deployment`, `prod_deployment` is not effected. At 11-05-2021 we done all the testing, everything ok, is time to push to product, we change to `ProdDeployment11052021`, this will create a new `deployment` for all 3 method we defined before. 

**Prod stage**
`prod_stage`: This is the production stage of our API. All production user will hit this API stage. It will always use `prod_deployment`, so everytime a new `prod_deployment` created, it will use that. Therefore change the date in the ID, then new deployment is created, `prod_stage` will use that. This is how we update our production API stage. 

All right, for now the basic of our API is completed. 

Now we can add some API method to our API. We can do it like this: 

```python
# ... continue with the code above

store = api.root.add_resource("store") 
store.add_method("GET") # GET /store
store.add_method("POST") # POST /store

profile = api.root.add_resource("profile")
profile.add_method("GET") # GET /profile
profile.add_method("POST") # POST /profile

product = api.root.add_resource("product")
product.add_method("GET") # GET /product
product.add_method("DELETE") # DELETE /product

```

Alright, so now you have 3 API root, which is `store`, `profile` and `product` with all the different CRUD method. 

For now, if you ok for all the method you defined, you should change the date in `ProdDeployment<Your date>` and description in `prod_deployment`. 

**For summarize:**
In this tutorial, you learned about: 
1) How to create different API stage using CDK
2) How to create different API deployment using CDK
3) How to define stage variable for each API stage using CDK
4) How to define API method using CDK 

I hope all this make sense to you. Have a good day. 

*In next part of the series:*
For now, all this 3 API root(`store`, `profile` , `product`), no matter what CRUD method, it also will only trigger `my_first_lambda_function` that we define above.

In next part, I will make different API root, will trigger different lambda function. This is called **Lambda Integration**.

I also will tell how we can build our **CDK Constructs**, what is it and why we should use it. 

**Before you go,** if you like this series or find this useful consider to buy me a coffee 😊🤞 for 5 USD or more. 
I will prepare a GitHub repo for this whole tutorial series and arrange into separate commit for each part. 
This will only available for my supporter cause I spent a lot of time to prepare this. Anyway, I appreciate you here. Have a good day.

<a href="https://www.buymeacoffee.com/kenchoong" target="_blank">
![bmaco](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ap0mog1ue623vr1zbo36.jpg)
</a>

Shout out to me on Twitter: [@upupkenchoong](https://twitter.com/upupkenchoong)