ЁЯПл The SchoolтА║ЁЯЫОя╕П API GatewayтА║ЁЯЫбя╕П рдзрдбрд╛ 12 тАФ Private APIs, WAF, рдорд░реНрдпрд╛рджрд╛ рдЖрдгрд┐ рдЦрд░реНрдЪ: рдХрдбрдХ рдорд░реНрдпрд╛рджрд╛
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯЫбя╕П рдзрдбрд╛ 12 тАФ Private APIs, WAF, рдорд░реНрдпрд╛рджрд╛ рдЖрдгрд┐ рдЦрд░реНрдЪ: рдХрдбрдХ рдорд░реНрдпрд╛рджрд╛

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 12 ┬╖ рдорд╛рдЧреЗ: lesson-11-monitoring


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбреЗ 01тАУ11, рдЖрдгрд┐ рдлрдХреНрдд рдЗрдЪреНрдЫрд╛ рдХрд░реВрди рди рд╣рд▓рдгрд╛рд▒реНрдпрд╛ рдорд░реНрдпрд╛рджрд╛: integration timeout (REST APIs рд╡рд░ default 29 s, HTTP APIs рд╡рд░ 30 s), 10 MB payload рдорд░реНрдпрд╛рджрд╛, interface VPC endpoint рдорд╛рдЧрдЪреЗ private APIs, REST stages рд╕рдореЛрд░рдЪрд╛ AWS WAF, рдЖрдгрд┐ bill. apigw/demo.py рдордзрд▓реЗ limits() 504 рдЖрдгрд┐ 502 рджрд╛рдЦрд╡рддреЗ, рдЖрдгрд┐ рдиреЗрдордХреНрдпрд╛ рдорд░реНрдпрд╛рджрд╛ рддреБрдореНрд╣реА рд╕реНрд╡рддрдГ рд╢реЛрдзрддрд╛.

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

Front office рдЪреЗ рдХрд╛рд╣реА рдирд┐рдпрдо рдЕрд╕реЗ рдЖрд╣реЗрдд рдЬреЗ рдХреЛрдгреАрд╣реА рд╡рд╛рдХрд╡реВ рд╢рдХрдд рдирд╛рд╣реА:

рдХрд╛рд╣реА offices рдлрдХреНрдд рд╢рд╛рд│реЗрдЪреНрдпрд╛ рдЖрддрдЪ ЁЯПл рдЕрд╕рддрд╛рдд тАФ рдПрдХ рдЦрд╛рдЬрдЧреА рджрд╛рд░, рдЬреНрдпрд╛рдкрд░реНрдпрдВрдд рдЖрдзреАрдЪ campus рд╡рд░ рдЕрд╕рд▓реЗрд▓реЗ рд▓реЛрдХрдЪ рдкреЛрд╣реЛрдЪреВ рд╢рдХрддрд╛рдд. рдЖрдгрд┐ office рд╕рдореЛрд░ рдПрдХ рдкрд╣рд╛рд░реЗрдХрд░реА ЁЯЫбя╕П (WAF) рдЙрднрд╛ рд░рд╛рд╣реВ рд╢рдХрддреЛ, рдЬреЛ рдУрд│рдЦреАрдЪреНрдпрд╛ рддреНрд░рд╛рд╕рджрд╛рдпрдХ рд▓реЛрдХрд╛рдВрдирд╛ clerk рдкрд░реНрдпрдВрдд рдкреЛрд╣реЛрдЪрдгреНрдпрд╛рдЖрдзреАрдЪ рдкрд░рдд рдкрд╛рдард╡рддреЛ.

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart LR
    c["ЁЯЩЛ caller"] --> waf["ЁЯЫбя╕П AWS WAF<br/>SQL injection ┬╖ IP sets ┬╖ rate rules"]
    waf --> gw["ЁЯЫОя╕П REST API stage"]
    gw -->|"body > 10 MB"| e413["413 Request too large"]
    gw -->|"kitchen > 29 s"| e504["504 Endpoint request timed out"]
    gw -->|"kitchen crashes"| e502["502 Internal server error"]
    vpc["ЁЯПл VPC тЖТ interface endpoint<br/>com.amazonaws.region.execute-api"] -->|"resource policy allows this vpce"| priv["ЁЯФТ private API"]

ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрдХреГрддреА + рдПрдХ lab: https://school-edh.pages.dev/apigateway/lesson-diagrams.html#l12

тЭУ рдХрд╛рдп

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг рдпрд╛ рдорд░реНрдпрд╛рджрд╛ рддреБрдордЪреЗ design рдард░рд╡рддрд╛рдд, рддреБрдордЪреЗ configuration рдирд╛рд╣реА. 45 рд╕реЗрдХрдВрджрд╛рдВрдЪрд╛ report default timeout рдЕрд╕рд▓реЗрд▓реНрдпрд╛ REST API рдорд╛рдЧреЗ рдирдХреНрдХреАрдЪ рдЕрдкрдпрд╢реА рдард░реЗрд▓, рддреБрдореНрд╣реА рдХрд┐рддреАрд╣реА tune рдХреЗрд▓реЗ рддрд░реА тАФ рдЙрдкрд╛рдп рдореНрд╣рдгрдЬреЗ рд╡реЗрдЧрд│рд╛ рдЖрдХрд╛рд░ (рдЖрдзреА рд╕реНрд╡реАрдХрд╛рд░рд╛, рдордЧ poll). Private API рд╣рд╛ internal service рдкреНрд░рд╕рд┐рджреНрдз рдХрд░рдгреНрдпрд╛рдЪрд╛, internet рдЪрд╛ рдХреЛрдгрддрд╛рд╣реА рдорд╛рд░реНрдЧ рди рдареЗрд╡рддрд╛, рд╕рдЧрд│реНрдпрд╛рдд рд╕реЛрдкрд╛ рдорд╛рд░реНрдЧ рдЖрд╣реЗ. рдЖрдгрд┐ bill рдкреНрд░рддреНрдпреЗрдХ request рд╕реЛрдмрдд рд╡рд╛рдврддреЗ, рдореНрд╣рдгреВрди рдЦреВрдк рдЬрд╛рд╕реНрдд рдЖрдгрд┐ рд╕реНрдерд┐рд░ volume рд╡рд░ load balancer рд╕реНрд╡рд╕реНрдд рдкрдбреВ рд╢рдХрддреЛ.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

apigw/gateway.py рдордзреНрдпреЗ рдорд░реНрдпрд╛рджрд╛ constants рдореНрд╣рдгреВрди рдЖрд╣реЗрдд: TIMEOUT_S = 29 рдЖрдгрд┐ MAX_PAYLOAD = 10 * 1024 * 1024. Gateway._handle() рдордзреНрдпреЗ MAX_PAYLOAD рдкреЗрдХреНрд╖рд╛ (JSON рдореНрд╣рдгреВрди) рдореЛрдареНрдпрд╛ body рд▓рд╛ 413 рдорд┐рд│рддреЛ; рдЬреНрдпрд╛ route рдЪреА latency 29 s рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд рдЖрд╣реЗ рддреНрдпрд╛рд▓рд╛ kitchen рд▓рд╛ call рди рдХрд░рддрд╛рдЪ 504 рдорд┐рд│рддреЛ; exception рдлреЗрдХрдгрд╛рд▒реНрдпрд╛ integration рд▓рд╛ 502 Internal server error рдорд┐рд│рддреЛ. apigw/demo.py рдордзреНрдпреЗ /report рд▓рд╛ 31 s рд▓рд╛рдЧрддрд╛рдд рдЖрдгрд┐ /broken RuntimeError рдлреЗрдХрддреЛ. Private endpoints, WAF рдЖрдгрд┐ рдХрд┐рдорддреА limits() рдЫрд╛рдкрддреЗ тАФ lab рддреНрдпрд╛ рдЪрд╛рд▓рд╡реВ рд╢рдХрдд рдирд╛рд╣реА.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

python3 apigw/demo.py limits
python3 - <<'EOF'
import sys; sys.path.insert(0, "apigw"); from demo import office
from gateway import Route, TIMEOUT_S, MAX_PAYLOAD
gw, _ = office()
gw.add(Route("GET", "/slow/{s}", lambda e: (200, {"ok": True}), latency=29),
       Route("GET", "/slower/{s}", lambda e: (200, {"ok": True}), latency=29.5),
       Route("POST", "/upload", lambda e: (201, {"size": len(e["body"]["data"])})))
print("29 s  :", gw.handle("GET", "/slow/x")[0::2])
print("29.5 s:", gw.handle("GET", "/slower/x")[0::2])
print("limit :", TIMEOUT_S, "s ┬╖", MAX_PAYLOAD, "bytes")
print("1 MB  :", gw.handle("POST", "/upload", body={"data": "x" * 1_000_000})[0::2])
print("11 MB :", gw.handle("POST", "/upload", body={"data": "x" * 11_000_000})[0::2])
EOF
python3 apigw/test_apigw.py

рдЖрдгрд┐ рдЪрд╛рд▓реВ office рд╡рд░:

python3 apigw/demo.py serve &
sleep 1                                # give the office a second to open
curl -i localhost:8080/report
kill %1

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

limits рдЫрд╛рдкрддреЗ hard edges: integration timeout 29 s (REST default), payload 10 MB, GET /report тЖТ 504 {'message': 'Endpoint request timed out'}, GET /broken тЖТ 502 {'message': 'Internal server error'}, рдордЧ рд▓рд╛рдВрдм рдХрд╛рдореЗ, private API, WAF рдпрд╛рдВрдЪреНрдпрд╛ рдУрд│реА, рдЖрдгрд┐ cost (example, us-east-1): REST ~$3.50 per million requests, HTTP ~$1.00 per million тАФ plus cache hours and data out.

рддреБрдордЪрд╛ snippet рд╣реЗ рдЫрд╛рдкрддреЛ:

29 s  : (200, {'ok': True})
29.5 s: (504, {'message': 'Endpoint request timed out'})
limit : 29 s ┬╖ 10485760 bytes
1 MB  : (201, {'size': 1000000})
11 MB : (413, {'message': 'Request too large'})

рдЖрдгрд┐ tests 12/12 passed рдиреЗ рд╕рдВрдкрддрд╛рдд. рдЪрд╛рд▓реВ office {"message": "Endpoint request timed out"} рд╕рд╣ HTTP/1.0 504 Gateway Timeout рдЙрддреНрддрд░ рджреЗрддреЗ.

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

рддреБрдореНрд╣реА рдорд░реНрдпрд╛рджрд╛ рдиреЗрдордХреНрдпрд╛ рд╢реЛрдзрд▓реНрдпрд╛: 29 s рдкрд╛рд╕ рд╣реЛрддреЛ рдЖрдгрд┐ 29.5 s рдирд╛рд╣реА; 1 MB рдкрд╛рд╕ рд╣реЛрддреЛ рдЖрдгрд┐ 11 MB рдирд╛рд╣реА; рдмрд┐рдШрдбрд▓реЗрд▓реЗ kitchen рддрдкрд╢реАрд▓ рд▓рдкрд╡рдгрд╛рд░рд╛ рд╕рд╛рдзрд╛ 502 рдмрдирддреЗ.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд

рдЦрд▒реНрдпрд╛ account рд╡рд░ тАФ execute-api рд╕рд╛рдареА interface endpoint, рдлрдХреНрдд рддреЛрдЪ рд╕реНрд╡реАрдХрд╛рд░рдгрд╛рд░рд╛ private REST API, рдЖрдгрд┐ public stage рд╡рд░ WAF:

aws ec2 create-vpc-endpoint --vpc-id vpc-0123456789abcdef0 --vpc-endpoint-type Interface \
    --service-name com.amazonaws.ap-south-1.execute-api \
    --subnet-ids subnet-0aaa1111bbbb2222c --security-group-ids sg-0123456789abcdef0
aws apigateway create-rest-api --name school-internal --endpoint-configuration types=PRIVATE \
    --policy file://private-policy.json
aws wafv2 associate-web-acl \
    --web-acl-arn arn:aws:wafv2:ap-south-1:111122223333:regional/webacl/school-api-acl/1234abcd-12ab-34cd-56ef-1234567890ab \
    --resource-arn arn:aws:apigateway:ap-south-1::/restapis/abc123/stages/prod

private-policy.json тАФ рдлрдХреНрдд рддреНрдпрд╛ рдПрдХрд╛рдЪ endpoint рдордзреВрди calls рдирд╛ рдкрд░рд╡рд╛рдирдЧреА:

{
  "Version": "2012-10-17",
  "Statement": [
    { "Effect": "Allow", "Principal": "*", "Action": "execute-api:Invoke",
      "Resource": "execute-api:/*" },
    { "Effect": "Deny", "Principal": "*", "Action": "execute-api:Invoke",
      "Resource": "execute-api:/*",
      "Condition": { "StringNotEquals": { "aws:SourceVpce": "vpce-0123456789abcdef0" } } }
  ]
}

ЁЯПн Production рдордзреНрдпреЗ рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ рдЖрд╣реЗ: рдкрд╣рд┐рд▓реНрдпрд╛ рджрд┐рд╡рд╕рд╛рдкрд╛рд╕реВрдирдЪ рд▓рд╛рдВрдм рдХрд╛рдореЗ accept-then-poll рдореНрд╣рдгреВрди design рдХрд░рд╛, files S3 рдордзреВрди рдкрд╛рдард╡рд╛, internal APIs private рдареЗрд╡рд╛, public REST stages рд╕рдореЛрд░ WAF рдареЗрд╡рд╛, рдЖрдгрд┐ рдорд╣рд┐рдиреНрдпрд╛рддреВрди рдПрдХрджрд╛ рд╕рдВрдкреВрд░реНрдг bill рд╡рд╛рдЪрд╛ тАФ рдлрдХреНрдд requests рдЪреА рдУрд│ рдирд╛рд╣реА.

ЁЯОУ Front office рдЖрддрд╛ рддреБрдордЪреЗ рдЖрд╣реЗ

рдПрдХ front office тЖТ offices рдЪреЗ рддреАрди рдкреНрд░рдХрд╛рд░ тЖТ рдХреЛрдгрддрд╛ desk, рдХреЛрдгрддреЗ kitchen тЖТ form рддрдкрд╛рд╕рдгреА рдЖрдгрд┐ рд╕реНрд╡рдЪреНрдЫ рдЙрддреНрддрд░ тЖТ рд░рдВрдЧреАрдд рддрд╛рд▓реАрдо рдЖрдгрд┐ рдЦрд░рд╛ рдкреНрд░рдпреЛрдЧ тЖТ badge рддрдкрд╛рд╕рдгреА тЖТ рджрд╛рд░рд╛рд╡рд░рдЪрд╛ token bucket тЖТ рд╕реВрдЪрдирд╛ рдлрд▓рдХ тЖТ browser рдЖрдзреА рд╡рд┐рдЪрд╛рд░рддреЛ тЖТ рдирд╛рд╡рдлрд▓рдХ тЖТ dashboard рдЖрдгрд┐ stopwatch тЖТ рдХрдбрдХ рдорд░реНрдпрд╛рджрд╛. рддреБрдореНрд╣реА рдлрдХреНрдд API Gateway рд╢рд┐рдХрд▓рд╛ рдирд╛рд╣реАрдд тАФ рддреБрдореНрд╣реА front office рдЪрд╛рд▓рд╡реВ рд╢рдХрддрд╛. ЁЯЫОя╕ПЁЯОУ

рд╢рд╛рд│реЗрддрд▓реА рдкреБрдврдЪреА рджрд╛рд░реЗ: API school office рдорд╛рдЧреЗ рдХрд╛рдп рдмрд╕рддреЗ рддреНрдпрд╛рдЪреЗ design рдХрд░рддреЗ; IAM school SigV4 рдЖрдгрд┐ IAM auth рдорд╛рдЧрдЪреЗ roles рд╕рдордЬрд╛рд╡рддреЗ; VPC school private API рдЬреНрдпрд╛рдд рд░рд╛рд╣рддреЛ рддреЛ рдЦрд╛рдЬрдЧреА campus рдмрд╛рдВрдзрддреЗ.

git checkout main
python3 apigw/demo.py     # one last run, for fun

ЁЯЫбя╕П Lesson 12 тАФ Private APIs, WAF, limits & cost: the hard edges

ЁЯУН You are here: Lesson 12 of 12 ┬╖ Previous: lesson-11-monitoring


ЁЯУж What's in this branch

Lessons 01тАУ11, plus the edges you cannot move by wishing: the integration timeout (29 s by default on REST APIs, 30 s on HTTP APIs), the 10 MB payload limit, private APIs behind an interface VPC endpoint, AWS WAF in front of REST stages, and the bill. limits() in apigw/demo.py shows a 504 and a 502, and you find the exact edges yourself.

ЁЯзТ Explain like I'm 5

The front office has a few rules that nobody can bend:

Some offices are inside the school only ЁЯПл тАФ a private door that only people already on the campus can reach. And a guard ЁЯЫбя╕П (WAF) can stand in front of the office, turning away known troublemakers before they even reach the clerk.

ЁЯЧ║я╕П Diagram

flowchart LR
    c["ЁЯЩЛ caller"] --> waf["ЁЯЫбя╕П AWS WAF<br/>SQL injection ┬╖ IP sets ┬╖ rate rules"]
    waf --> gw["ЁЯЫОя╕П REST API stage"]
    gw -->|"body > 10 MB"| e413["413 Request too large"]
    gw -->|"kitchen > 29 s"| e504["504 Endpoint request timed out"]
    gw -->|"kitchen crashes"| e502["502 Internal server error"]
    vpc["ЁЯПл VPC тЖТ interface endpoint<br/>com.amazonaws.region.execute-api"] -->|"resource policy allows this vpce"| priv["ЁЯФТ private API"]

ЁЯЧ║я╕П Drawn version + a lab: https://school-edh.pages.dev/apigateway/lesson-diagrams.html#l12

тЭУ What

ЁЯдФ Why

Because these edges decide your design, not your configuration. A 45-second report will fail behind a REST API with the default timeout, however you tune it тАФ the fix is a different shape (accept, then poll). A private API is the simplest way to publish an internal service without any internet path. And the bill grows with every request, so at very high steady volume a load balancer can be cheaper.

ЁЯФз How (in this repo)

apigw/gateway.py has the edges as constants: TIMEOUT_S = 29 and MAX_PAYLOAD = 10 * 1024 * 1024. In Gateway._handle() a body larger than MAX_PAYLOAD (as JSON) gets 413; a route whose latency is more than 29 s gets 504 without calling the kitchen; an integration that raises an exception gets 502 Internal server error. In apigw/demo.py, /report takes 31 s and /broken raises RuntimeError. Private endpoints, WAF and prices are printed by limits() тАФ the lab cannot run them.

ЁЯзк Try it

python3 apigw/demo.py limits
python3 - <<'EOF'
import sys; sys.path.insert(0, "apigw"); from demo import office
from gateway import Route, TIMEOUT_S, MAX_PAYLOAD
gw, _ = office()
gw.add(Route("GET", "/slow/{s}", lambda e: (200, {"ok": True}), latency=29),
       Route("GET", "/slower/{s}", lambda e: (200, {"ok": True}), latency=29.5),
       Route("POST", "/upload", lambda e: (201, {"size": len(e["body"]["data"])})))
print("29 s  :", gw.handle("GET", "/slow/x")[0::2])
print("29.5 s:", gw.handle("GET", "/slower/x")[0::2])
print("limit :", TIMEOUT_S, "s ┬╖", MAX_PAYLOAD, "bytes")
print("1 MB  :", gw.handle("POST", "/upload", body={"data": "x" * 1_000_000})[0::2])
print("11 MB :", gw.handle("POST", "/upload", body={"data": "x" * 11_000_000})[0::2])
EOF
python3 apigw/test_apigw.py

And on the live office:

python3 apigw/demo.py serve &
sleep 1                                # give the office a second to open
curl -i localhost:8080/report
kill %1

тЬЕ Verify тАФ what you should see

limits prints hard edges: integration timeout 29 s (REST default), payload 10 MB, GET /report тЖТ 504 {'message': 'Endpoint request timed out'}, GET /broken тЖТ 502 {'message': 'Internal server error'}, then the lines on long jobs, the private API, WAF and cost (example, us-east-1): REST ~$3.50 per million requests, HTTP ~$1.00 per million тАФ plus cache hours and data out.

Your snippet prints:

29 s  : (200, {'ok': True})
29.5 s: (504, {'message': 'Endpoint request timed out'})
limit : 29 s ┬╖ 10485760 bytes
1 MB  : (201, {'size': 1000000})
11 MB : (413, {'message': 'Request too large'})

and the tests end with 12/12 passed. The live office answers HTTP/1.0 504 Gateway Timeout with {"message": "Endpoint request timed out"}.

ЁЯПБ What you just proved

You found the edges exactly: 29 s passes and 29.5 s does not; 1 MB passes and 11 MB does not; a crashing kitchen becomes a plain 502 that hides the details.

тЪая╕П Common mistakes

ЁЯПн In production

On a real account тАФ an interface endpoint for execute-api, a private REST API that only accepts it, and WAF on a public stage:

aws ec2 create-vpc-endpoint --vpc-id vpc-0123456789abcdef0 --vpc-endpoint-type Interface \
    --service-name com.amazonaws.ap-south-1.execute-api \
    --subnet-ids subnet-0aaa1111bbbb2222c --security-group-ids sg-0123456789abcdef0
aws apigateway create-rest-api --name school-internal --endpoint-configuration types=PRIVATE \
    --policy file://private-policy.json
aws wafv2 associate-web-acl \
    --web-acl-arn arn:aws:wafv2:ap-south-1:111122223333:regional/webacl/school-api-acl/1234abcd-12ab-34cd-56ef-1234567890ab \
    --resource-arn arn:aws:apigateway:ap-south-1::/restapis/abc123/stages/prod

private-policy.json тАФ allow calls only through that one endpoint:

{
  "Version": "2012-10-17",
  "Statement": [
    { "Effect": "Allow", "Principal": "*", "Action": "execute-api:Invoke",
      "Resource": "execute-api:/*" },
    { "Effect": "Deny", "Principal": "*", "Action": "execute-api:Invoke",
      "Resource": "execute-api:/*",
      "Condition": { "StringNotEquals": { "aws:SourceVpce": "vpce-0123456789abcdef0" } } }
  ]
}

ЁЯПн Why this matters in production: design long jobs as accept-then-poll from day one, send files through S3, keep internal APIs private, put WAF in front of public REST stages, and read the whole bill once a month тАФ not only the request line.

ЁЯОУ The front office is yours

One front office тЖТ three kinds of office тЖТ which desk, which kitchen тЖТ the form check and the clean answer тЖТ rehearsal and the real show тЖТ the badge check тЖТ the token bucket at the door тЖТ the notice board тЖТ the browser asks first тЖТ the name plate тЖТ the dashboard and the stopwatch тЖТ the hard edges. You didn't just learn API Gateway тАФ you can run the front office. ЁЯЫОя╕ПЁЯОУ

Next doors in the school: the API school designs what sits behind the office; the IAM school explains SigV4 and the roles behind IAM auth; the VPC school builds the private campus a private API lives in.

git checkout main
python3 apigw/demo.py     # one last run, for fun
тЖР PreviousmonitoringFinished! Take the quiz тЖТcheck what stuck

This page is the lesson's README from the lesson-12-private-waf-limits branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.