In my previous , I went through how to create a maintenance mode page for your application, and how to implement it using Terraform and github pages. But the website is just one part of an Application, and often there’s also a public (or private) API that also needs to have a maintenance mode. Let’s see how we can do that using Terraform on API Gateway. blog post Architecture As previously mentioned, we host all of our infrastructure on AWS, with a clear separation between the Application and the API: The front end is a React application, hosted on S3 with CloudFront as a CDN. The Backend services are mostly Serverless using AWS Lambda with API Gateway that manages our public API. DNS is managed by Route 53. Implementing a Solution Beyond the requirements , we had one new one: When the API is in maintenance it should return “503 Service Unavailable” response This led us led us to the following solution: for our webpage maintenance mode with an informative message. Create a new API Gateway that will be dedicated to the maintenance mode This API will use a mock integration It will return the same response for all endpoints using proxy resource This mocked API will co-exists with our real API. We will use and change the base mapping between the real API and the mocked one. custom domain Based on that, let’s see the Terraform code in action: Mocked API Gateway Looking at the code you are able to see that we are using ANY method together with “{proxy+}” to achieve the ability to cover all resources with a simple configuration, and using the response template to generate the “503 Service Unavailable” response with a clear message to the end user. resource { name = description = } { rest_api_id = aws_api_gateway_rest_api.maintenance_mode_api.id parent_id = aws_api_gateway_rest_api.maintenance_mode_api.root_resource_id path_part = } { rest_api_id = aws_api_gateway_rest_api.maintenance_mode_api.id resource_id = aws_api_gateway_resource.maintenance_mode_resource.id http_method = authorization = } { rest_api_id = aws_api_gateway_rest_api.maintenance_mode_api.id resource_id = aws_api_gateway_resource.maintenance_mode_resource.id http_method = aws_api_gateway_method.maintenance_mode_method.http_method = timeout_milliseconds = 29000 passthrough_behavior = request_templates = { = <<EOF { : 503} EOF } } { rest_api_id = aws_api_gateway_rest_api.maintenance_mode_api.id resource_id = aws_api_gateway_resource.maintenance_mode_resource.id http_method = aws_api_gateway_method.maintenance_mode_method.http_method status_code = } { rest_api_id = aws_api_gateway_rest_api.maintenance_mode_api.id resource_id = aws_api_gateway_resource.maintenance_mode_resource.id http_method = aws_api_gateway_method.maintenance_mode_method.http_method status_code = aws_api_gateway_method_response.maintenance_mode_response_503.status_code # Transforms the backend JSON response XML response_templates = { = <<EOF EOF } } { depends_on = [aws_api_gateway_integration.maintenance_mode_integration] rest_api_id = aws_api_gateway_rest_api.maintenance_mode_api.id stage_name = } "aws_api_gateway_rest_api" "maintenance_mode_api" "maintenance-mode-API" "This is my Maintenance mode API" resource "aws_api_gateway_resource" "maintenance_mode_resource" "{proxy+}" resource "aws_api_gateway_method" "maintenance_mode_method" "ANY" "NONE" resource "aws_api_gateway_integration" "maintenance_mode_integration" type "MOCK" "WHEN_NO_MATCH" "application/json" "statusCode" resource "aws_api_gateway_method_response" "maintenance_mode_response_503" "503" resource "aws_api_gateway_integration_response" "maintenance_mode_integration_response" to "application/json" #set($inputRoot = $input.path('$')) { "message" : "Sorry for the inconvenience but we are performing some maintenance at the moment. We will be back online shortly!" } resource "aws_api_gateway_deployment" "maintenance_mode_deployment" "prod" Now using a custom domain we can control the maintenance mode, so the base path mapping will either point to the real API and in case of a maintenance mode it will point to the mocked API. resource { certificate_arn = var.certificate_arn domain_name = var.domain_name } { api_id = var.is_maintenance_mode ? aws_api_gateway_rest_api.maintenance_mode_api.id : aws_api_gateway_rest_api.api.id stage_name = var.is_maintenance_mode ? aws_api_gateway_deployment.maintenance_mode_deployment.stage_name : aws_api_gateway_deployment.deployment.stage_name domain_name = aws_api_gateway_domain_name.domain_name.domain_name base_path = } "aws_api_gateway_domain_name" "domain_name" resource "aws_api_gateway_base_path_mapping" "base_mapping" "/" Also in AWS, we want to ensure that Route53 is pointing in the custom domain we’ve created. As opposed to the application maintenance mode, here our custom domain switches on and off our maintenance mode and not our DNS record. resource { zone_id = name = type = alias { name = aws_api_gateway_domain_name zone_id = aws_api_gateway_domain_name evaluate_target_health = false } } "aws_route53_record" "api_dns_record" var .route53_zone_id var .route53_suffix_domain_name "A" .domain_name .regional_domain_name .domain_name .regional_zone_id ⚠️ Pay attention that this Terraform code does not create the Route53 hosted zone, nor the SSL certificates — you need to complete those as appropriate for your own setup ⚠️ Deployment Now that our system is all configured, all I have to do is change the Terraform variable of the maintenance mode to be true/false and deploy the environment (in our case via the env0 UI). The complete template source code can be found in this which includes all the Terraform code. We hope you find this useful, or get other ideas for more ways to use Terraform for your deployment workflows. github repo About env0 env0 lets your team manage their own environments in AWS, Azure and Google, governed by your policies and with complete visibility & cost management. You can learn more about env0 and you can also . here try it out yourself Feel free to drop us your thoughts below! Previously published at https://www.env0.com/blog/creating-a-maintenance-mode-for-your-api-gateway-with-terraform