You need to implement a simplified REST API handler that processes HTTP requests for managing user resources. Your system should support standard CRUD operations through appropriate HTTP methods and maintain an in-memory data store.
The API handler receives a sequence of operations, where each operation consists of an HTTP method, a path, and optional request data. You must process these operations in order and return the result of the final operation.
Your implementation should handle the following endpoints:
Example 1:
Input: [ ("POST", "/users", {"name": "Alice", "email": "alice@example.com"}), ("GET", "/users/1", {}) ] Output: {"id": 1, "name": "Alice", "email": "alice@example.com"} Explanation: First operation creates a user with ID 1. Second operation retrieves that user, which is returned as the final result.
Example 2:
Input: [ ("POST", "/users", {"name": "Bob", "email": "bob@test.com"}), ("PUT", "/users/1", {"email": "bob.updated@test.com"}), ("GET", "/users/1", {}) ] Output: {"id": 1, "name": "Bob", "email": "bob.updated@test.com"} Explanation: Create user, update email field, then retrieve the updated user.
Example 3:
Input: [ ("POST", "/users", {"name": "Alice", "email": "alice@test.com"}), ("POST", "/users", {"name": "Bob", "email": "bob@test.com"}), ("GET", "/users", {}) ] Output: [{"id": 1, "name": "Alice", "email": "alice@test.com"}, {"id": 2, "name": "Bob", "email": "bob@test.com"}] Explanation: Create two users, then retrieve all users as an array.
Hint 1: Data Structure Choice Use a dictionary to store users with their IDs as keys. This provides O(1) access time for lookups, updates, and deletions. Keep track of the next available ID separately.
Hint 2: Parsing the Path For paths like "/users/1", you need to extract the ID portion. Consider splitting the path by "/" and checking the length to determine if it's a collection endpoint or a specific resource endpoint.
Hint 3: Handling Different HTTP Methods Create separate helper functions for each HTTP method (POST, GET, PUT, DELETE). This makes your code more maintainable and easier to test. Each method should handle both the logic and the appropriate return value.
Full Solution `` Explanation:
The solution implements a simple REST API handler with the following components:
Data Storage: We use a dictionary
usersto store user objects with their IDs as keys, providing O(1) access time. A counternext_idtracks the next available ID.Request Parsing: For each operation, we parse the path to determine whether it's targeting the collection ("/users") or a specific resource ("/users/{id}").
HTTP Method Handlers:
- POST /users: Creates a new user by combining the auto-generated ID with the provided data, stores it, and increments the ID counter.
- GET /users: Returns all users as a list by calling
list(users.values()).- GET /users/{id}: Looks up a specific user by ID using
dict.get(), returning None if not found.- PUT /users/{id}: Updates an existing user by merging new data with existing data using
dict.update().- DELETE /users/{id}: Removes a user from storage if it exists.
Return Value: After processing each operation, we store its result and return the result of the final operation.
Time Complexity: O(n × m) where n is the number of operations and m is the average number of users (for GET /users). Individual operations on specific users are O(1).
Space Complexity: O(u) where u is the number of users stored in the system.
This implementation provides a clean, maintainable foundation for a REST API system that can be easily extended with additional endpoints or validation logic.
import json
def process_api_requests(operations):
"""
Process a sequence of REST API operations and return the result of the last operation.
Args:
operations: List of tuples (method, path, data)
Returns:
Result of the last operation as a JSON-serializable object
"""
# In-memory storage for users
users = {}
next_id = 1
result = None
for method, path, data in operations:
# Parse the path to determine the endpoint
path_parts = path.split('/')
if method == "POST" and path == "/users":
# Create a new user
user = {"id": next_id, **data}
users[next_id] = user
result = user
next_id += 1
elif method == "GET" and path == "/users":
# Get all users
result = list(users.values())
elif method == "GET" and len(path_parts) == 3 and path_parts[1] == "users":
# Get a specific user by ID
user_id = int(path_parts[2])
result = users.get(user_id, None)
elif method == "PUT" and len(path_parts) == 3 and path_parts[1] == "users":
# Update a specific user by ID
user_id = int(path_parts[2])
if user_id in users:
# Merge the new data with existing user data
users[user_id].update(data)
result = users[user_id]
else:
result = None
elif method == "DELETE" and len(path_parts) == 3 and path_parts[1] == "users":
# Delete a specific user by ID
user_id = int(path_parts[2])
if user_id in users:
del users[user_id]
result = True
else:
result = False
return result