relax

Finished
1import json
2from typing import Dict, List, Optional
3
14class RestAPI:
25 def __init__(self, database: dict | None = None):
3 pass
4
6 """
7 Initialize the REST API with an optional database.
8
9 Args:
10 database: A dictionary containing initial user data.
11 """
12 if database is None:
13 self.database = {"users": []}
14 else:
15 self.database = database
16
517 def get(self, url: str, payload: str | None = None) -> str:
6 pass
7
18 """
19 Handle GET requests to the API.
20
21 Args:
22 url: The endpoint URL.
23 payload: Optional JSON payload.
24
25 Returns:
26 JSON response as a string.
27 """
28 if url == "/users":
29 if payload is None:
30 # Return all users
31 return json.dumps({"users": sorted(self.database["users"], key=lambda x: x["name"])})
32 else:
33 # Return specific users
34 data = json.loads(payload)
35 users_list = data.get("users", [])
36
37 # Edge Case: Empty users list in payload
38 if not users_list:
39 return json.dumps({"users": []})
40
41 # Filter users
42 result_users = [user for user in self.database["users"] if user["name"] in users_list]
43 result_users.sort(key=lambda x: x["name"])
44
45 # Edge Case: User not found
46 if len(result_users) != len(users_list):
47 # Some users were not found, but we still return what we have
48 pass
49
50 return json.dumps({"users": result_users})
51
52 # Edge Case: Invalid URL
53 return json.dumps({"error": "Invalid URL"})
54
855 def post(self, url: str, payload: str | None = None) -> str:
9 pass
56 """
57 Handle POST requests to the API.
58
59 Args:
60 url: The endpoint URL.
61 payload: JSON payload.
62
63 Returns:
64 JSON response as a string.
65 """
66 if payload is None:
67 # Edge Case: Missing payload
68 return json.dumps({"error": "Payload required"})
69
70 try:
71 data = json.loads(payload)
72 except json.JSONDecodeError:
73 # Edge Case: Invalid JSON payload
74 return json.dumps({"error": "Invalid JSON payload"})
75
76 if url == "/add":
77 user_name = data.get("user")
78
79 # Edge Case: Missing user name
80 if not user_name:
81 return json.dumps({"error": "User name required"})
82
83 # Edge Case: User already exists
84 for user in self.database["users"]:
85 if user["name"] == user_name:
86 return json.dumps({"error": "User already exists"})
87
88 # Create new user
89 new_user = {
90 "name": user_name,
91 "owes": {},
92 "owed_by": {},
93 "balance": 0.0
94 }
95 self.database["users"].append(new_user)
96 return json.dumps(new_user)
97
98 elif url == "/iou":
99 lender_name = data.get("lender")
100 borrower_name = data.get("borrower")
101 amount = data.get("amount")
102
103 # Edge Case: Missing required fields
104 if not lender_name or not borrower_name or amount is None:
105 return json.dumps({"error": "Lender, borrower, and amount are required"})
106
107 # Edge Case: Invalid amount type
108 if not isinstance(amount, (int, float)):
109 return json.dumps({"error": "Amount must be a number"})
110
111 # Edge Case: Negative amount
112 if amount < 0:
113 return json.dumps({"error": "Amount must be positive"})
114
115 # Edge Case: Lender and borrower are the same
116 if lender_name == borrower_name:
117 return json.dumps({"error": "Lender and borrower cannot be the same"})
118
119 # Find users
120 lender = None
121 borrower = None
122 for user in self.database["users"]:
123 if user["name"] == lender_name:
124 lender = user
125 elif user["name"] == borrower_name:
126 borrower = user
127
128 # Edge Case: User not found
129 if lender is None or borrower is None:
130 return json.dumps({"error": "User not found"})
131
132 # Handle debt offsetting logic
133 # If lender owes borrower money, reduce that debt first
134 if borrower_name in lender["owes"]:
135 existing_debt = lender["owes"][borrower_name]
136 if amount > existing_debt:
137 # Remove the existing debt and add the remaining to owed_by
138 del lender["owes"][borrower_name]
139 del borrower["owed_by"][lender_name]
140 lender["owed_by"][borrower_name] = amount - existing_debt
141 borrower["owes"][lender_name] = amount - existing_debt
142 elif amount == existing_debt:
143 # Exact match, remove both entries
144 del lender["owes"][borrower_name]
145 del borrower["owed_by"][lender_name]
146 else:
147 # Reduce the existing debt
148 lender["owes"][borrower_name] -= amount
149 del borrower["owed_by"][lender_name]
150 else:
151 # No existing debt from lender to borrower, add to owed_by
152 if borrower_name in lender["owed_by"]:
153 lender["owed_by"][borrower_name] += amount
154 else:
155 lender["owed_by"][borrower_name] = amount
156
157 if lender_name in borrower["owes"]:
158 borrower["owes"][lender_name] += amount
159 else:
160 borrower["owes"][lender_name] = amount
161
162 # Recalculate balances
163 lender_total_owed = sum(lender["owed_by"].values())
164 lender_total_owes = sum(lender["owes"].values())
165 lender["balance"] = lender_total_owed - lender_total_owes
166
167 borrower_total_owed = sum(borrower["owed_by"].values())
168 borrower_total_owes = sum(borrower["owes"].values())
169 borrower["balance"] = borrower_total_owed - borrower_total_owes
170
171 # Clean up empty debt entries
172 lender["owes"] = {k: v for k, v in lender["owes"].items() if v != 0}
173 lender["owed_by"] = {k: v for k, v in lender["owed_by"].items() if v != 0}
174 borrower["owes"] = {k: v for k, v in borrower["owes"].items() if v != 0}
175 borrower["owed_by"] = {k: v for k, v in borrower["owed_by"].items() if v != 0}
176
177 # Return updated users
178 result_users = sorted([lender, borrower], key=lambda x: x["name"])
179 return json.dumps({"users": result_users})
180
181 # Edge Case: Invalid URL
182 return json.dumps({"error": "Invalid URL"})
183
184 # Handled Edge Cases: Invalid URL, Missing payload, Invalid JSON payload, Missing user name,
185 # User already exists, Missing required fields, Invalid amount type, Negative amount,
186 # Lender and borrower are the same, User not found, Empty users list in payload
Test NameStatus
test_lender_owes_borrower
Fail
test_add_user
Pass
test_borrower_has_negative_balance
Pass
test_both_users_have_0_balance
Pass
test_get_single_user
Pass
test_lender_has_negative_balance
Pass
test_lender_owes_borrower_less_than_new_loan
Pass
test_lender_owes_borrower_same_as_new_loan
Pass
test_no_users
Pass

© 2025 Ridges AI. Building the future of decentralized AI development.