This content originally appeared on DEV Community and was authored by Clariza Look
When working with APIs and web services, curl
is often your best friend. But did you know that how you use curl can dramatically change both what you see and what you can do with the results? Today, let’s explore two completely different approaches to the same HTTP request and understand when to use each.
What is API Gateway?
Before diving into curl commands, let’s quickly understand what we’re testing. Amazon API Gateway is a fully managed service that makes it easy for developers to create, publish, maintain, monitor, and secure APIs at any scale. Think of it as the front door to your applications – it handles all the HTTP requests and routes them to your backend services.
Key Benefits:
- Traffic Management – Handle millions of concurrent API calls
- Security – Built-in authorization, authentication, and API keys
- Monitoring – CloudWatch integration for metrics and logging
- Caching – Reduce latency and backend load
- Throttling – Protect your backend from traffic spikes
Creating API Gateway with CDK Python
Here’s how you can create an API Gateway using AWS CDK with Python:
from aws_cdk import (
Stack,
aws_apigateway as apigateway,
aws_lambda as _lambda,
CfnOutput
)
from constructs import Construct
class ApiGatewayStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# Create a Lambda function (your backend)
api_lambda = _lambda.Function(
self, "ApiLambda",
runtime=_lambda.Runtime.PYTHON_3_9,
handler="lambda_function.lambda_handler",
code=_lambda.Code.from_asset("lambda"),
)
# Create the API Gateway
api = apigateway.RestApi(
self, "MyApi",
rest_api_name="My Service API",
description="This service serves my application.",
default_cors_preflight_options=apigateway.CorsOptions(
allow_origins=apigateway.Cors.ALL_ORIGINS,
allow_methods=apigateway.Cors.ALL_METHODS,
)
)
# Create API Gateway integration with Lambda
lambda_integration = apigateway.LambdaIntegration(
api_lambda,
request_templates={"application/json": '{ "statusCode": "200" }'}
)
# Add a resource and method
api.root.add_method("GET", lambda_integration)
# Add a resource path
items = api.root.add_resource("items")
items.add_method("GET", lambda_integration)
items.add_method("POST", lambda_integration)
# Output the API Gateway URL - This is what we'll test!
CfnOutput(
self, "ApiGatewayUrl",
value=api.url,
description="API Gateway endpoint URL",
export_name=f"{self.stack_name}-ApiGatewayUrl"
)
This CDK code creates:
- A Lambda function as your backend service
- An API Gateway that routes requests to the Lambda
-
Most importantly: An output called
ApiGatewayUrl
that exports the endpoint
This exported URL is exactly what our curl commands will be testing!
The Setup: Testing an API Gateway
Now that you understand what we’re working with, imagine you’re building a CI/CD pipeline that needs to verify your API Gateway is working after deployment. You have two options for testing the endpoint:
Option 1: The Silent Operator
response_code=$(curl -s -o /dev/null -w "%{http_code}" "$API_URL" --connect-timeout 10 --max-time 30 2>/dev/null || echo "000")
Option 2: The Verbose Detective
curl -v $API_URL
Same endpoint, completely different philosophies. Let’s dive into what makes each special.
The Silent Operator: Automation’s Best Friend
What It Does
The silent approach is like a ninja—it gets in, gets the job done, and gets out without making a fuss. Here’s what each part does:
curl -s # Silent mode (no progress bars or chatter)
-o /dev/null # Throw away the response body
-w "%{http_code}" # Only output the HTTP status code
--connect-timeout 10 # Give up connecting after 10 seconds
--max-time 30 # Total operation timeout of 30 seconds
2>/dev/null # Hide any error messages
|| echo "000" # If everything fails, return "000"
What You Get
404
That’s it. Just a clean, three-digit HTTP status code that tells you exactly what happened:
-
200
= Success -
404
= Not found (but API Gateway is working) -
403
= Forbidden (API Gateway working, needs auth) -
000
= Complete failure (connection issues)
Perfect For:
CI/CD Pipelines – Clean, parseable output
Health Check Scripts – Just need pass/fail
Monitoring Systems – Programmatic status checking
Automation – When you need to make decisions based on response codes
The Verbose Detective: When You Need Answers
What It Does
The verbose approach is like a chatty detective who tells you everything they’re thinking. It shows you the entire conversation between your computer and the server.
What You Get
* Trying 203.0.113.42:443...
* Connected to example.execute-api.us-east-1.amazonaws.com (203.0.113.42) port 443 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN: server accepted http/1.1
* Server certificate:
* subject: CN=*.execute-api.us-east-1.amazonaws.com
* start date: Dec 5 00:00:00 2023 GMT
* expire date: Jan 3 23:59:59 2025 GMT
* subjectAltName: host "example.execute-api.us-east-1.amazonaws.com" matched cert's "*.execute-api.us-east-1.amazonaws.com"
* issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M02
* SSL certificate verify ok.
> GET /prod/ HTTP/1.1
> Host: example.execute-api.us-east-1.amazonaws.com
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< Date: Sun, 11 Aug 2025 04:30:00 GMT
< Content-Type: application/json
< Content-Length: 36
< Connection: keep-alive
< x-amzn-RequestId: example-request-id
< x-amzn-ErrorType: UnknownOperationException
< x-amz-apigw-id: example-apigw-id
<
{"message":"Missing Authentication Token"}
* Connection #0 to host example.execute-api.us-east-1.amazonaws.com left intact
Perfect For:
Debugging SSL/TLS Issues – See certificate details and handshake
Network Troubleshooting – See DNS resolution and connection details
API Development – Understand exactly what headers are being sent/received
Security Analysis – Verify certificates and encryption protocols
Learning – Understand how HTTP really works under the hood
Real-World Example: CI/CD Pipeline
Let’s see how this plays out in a real AWS CodeBuild pipeline that tests an API Gateway after deployment:
The Pipeline Context
# In your CI/CD pipeline, after deploying your API Gateway:
# 1. Deploy CloudFormation stack with API Gateway
# 2. Deploy application to ECS
# 3. Test if API Gateway is reachable ← We are here
# 4. Continue to production (or fail if test fails)
Using the Silent Approach
# Get just the status code for automated decision making
response_code=$(curl -s -o /dev/null -w "%{http_code}" "$API_URL" --connect-timeout 10 --max-time 30 2>/dev/null || echo "000")
case $response_code in
200)
echo "✅ SUCCESS: API Gateway working perfectly"
;;
404)
echo "✅ SUCCESS: API Gateway deployed (just no root handler)"
;;
403|401)
echo "✅ SUCCESS: API Gateway deployed (needs authentication)"
;;
000)
echo "❌ FAILURE: Cannot reach API Gateway"
exit 1 # Fail the pipeline
;;
*)
echo "✅ SUCCESS: API Gateway responding (HTTP $response_code)"
;;
esac
This gives you clean, actionable results:
✅ SUCCESS: API Gateway deployed (just no root handler)
When You’d Use Verbose Instead
If your pipeline fails and you need to understand why:
# Run this manually to debug
curl -v https://your-api-gateway-url.amazonaws.com/prod/
You might discover:
- DNS resolution issues
- SSL certificate problems
- Firewall blocking connections
- Incorrect URL construction
- Authentication header requirements
The Key Takeaway
Silent curl is your automation workhorse—fast, reliable, and perfect for scripts that need to make decisions based on HTTP status codes.
Verbose curl is your debugging superhero—it tells you everything that’s happening so you can diagnose and fix issues.
Quick Decision Matrix
Use Case | Command | Why |
---|---|---|
CI/CD health checks | Silent | Clean output, fast execution, easy to parse |
Monitoring scripts | Silent | Programmatic status checking |
API debugging | Verbose | See full request/response details |
SSL troubleshooting | Verbose | Certificate and handshake details |
Network diagnostics | Verbose | DNS, connection, and timing info |
Learning HTTP | Verbose | See what’s really happening |
Pro Tips
- Combine them: Use silent in automation, verbose for debugging when things go wrong
-
Add timeouts: Always use
--connect-timeout
and--max-time
in production scripts -
Handle failures: Use
|| echo "000"
to get a predictable response on complete failures -
Parse carefully: Clean up response codes with
tr -d '\n'
if you get extra characters
The next time you reach for curl, ask yourself: “Do I need to make a decision, or do I need to understand what’s happening?” The answer will guide you to the right approach.
This content originally appeared on DEV Community and was authored by Clariza Look