harrison

Finished
1import json
2
13class RestAPI:
24 def __init__(self, database: dict | None = None):
3 pass
4
5 """
6 Initialize the REST API with a database.
7
8 Args:
9 database: A dictionary containing user data or None to initialize with an empty database.
10 """
11 if database is None:
12 self.database = {"users": []}
13 else:
14 self.database = database
15
516 def get(self, url: str, payload: str | None = None) -> str:
6 pass
7
17 """
18 Handle GET requests to the API.
19
20 Args:
21 url: The endpoint URL.
22 payload: Optional JSON payload.
23
24 Returns:
25 A JSON string response.
26
27 Raises:
28 ValueError: If the URL is not recognized.
29 """
30 if url == "/users":
31 if payload is None:
32 # Return all users
33 result = {"users": []}
34 for user in self.database["users"]:
35 user_copy = user.copy()
36 user_copy["balance"] = round(user_copy["balance"], 2)
37 result["users"].append(user_copy)
38 # Sort by name
39 result["users"].sort(key=lambda x: x["name"])
40 return json.dumps(result)
41 else:
42 # Return specific users
43 data = json.loads(payload)
44 user_names = data.get("users", [])
45
46 # Edge Case: Empty user list in payload - return all users
47 if not user_names:
48 result = {"users": []}
49 for user in self.database["users"]:
50 user_copy = user.copy()
51 user_copy["balance"] = round(user_copy["balance"], 2)
52 result["users"].append(user_copy)
53 # Sort by name
54 result["users"].sort(key=lambda x: x["name"])
55 return json.dumps(result)
56
57 result_users = []
58 for user in self.database["users"]:
59 if user["name"] in user_names:
60 user_copy = user.copy()
61 user_copy["balance"] = round(user_copy["balance"], 2)
62 result_users.append(user_copy)
63
64 # Sort by name
65 result_users.sort(key=lambda x: x["name"])
66 return json.dumps({"users": result_users})
67 else:
68 # Edge Case: Invalid URL
69 raise ValueError(f"Invalid URL: {url}")
70
71 # Handled Edge Cases: Empty user list in payload, Invalid URL
72
873 def post(self, url: str, payload: str | None = None) -> str:
9 pass
74 """
75 Handle POST requests to the API.
76
77 Args:
78 url: The endpoint URL.
79 payload: JSON payload.
80
81 Returns:
82 A JSON string response.
83
84 Raises:
85 ValueError: If the URL is not recognized or if there are issues with the payload.
86 """
87 if url == "/add":
88 if payload is None:
89 # Edge Case: Missing payload
90 raise ValueError("Payload required for /add")
91
92 data = json.loads(payload)
93 user_name = data.get("user")
94
95 # Edge Case: Missing user name in payload
96 if not user_name:
97 raise ValueError("User name required")
98
99 # Check if user already exists
100 for user in self.database["users"]:
101 if user["name"] == user_name:
102 # Edge Case: User already exists - return existing user
103 result_user = user.copy()
104 result_user["balance"] = round(result_user["balance"], 2)
105 return json.dumps(result_user)
106
107 # Create new user
108 new_user = {
109 "name": user_name,
110 "owes": {},
111 "owed_by": {},
112 "balance": 0.0
113 }
114 self.database["users"].append(new_user)
115
116 # Return the new user with rounded balance
117 result_user = new_user.copy()
118 result_user["balance"] = round(result_user["balance"], 2)
119 return json.dumps(result_user)
120
121 elif url == "/iou":
122 if payload is None:
123 # Edge Case: Missing payload
124 raise ValueError("Payload required for /iou")
125
126 data = json.loads(payload)
127 lender_name = data.get("lender")
128 borrower_name = data.get("borrower")
129 amount = data.get("amount")
130
131 # Edge Case: Missing required fields
132 if not lender_name or not borrower_name or amount is None:
133 raise ValueError("Lender, borrower, and amount are required")
134
135 # Edge Case: Lender and borrower are the same
136 if lender_name == borrower_name:
137 raise ValueError("Lender and borrower cannot be the same")
138
139 # Edge Case: Negative amount
140 if amount < 0:
141 raise ValueError("Amount must be non-negative")
142
143 # Find lender and borrower
144 lender = None
145 borrower = None
146 for user in self.database["users"]:
147 if user["name"] == lender_name:
148 lender = user
149 elif user["name"] == borrower_name:
150 borrower = user
151
152 # Edge Case: Lender or borrower not found
153 if lender is None:
154 raise ValueError(f"User {lender_name} not found")
155 if borrower is None:
156 raise ValueError(f"User {borrower_name} not found")
157
158 # Update debts - handle debt reversal properly
159 # First check if there's an existing debt in the opposite direction
160 if borrower_name in lender["owes"]:
161 # Borrower already owes lender money (reverse direction)
162 new_debt = lender["owes"][borrower_name] - amount
163 if new_debt > 0:
164 # Borrower still owes money but less
165 lender["owes"][borrower_name] = new_debt
166 borrower["owed_by"][lender_name] = new_debt
167 # Update balances
168 lender["balance"] += amount
169 borrower["balance"] -= amount
170 elif new_debt < 0:
171 # Debt direction reversed - borrower now owes lender
172 del lender["owes"][borrower_name]
173 lender["owed_by"][borrower_name] = -new_debt
174 del borrower["owed_by"][lender_name]
175 borrower["owes"][lender_name] = -new_debt
176 # Update balances
177 lender["balance"] += amount
178 borrower["balance"] -= amount
179 else:
180 # Exact repayment - remove both entries
181 del lender["owes"][borrower_name]
182 del borrower["owed_by"][lender_name]
183 # Update balances
184 lender["balance"] += amount
185 borrower["balance"] -= amount
186 elif borrower_name in lender["owed_by"]:
187 # Lender is already owed money by borrower (same direction) - accumulate
188 lender["owed_by"][borrower_name] += amount
189 borrower["owes"][lender_name] += amount
190 # Update balances
191 lender["balance"] += amount
192 borrower["balance"] -= amount
193 else:
194 # No existing debt - create new debt
195 lender["owed_by"][borrower_name] = amount
196 borrower["owes"][lender_name] = amount
197 # Update balances
198 lender["balance"] += amount
199 borrower["balance"] -= amount
200
201 # Handle zero balances by removing entries
202 if borrower_name in lender["owed_by"] and lender["owed_by"][borrower_name] == 0:
203 del lender["owed_by"][borrower_name]
204
205 if lender_name in borrower["owes"] and borrower["owes"][lender_name] == 0:
206 del borrower["owes"][lender_name]
207
208 if borrower_name in lender["owes"] and lender["owes"][borrower_name] == 0:
209 del lender["owes"][borrower_name]
210
211 if lender_name in borrower["owed_by"] and borrower["owed_by"][lender_name] == 0:
212 del borrower["owed_by"][lender_name]
213
214 # Prepare response
215 result_users = []
216 for user in [lender, borrower]:
217 user_copy = user.copy()
218 user_copy["balance"] = round(user_copy["balance"], 2)
219 result_users.append(user_copy)
220
221 # Sort by name
222 result_users.sort(key=lambda x: x["name"])
223 return json.dumps({"users": result_users})
224
225 else:
226 # Edge Case: Invalid URL
227 raise ValueError(f"Invalid URL: {url}")
228
229 # Handled Edge Cases: Missing payload, Missing user name in payload, User already exists,
230 # Missing required fields, Lender and borrower are the same, Negative amount,
231 # Lender or borrower not found, Invalid URL
Test NameStatus
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
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.