blob: dad85fa07c0b1673b0e2d044c43efb998c9b4cd1 [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""
Vercel Serverless Function for counter application
Endpoint: /api/counter
"""
import json
from http.server import BaseHTTPRequestHandler
from app import counter_app
class handler(BaseHTTPRequestHandler):
"""Vercel Serverless Function handler.
This class handles HTTP requests for the counter API endpoint.
Must inherit from BaseHTTPRequestHandler to work with Vercel's Python runtime.
"""
def do_POST(self):
"""Handle POST requests to increment counter.
Expects JSON body with 'number' field indicating count limit.
Returns serialized application state on success.
"""
try:
# Read request body
content_length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(content_length)
# Parse JSON payload
data = json.loads(body.decode("utf-8"))
# Extract parameter (equivalent to Lambda's event["body"]["number"])
count_up_to = int(data.get("number", 0))
# Validate input
if count_up_to <= 0:
self.send_error_response(400, "number must be greater than 0")
return
# Execute business logic (identical to Lambda implementation)
app = counter_app.application(count_up_to)
action, result, state = app.run(halt_after=["result"])
# Return success response with serialized state
self.send_json_response(200, state.serialize())
except json.JSONDecodeError:
self.send_error_response(400, "Invalid JSON format")
except ValueError as e:
self.send_error_response(400, f"Invalid number format: {str(e)}")
except KeyError as e:
self.send_error_response(400, f"Missing required field: {str(e)}")
except Exception as e:
# Log error for debugging
print(f"Error in counter handler: {str(e)}")
import traceback
traceback.print_exc()
self.send_error_response(500, "Internal server error")
def do_GET(self):
"""Handle GET requests - not allowed.
Returns 405 Method Not Allowed error.
"""
self.send_error_response(405, "Only POST method is allowed")
def do_PUT(self):
"""Handle PUT requests - not allowed.
Returns 405 Method Not Allowed error.
"""
self.send_error_response(405, "Only POST method is allowed")
def do_DELETE(self):
"""Handle DELETE requests - not allowed.
Returns 405 Method Not Allowed error.
"""
self.send_error_response(405, "Only POST method is allowed")
def send_json_response(self, status_code, data):
"""Send JSON response to client.
Args:
status_code: HTTP status code
data: Response data (dict, list, or any JSON-serializable object)
"""
self.send_response(status_code)
self.send_header("Content-Type", "application/json")
self.end_headers()
if isinstance(data, (dict, list)):
response_body = json.dumps(data, ensure_ascii=False)
else:
response_body = str(data)
self.wfile.write(response_body.encode("utf-8"))
def send_error_response(self, status_code, message):
"""Send error response to client.
Args:
status_code: HTTP error status code
message: Error message string to include in response body
"""
self.send_response(status_code)
self.send_header("Content-Type", "application/json")
self.end_headers()
error_body = json.dumps({"error": message})
self.wfile.write(error_body.encode("utf-8"))