GCP Cloud Functions & API Gateway

Complete Deployment Guide with Terminal Commands

Initial Setup

Basic Authentication & Project Setup
# Authenticate with GCP
gcloud auth login

# List all projects
gcloud projects list

# Set the active project
gcloud config set project PROJECT_ID
# Set environment variables for easier reference
export PROJECT_ID="your-project-id"
export REGION="us-central1"

# Verify variables are set
echo "Project ID: $PROJECT_ID"
echo "Region: $REGION"

Enable Required Services

Basic Enable GCP Services
# Enable all required services
gcloud services enable cloudfunctions.googleapis.com \
  run.googleapis.com \
  cloudbuild.googleapis.com \
  artifactregistry.googleapis.com \
  apigateway.googleapis.com \
  servicemanagement.googleapis.com \
  servicecontrol.googleapis.com \
  logging.googleapis.com \
  --project=$PROJECT_ID
Tip: You can check which services are already enabled with:
gcloud services list --enabled --project=$PROJECT_ID

IAM Roles for Developers

Intermediate Required IAM Roles
# List of roles needed for Cloud Functions and API Gateway development:
# roles/apigateway.admin
# roles/cloudfunctions.admin
# roles/cloudfunctions.invoker
# roles/iam.serviceAccountUser
# roles/serviceusage.serviceUsageViewer
# roles/serviceusage.serviceUsageConsumer
# roles/logging.viewer
# roles/monitoring.viewer
# roles/serviceusage.serviceUsageAdmin
# Grant a user the necessary roles
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="user:user@example.com" \
  --role="roles/cloudfunctions.admin"

# Repeat for other required roles
# Check IAM policy for a project
gcloud projects get-iam-policy $PROJECT_ID \
  --flatten="bindings[].members" \
  --format="table(bindings.role, bindings.members)"

Deploy Cloud Functions

Intermediate Deploy Cloud Functions
# Deploy a public HTTP function (no authentication)
gcloud functions deploy getHelloWorld \
  --gen2 \
  --runtime nodejs20 \
  --trigger-http \
  --region $REGION \
  --allow-unauthenticated \
  --source="./functions/getHelloWorld" \
  --entry-point="getHelloWorld" \
  --project="$PROJECT_ID"
# Deploy a private HTTP function (requires authentication)
gcloud functions deploy getUserData \
  --gen2 \
  --runtime nodejs20 \
  --trigger-http \
  --region $REGION \
  --no-allow-unauthenticated \
  --source="./functions/getUserData" \
  --entry-point="getUserData" \
  --project="$PROJECT_ID"
Note: After deployment, you'll get URLs like:
https://$REGION-$PROJECT_ID.cloudfunctions.net/getHelloWorld
https://$REGION-$PROJECT_ID.cloudfunctions.net/getUserData
# List all deployed functions
gcloud functions list --region=$REGION --project=$PROJECT_ID

Deploy API Gateway

Advanced API Gateway Deployment
# Set environment variables for API Gateway
export PROJECT_ID="your-project-id"
export REGION="us-central1"
export GATEWAY_NAME="user-check-gateway"
export API_NAME="user-check-api"
export API_CONFIG="user-check-config"
export API_YAML="api-gateway.yaml"
# Step 1: Create the API
gcloud api-gateway apis create "$API_NAME" --project="$PROJECT_ID"

# Step 2: Create API config (requires YAML file)
gcloud api-gateway api-configs create "$API_CONFIG" \
  --api="$API_NAME" \
  --openapi-spec="$API_YAML" \
  --project="$PROJECT_ID"

# Step 3: Create the gateway
gcloud api-gateway gateways create "$GATEWAY_NAME" \
  --api="$API_NAME" \
  --api-config="$API_CONFIG" \
  --location="$REGION" \
  --project="$PROJECT_ID"
# Get the Gateway URL
export GATEWAY_URL=$(gcloud api-gateway gateways describe "$GATEWAY_NAME" \
  --location="$REGION" --project="$PROJECT_ID" \
  --format="value(defaultHostname)")
echo "API Gateway is live at: https://$GATEWAY_URL"
# List all API gateways
gcloud api-gateway gateways list --project=$PROJECT_ID --format="table(name, location)"
# Get API Gateway details
gcloud api-gateway gateways describe $GATEWAY_NAME \
  --location=$REGION --project=$PROJECT_ID

API Keys Management

Intermediate API Keys
# Check if API key already exists
EXISTING_API_KEY_NAME=$(gcloud alpha services api-keys list \
  --filter='displayName="helloWorld API Key"' \
  --format="value(name)" | tail -n 1)

if [ -z "$EXISTING_API_KEY_NAME" ]; then
  echo "Creating new API Key..."
  # Create API Key
  gcloud alpha services api-keys create \
    --display-name="helloWorld API Key" \
    --format="value(name)"
  sleep 10
else
  echo "Reusing existing API Key: $EXISTING_API_KEY_NAME"
fi

# Get the API key value
API_KEY=$(gcloud alpha services api-keys get-key-string "$EXISTING_API_KEY_NAME" \
  --format="get(keyString)" 2>/dev/null)
echo "API Key: $API_KEY"
# Enable the gateway service for API key authentication
# First, get the managed service name
MANAGED_SERVICE=$(gcloud api-gateway apis describe "$API_NAME" \
  --project="$PROJECT_ID" --format="value(managedService)")

# Enable the service
gcloud services enable "$MANAGED_SERVICE" --project="$PROJECT_ID"
# List all API keys
gcloud alpha services api-keys list --format="table(name, displayName)"
# Restrict API key to specific gateway
gcloud alpha services api-keys update "$API_KEY_NAME" \
  --api-target=apigateway.googleapis.com \
  --allowed-urls="https://$GATEWAY_URL/*" \
  --project="$PROJECT_ID"

Testing the Deployment

Basic Test Endpoints
# Test public endpoint (no API key needed)
curl -X GET "https://$GATEWAY_URL/get-hello"

# Test secure endpoint (API key required)
curl -X GET "https://$GATEWAY_URL/get-user-data" \
  -H "x-api-key: $API_KEY"

# Test POST endpoint
curl -X POST "https://$GATEWAY_URL/post-submit-data" \
  -H "Content-Type: application/json" \
  -d '{"name": "John", "email": "john@example.com"}'
# Test Cloud Function directly
curl -X GET "https://$REGION-$PROJECT_ID.cloudfunctions.net/getHelloWorld"

# Test authenticated function with identity token
curl -X GET \
  -H "Authorization: bearer $(gcloud auth print-identity-token)" \
  "https://$REGION-$PROJECT_ID.cloudfunctions.net/getUserData"

Update & Versioning

Advanced Update API Gateway
# Create a new API config version
NEW_API_CONFIG="user-check-gateway-config-v2"

gcloud api-gateway api-configs create "$NEW_API_CONFIG" \
  --api="$API_NAME" \
  --openapi-spec="$API_YAML" \
  --project="$PROJECT_ID"

# Update the gateway to use the new config
gcloud api-gateway gateways update "$GATEWAY_NAME" \
  --api="$API_NAME" \
  --api-config="$NEW_API_CONFIG" \
  --location="$REGION" \
  --project="$PROJECT_ID"
# Rollback to previous version if needed
gcloud api-gateway gateways update "$GATEWAY_NAME" \
  --api-config="previous-config-name" \
  --location="$REGION" \
  --project="$PROJECT_ID"
# List all API configs for an API
gcloud api-gateway api-configs list --api="$API_NAME" \
  --project="$PROJECT_ID"

Delete Resources

Intermediate Cleanup Resources
# Delete Cloud Function
gcloud functions delete FUNCTION_NAME \
  --region=$REGION \
  --project=$PROJECT_ID
# Delete API Gateway and related resources
gcloud api-gateway gateways delete "$GATEWAY_NAME" \
  --location="$REGION" \
  --project="$PROJECT_ID"

gcloud api-gateway api-configs delete "$API_CONFIG" \
  --api="$API_NAME" \
  --project="$PROJECT_ID"

gcloud api-gateway apis delete "$API_NAME" \
  --project="$PROJECT_ID"
# Delete API Key
gcloud alpha services api-keys delete "API_KEY_NAME"

Troubleshooting

Advanced Common Issues & Solutions
# Check API Gateway status
gcloud api-gateway gateways describe "$GATEWAY_NAME" \
  --location="$REGION" \
  --project="$PROJECT_ID"

# Check API configs
gcloud api-gateway api-configs list \
  --api="$API_NAME" \
  --project="$PROJECT_ID"

# Check Cloud Function logs
gcloud functions logs read FUNCTION_NAME \
  --region=$REGION \
  --project=$PROJECT_ID
Common Issues:
  • API Gateway returns 404: Check if the managed service is enabled
  • Authentication errors: Verify API key is correctly configured and restricted
  • CORS issues: Configure CORS in your Cloud Function code
  • Permission errors: Verify IAM roles are properly assigned
# Check if API Gateway service is enabled
gcloud services list --enabled --filter="apigateway" \
  --project="$PROJECT_ID"

Swagger Configuration

Advanced Swagger/OpenAPI Specification
# Example Swagger configuration for API Gateway
swagger: "2.0"
info:
  title: User Check API Gateway
  version: "1.0.0"
schemes:
  - https
paths:
  /get-hello:
    get:
      summary: Public GET Endpoint
      operationId: getUserInfo
      x-google-backend:
        address: https://us-central1-learning-cloud-450805.cloudfunctions.net/getHelloWorld
        protocol: h2
      responses:
        "200":
          description: "Successful GET request"
  /get-user-data:
    get:
      summary: Secure GET Endpoint (Requires API Key)
      operationId: getUserData
      x-google-backend:
        address: https://us-central1-learning-cloud-450805.cloudfunctions.net/getUserData
        protocol: h2
      security:
        - api_key: []
      responses:
        "200":
          description: "Successful authenticated request"
securityDefinitions:
  api_key:
    type: apiKey
    name: x-api-key
    in: header
# Example Swagger configuration for API Gateway
swagger: "2.0"
info:
  title: User Check API Gateway
  version: "1.0.0"
schemes:
  - https
paths:
  /get-hello:
    get:
      summary: Public GET Endpoint
      operationId: getUserInfo
      x-google-backend:
        address: https://us-central1-learning-cloud-450805.cloudfunctions.net/getHelloWorld
        protocol: h2
      responses:
        "200":
          description: "Successful GET request"
  /get-user-data:
    get:
      summary: Secure GET Endpoint (Requires API Key)
      operationId: getUserData
      x-google-backend:
        address: https://us-central1-learning-cloud-450805.cloudfunctions.net/getUserData
        protocol: h2
      security:
        - api_key: []
      responses:
        "200":
          description: "Successful authenticated request"
securityDefinitions:
  api_key:
    type: apiKey
    name: x-api-key
    in: header
# Advanced Swagger configuration for API Gateway
swagger: "2.0"
info:
  title: Advanced User Check API Gateway
  description: Fully advanced Swagger config with API key, OAuth2, JWT, quota, and CORS
  version: "1.0.0"
host: example-api.gateway.dev
schemes:
  - https
basePath: /
consumes:
  - application/json
produces:
  - application/json
x-google-endpoints:
  - name: example-api.gateway.dev
    allowCors: true
paths:
  /get-hello:
    get:
      summary: Public GET Endpoint
      description: Simple hello endpoint without auth
      operationId: getUserInfo
      x-google-backend:
        address: https://us-central1-learning-cloud-450805.cloudfunctions.net/getHelloWorld
        protocol: h2
        deadline: 15.0
        path_translation: APPEND_PATH_TO_ADDRESS
      responses:
        "200":
          description: Successful GET request
  /get-user-data:
    get:
      summary: Secure GET Endpoint (Requires API Key)
      operationId: getUserData
      x-google-backend:
        address: https://us-central1-learning-cloud-450805.cloudfunctions.net/getUserData
        protocol: h2
        deadline: 20.0
      security:
        - api_key: []
      responses:
        "200":
          description: Successful authenticated request
        "401":
          description: Unauthorized
  /get-user-oauth:
    get:
      summary: OAuth2 Secured Endpoint
      operationId: getUserOAuth
      x-google-backend:
        address: https://us-central1-learning-cloud-450805.cloudfunctions.net/getUserOAuth
      security:
        - google_id_token: []
        - firebase: []
      responses:
        "200":
          description: Authenticated via OAuth2 / JWT
        "403":
          description: Forbidden
securityDefinitions:
  api_key:
    type: apiKey
    name: x-api-key
    in: header
  google_id_token:
    type: oauth2
    authorizationUrl: ""
    flow: implicit
    x-google-issuer: https://accounts.google.com
    x-google-jwks_uri: https://www.googleapis.com/oauth2/v3/certs
    x-google-audiences: example-api-client-id.apps.googleusercontent.com
  firebase:
    type: oauth2
    authorizationUrl: ""
    flow: implicit
    x-google-issuer: https://securetoken.google.com/my-firebase-project
    x-google-jwks_uri: https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com
    x-google-audiences: my-firebase-project
x-google-quota:
  limits:
    requests_per_minute:
      name: per-minute
      metric: serviceruntime.googleapis.com/api/request_count
      unit: 1/min/{project}
      values:
        STANDARD: 100
    requests_per_day:
      name: per-day
      metric: serviceruntime.googleapis.com/api/request_count
      unit: 1/day/{project}
      values:
        STANDARD: 5000
x-google-backend:
  deadline: 30.0
  protocol: h2
  path_translation: APPEND_PATH_TO_ADDRESS
x-google-allow:
  - GET
  - POST
  - OPTIONS
x-google-allow-credentials: true
x-google-allow-headers:
  - Authorization
  - Content-Type
  - x-api-key
x-google-allow-origin: "*"
x-google-custom-errors:
  rules:
  - error_code: 404
    error_message: Custom Not Found Message
  - error_code: 500
    error_message: Something went wrong, please try again later.
# Full Advanced Swagger configuration for API Gateway
swagger: "2.0"
info:
  title: Full Auth API Gateway
  description: Includes public, API key, JWT, OAuth2, and custom key secured endpoints
  version: "1.0.0"
host: example-api.gateway.dev
schemes:
  - https
basePath: /
consumes:
  - application/json
produces:
  - application/json
x-google-endpoints:
  - name: example-api.gateway.dev
    allowCors: true
paths:
  /auth/login:
    post:
      summary: User Login (Public)
      description: Authenticate user and return JWT token
      operationId: userLogin
      x-google-backend:
        address: https://us-central1-project.cloudfunctions.net/login
      responses:
        "200":
          description: Login successful (returns JWT)
  /auth/logout:
    post:
      summary: User Logout (Requires JWT)
      operationId: userLogout
      x-google-backend:
        address: https://us-central1-project.cloudfunctions.net/logout
      security:
        - jwt_auth: []
      responses:
        "200":
          description: Logout successful
  /auth/register:
    post:
      summary: User Registration (Public)
      operationId: userRegister
      x-google-backend:
        address: https://us-central1-project.cloudfunctions.net/register
      responses:
        "200":
          description: Registration successful
  /dashboard:
    get:
      summary: Dashboard (Requires API Key)
      operationId: getDashboard
      x-google-backend:
        address: https://us-central1-project.cloudfunctions.net/dashboard
      security:
        - api_key: []
      responses:
        "200":
          description: Dashboard data
  /dashboard/course:
    get:
      summary: Dashboard Course (Requires OAuth2 or Custom Key)
      operationId: getDashboardCourse
      x-google-backend:
        address: https://us-central1-project.cloudfunctions.net/course
      security:
        - google_oauth: []
        - custom_key: []
      responses:
        "200":
          description: Course data
securityDefinitions:
  api_key:
    type: apiKey
    name: x-api-key
    in: header
  jwt_auth:
    type: oauth2
    flow: implicit
    x-google-issuer: https://securetoken.google.com/my-project
    x-google-jwks_uri: https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com
    x-google-audiences: my-project
  google_oauth:
    type: oauth2
    flow: implicit
    x-google-issuer: https://accounts.google.com
    x-google-jwks_uri: https://www.googleapis.com/oauth2/v3/certs
    x-google-audiences: client-id.apps.googleusercontent.com
  custom_key:
    type: apiKey
    name: x-custom-key
    in: header
x-google-quota:
  limits:
    requests_per_minute:
      name: per-minute
      metric: serviceruntime.googleapis.com/api/request_count
      unit: 1/min/{project}
      values:
        STANDARD: 100
x-google-allow:
  - GET
  - POST
  - OPTIONS
x-google-allow-origin: "*"
x-google-allow-headers:
  - Authorization
  - Content-Type
  - x-api-key
  - x-custom-key
x-google-allow-credentials: true
# Advanced Swagger 2.0 Example with Multiple Security Types
swagger: "2.0"
info:
  title: Full Auth Example API Gateway
  version: "1.0.0"
schemes:
  - https
paths:
  /register:
    post:
      summary: Public Register (no auth required)
      operationId: registerUser
      x-google-backend:
        address: https://example.com/register
      responses:
        "200":
          description: "User registered successfully"

  /login:
    post:
      summary: Login with username/password to get JWT
      operationId: loginUser
      x-google-backend:
        address: https://example.com/login
      responses:
        "200":
          description: "Returns JWT token"

  /logout:
    post:
      summary: Logout (requires JWT)
      operationId: logoutUser
      security:
        - jwt_token: [] # depends on login
      x-google-backend:
        address: https://example.com/logout
      responses:
        "200":
          description: "User logged out"

  /dashboard:
    get:
      summary: Secure dashboard (JWT or OAuth2)
      operationId: getDashboard
      security:
        - jwt_token: [] # OR
        - oauth2: [read] # dashboard can be accessed via oauth2 scope
      x-google-backend:
        address: https://example.com/dashboard
      responses:
        "200":
          description: "Dashboard data"

  /dashboard/course:
    get:
      summary: Advanced - Requires BOTH JWT + Custom API Key
      operationId: getCourses
      security:
        - jwt_token: []
        - api_key: [] # multi-factor security
      x-google-backend:
        address: https://example.com/dashboard/course
      responses:
        "200":
          description: "Course list"

securityDefinitions:
  # 1. Custom API Key
  api_key:
    type: apiKey
    name: x-api-key
    in: header

  # 2. JWT (Bearer Token)
  jwt_token:
    type: apiKey
    name: Authorization
    in: header
    x-google-issuer: "https://securetoken.google.com/project-id"
    x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/jwk/project-id"
    x-google-audiences: "project-id"

  # 3. OAuth2
  oauth2:
    type: oauth2
    authorizationUrl: "https://accounts.google.com/o/oauth2/auth"
    flow: accessCode
    tokenUrl: "https://oauth2.googleapis.com/token"
    scopes:
      read: "Read access to dashboard"
      write: "Write access to dashboard"
Tip: Use the OpenAPI specification to define your API structure, security requirements, and backend connections in a standardized format.

Multiple Gateways

Advanced Managing Multiple Gateways
# Create multiple API gateways with different configurations

# Gateway 1
GATEWAY_1="gateway-1"
API_NAME_1="gateway-1-api"
API_CONFIG_1="gateway-1-config"

gcloud api-gateway apis create $API_NAME_1 --project=$PROJECT_ID
gcloud api-gateway api-configs create $API_CONFIG_1 \
  --api=$API_NAME_1 \
  --openapi-spec="gateway-1.yaml" \
  --project=$PROJECT_ID
gcloud api-gateway gateways create $GATEWAY_1 \
  --api=$API_NAME_1 \
  --api-config=$API_CONFIG_1 \
  --location=$REGION \
  --project=$PROJECT_ID

# Gateway 2
GATEWAY_2="gateway-2"
API_NAME_2="gateway-2-api"
API_CONFIG_2="gateway-2-config"

gcloud api-gateway apis create $API_NAME_2 --project=$PROJECT_ID
gcloud api-gateway api-configs create $API_CONFIG_2 \
  --api=$API_NAME_2 \
  --openapi-spec="gateway-2.yaml" \
  --project=$PROJECT_ID
gcloud api-gateway gateways create $GATEWAY_2 \
  --api=$API_NAME_2 \
  --api-config=$API_CONFIG_2 \
  --location=$REGION \
  --project=$PROJECT_ID
# Create API keys for different gateways
API_KEY_1_NAME="api-key-gateway-1"
API_KEY_1=$(gcloud alpha services api-keys create \
  --display-name="$API_KEY_1_NAME" \
  --format="value(name)" \
  --project=$PROJECT_ID)

API_KEY_2_NAME="api-key-gateway-2"
API_KEY_2=$(gcloud alpha services api-keys create \
  --display-name="$API_KEY_2_NAME" \
  --format="value(name)" \
  --project=$PROJECT_ID)

# Restrict each key to its specific gateway
GATEWAY_1_URL=$(gcloud api-gateway gateways describe $GATEWAY_1 \
  --location=$REGION --project=$PROJECT_ID \
  --format='value(defaultHostname)')

gcloud alpha services api-keys update "$API_KEY_1" \
  --api-target=apigateway.googleapis.com \
  --allowed-urls="https://$GATEWAY_1_URL/*" \
  --project=$PROJECT_ID

Pro Tips

  • Always use the --dry-run flag when available to test commands without making changes
  • Use environment variables to avoid repetition and mistakes
  • Enable detailed logging for debugging complex issues
  • Regularly clean up unused resources to avoid unnecessary costs
  • Use version control for your API Gateway configuration files
  • Test your API Gateway configuration locally before deploying