let it go

Finished
1import json
2from typing import Dict, List, Optional, Any
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 string response.
27 """
28 if url == "/users":
29 if payload is None:
30 # Return all users
31 return json.dumps({"users": [self._format_user(user) for user in self.database["users"]]})
32 else:
33 # Return specific users
34 data = json.loads(payload)
35 user_names = data.get("users", [])
36
37 # Edge Case: Empty user list in payload
38 if not user_names:
39 return json.dumps({"users": []})
40
41 # Filter users by name and sort
42 users = [user for user in self.database["users"] if user["name"] in user_names]
43 users.sort(key=lambda x: x["name"])
44
45 # Edge Case: Request for non-existent users
46 # Non-existent users are simply not included in the response
47
48 return json.dumps({"users": [self._format_user(user) for user in users]})
49
50 # Edge Case: Invalid URL
51 return json.dumps({"error": "Invalid URL"})
52
853 def post(self, url: str, payload: str | None = None) -> str:
9 pass
54 """
55 Handle POST requests to the API.
56
57 Args:
58 url: The endpoint URL.
59 payload: JSON payload.
60
61 Returns:
62 JSON string response.
63 """
64 if payload is None:
65 # Edge Case: Missing payload
66 return json.dumps({"error": "Payload required"})
67
68 try:
69 data = json.loads(payload)
70 except json.JSONDecodeError:
71 # Edge Case: Invalid JSON payload
72 return json.dumps({"error": "Invalid JSON payload"})
73
74 if url == "/add":
75 user_name = data.get("user")
76
77 # Edge Case: Missing user name
78 if user_name is None:
79 return json.dumps({"error": "User name required"})
80
81 # Edge Case: User already exists - return existing user
82 existing_user = next((user for user in self.database["users"] if user["name"] == user_name), None)
83 if existing_user:
84 return json.dumps(self._format_user(existing_user))
85
86 # Create new user
87 new_user = {
88 "name": user_name,
89 "owes": {},
90 "owed_by": {},
91 "balance": 0.0
92 }
93 self.database["users"].append(new_user)
94
95 return json.dumps(self._format_user(new_user))
96
97 elif url == "/iou":
98 lender_name = data.get("lender")
99 borrower_name = data.get("borrower")
100 amount = data.get("amount")
101
102 # Edge Case: Missing required fields
103 if lender_name is None or borrower_name is None or amount is None:
104 return json.dumps({"error": "Lender, borrower, and amount required"})
105
106 # Edge Case: Invalid amount type
107 if not isinstance(amount, (int, float)):
108 return json.dumps({"error": "Amount must be a number"})
109
110 # Edge Case: Negative amount
111 if amount < 0:
112 return json.dumps({"error": "Amount must be positive"})
113
114 # Find users
115 lender = next((user for user in self.database["users"] if user["name"] == lender_name), None)
116 borrower = next((user for user in self.database["users"] if user["name"] == borrower_name), None)
117
118 # Edge Case: Lender and borrower are the same - return user once
119 if lender_name == borrower_name:
120 # Return updated user
121 return json.dumps({"users": [self._format_user(lender)]})
122
123 # Edge Case: Lender or borrower does not exist
124 if lender is None or borrower is None:
125 return json.dumps({"error": "Lender or borrower does not exist"})
126
127 # Edge Case: Lender or borrower does not exist
128 if lender is None or borrower is None:
129 return json.dumps({"error": "Lender or borrower does not exist"})
130
131 # Update owes/owed_by relationships
132 # Only update if amount is greater than zero
133 if amount > 0:
134 # Update lender's owed_by
135 if borrower_name in lender["owed_by"]:
136 lender["owed_by"][borrower_name] += amount
137 else:
138 lender["owed_by"][borrower_name] = amount
139
140 # Update borrower's owes
141 if lender_name in borrower["owes"]:
142 borrower["owes"][lender_name] += amount
143 else:
144 borrower["owes"][lender_name] = amount
145
146 # Recalculate balances
147 self._recalculate_balance(lender)
148 self._recalculate_balance(borrower)
149
150 # Return updated users sorted by name
151 users = [lender, borrower]
152 users.sort(key=lambda x: x["name"])
153
154 return json.dumps({"users": [self._format_user(user) for user in users]})
155
156 # Edge Case: Invalid URL
157 return json.dumps({"error": "Invalid URL"})
158
159 def _format_user(self, user: Dict[str, Any]) -> Dict[str, Any]:
160 """
161 Format a user object for output, calculating the balance.
162
163 Args:
164 user: The user dictionary.
165
166 Returns:
167 Formatted user dictionary.
168 """
169 # Calculate balance as (total owed by others) - (total owed to others)
170 total_owed_by = sum(user["owed_by"].values())
171 total_owes = sum(user["owes"].values())
172 balance = float(round(total_owed_by - total_owes, 2))
173
174 return {
175 "name": user["name"],
176 "owes": user["owes"],
177 "owed_by": user["owed_by"],
178 "balance": balance
179 }
180
181 def _recalculate_balance(self, user: Dict[str, Any]) -> None:
182 """
183 Recalculate a user's balance based on their owes and owed_by.
184
185 Args:
186 user: The user dictionary to update.
187 """
188 total_owed_by = sum(user["owed_by"].values())
189 total_owes = sum(user["owes"].values())
190 user["balance"] = float(round(total_owed_by - total_owes, 2))
191
192 # Handled Edge Cases:
193 # - Invalid URL in GET and POST
194 # - Missing payload in POST
195 # - Invalid JSON payload
196 # - Empty user list in GET /users
197 # - Request for non-existent users in GET /users
198 # - Missing user name in POST /add
199 # - User already exists in POST /add
200 # - Missing required fields in POST /iou
201 # - Invalid amount type in POST /iou
202 # - Negative amount in POST /iou
203 # - Lender and borrower are the same in POST /iou
204 # - Lender or borrower does not exist in POST /iou
Test NameStatus
test_lender_owes_borrower
Fail
test_lender_owes_borrower_less_than_new_loan
Fail
test_lender_owes_borrower_same_as_new_loan
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_no_users
Pass

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