API-Gateway ❤️ CloudWatch

API Gateway — The workhorse 🐴

Ever since API-Gateway was released by AWS back in 2015 people got surprised by their AWS bill: It was way more expensive to go server-less than expected.
Mostly this can be rooted to one point: API-Gateway is not intended as proxy or Load Balancer: If none of its features are used, it is a very expensive Load Balancer — with less features.

Do NOT do this — this is expensive
  • Its resources, methods, and its models to provide a stable API
  • Combining the request & response mapping the Apache Velocity templates to expose just the right amount of an AWS API
  • While providing security via IAM and such
  • And use caching & API-keys
Target solution

CloudWatch-The old accountant 👴

While CloudWatch is decent at what it does (well it’s not DataDog and not Splunk) it’s also old: It was first released in 2009 and the API definitely feels that way.

Matchmaking 🏇

The goal here is to expose a custom metric from CloudWatch via the API-Gateway without any Lambda & SDK. There are three main hurdles to overcome:

  • API-Gateway is really built around JSON & REST APIs— Query Parameters will need special handling
  • CloudWatch expects timestamps in ISO8601 but API-Gateway’s Velocity does not provide access to DateTool
  • CloudWatch has a very unique way to express lists. Once this is clear things become way smoother

It’s all about the headers

The first solution to the puzzle is to sent the right headers to the CloudWatch API from the API-Gateway. As the API-Gateway is built around JSON so we have disguise this origin:

Accept = "application/json"
Content-Type = "application/x-www-form-urlencoded"

URL query parameters for the win

As the CloudWatch API uses query parameters for each and everything, here is the request mapping (yes for application/json— or whatever our API-Gateway should expose to the client).
This is the most basic API request:

  • There cannot be any newlines in the mapping
  • The CloudWatch API state that it respects the Action (and Operation) but this always end in an error. Therefore the API-Gateway action integration is just set blank


For a realistic request and to fulfill the stated requirements from the beginning the array notation from the CloudWatch API must be used.
It follows the notation $NAME.member.1 for a string array. For complex objects it is $NAME.member.1.$PROPERTY — while the numeric counter must start by 1!

  • The version is set to 2010-08-01 to use the most ‘recent’ API schema
  • The metric to retrieve is in the namespace customNamespace/custom — and URL encoded
  • A Statistics must always provided in array format. Only Maximum is selected but the array notation must be used nevertheless.
  • The metricName is a path parameter derived from the API-Gateway resource. It is available via the $input variable.
  • Same goes for the startTime & the endTime (here a query parameter) from the caller. The format must be in ISO8601 AND URL encoded by the caller already (which is already the case as it is a query parameter for the API-Gateway itself)!
  • Period is set to static 60 seconds
  • Finally a Dimensions for the custom metric is selected. To do so, the dimension ( userId here) must be selected.
    The filter value is provided via Dimensions.member.1.Value : We use the caller’s Cognito identity. Here we let the API-Gateway perform the URL encoding.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store



CloudSpout.io serves to channel the power of the Cloud for today’s business & tomorrow’s growth.