future

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 response string.
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 users 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: Requested user does not exist
46 if len(users) != len(user_names):
47 return json.dumps({"users": []})
48
49 return json.dumps({"users": [self._format_user(user) for user in users]})
50
51 # Edge Case: Invalid URL
52 return json.dumps({"error": "Invalid URL"})
53
854 def post(self, url: str, payload: str | None = None) -> str:
9 pass
55 """
56 Handle POST requests to the API.
57
58 Args:
59 url: The endpoint URL.
60 payload: JSON payload.
61
62 Returns:
63 JSON response string.
64 """
65 if payload is None:
66 # Edge Case: Missing payload
67 return json.dumps({"error": "Missing payload"})
68
69 try:
70 data = json.loads(payload)
71 except json.JSONDecodeError:
72 # Edge Case: Invalid JSON payload
73 return json.dumps({"error": "Invalid JSON payload"})
74
75 if url == "/add":
76 user_name = data.get("user")
77
78 # Edge Case: Missing user name
79 if not user_name:
80 return json.dumps({"error": "Missing user name"})
81
82 # Edge Case: User already exists
83 if any(user["name"] == user_name for user in self.database["users"]):
84 return json.dumps({"error": "User already exists"})
85
86 new_user = {
87 "name": user_name,
88 "owes": {},
89 "owed_by": {},
90 "balance": 0.0
91 }
92
93 self.database["users"].append(new_user)
94 return json.dumps(self._format_user(new_user))
95
96 elif url == "/iou":
97 lender_name = data.get("lender")
98 borrower_name = data.get("borrower")
99 amount = data.get("amount")
100
101 # Edge Case: Missing required fields
102 if not lender_name or not borrower_name or amount is None:
103 return json.dumps({"error": "Missing required fields"})
104
105 # Edge Case: Invalid amount type
106 if not isinstance(amount, (int, float)):
107 return json.dumps({"error": "Invalid amount"})
108
109 # Edge Case: Negative amount
110 if amount < 0:
111 return json.dumps({"error": "Amount must be positive"})
112
113 # Edge Case: Lender and borrower are the same
114 if lender_name == borrower_name:
115 return json.dumps({"error": "Lender and borrower cannot be the same"})
116
117 lender = next((user for user in self.database["users"] if user["name"] == lender_name), None)
118 borrower = next((user for user in self.database["users"] if user["name"] == borrower_name), None)
119
120 # Edge Case: Lender or borrower does not exist
121 if not lender or not borrower:
122 return json.dumps({"error": "Lender or borrower does not exist"})
123
124 # Handle debt offsetting when lender already owes borrower
125 if lender_name in borrower["owed_by"] and borrower_name in lender["owes"]:
126 # Lender owes borrower, and now lender is lending to borrower
127 existing_debt = lender["owes"][borrower_name]
128
129 if amount == existing_debt:
130 # Debts cancel out completely
131 del lender["owes"][borrower_name]
132 del borrower["owed_by"][lender_name]
133 elif amount > existing_debt:
134 # New loan is larger, so borrower now owes lender the difference
135 del lender["owes"][borrower_name]
136 del borrower["owed_by"][lender_name]
137
138 # Create new debt in opposite direction
139 lender["owed_by"][borrower_name] = amount - existing_debt
140 borrower["owes"][lender_name] = amount - existing_debt
141 else:
142 # New loan is smaller, reduce existing debt
143 lender["owes"][borrower_name] = existing_debt - amount
144 borrower["owed_by"][lender_name] = existing_debt - amount
145 else:
146 # Normal case: no existing opposite debt
147 # Update lender's owed_by
148 if borrower_name in lender["owed_by"]:
149 lender["owed_by"][borrower_name] += amount
150 else:
151 lender["owed_by"][borrower_name] = amount
152
153 # Update borrower's owes
154 if lender_name in borrower["owes"]:
155 borrower["owes"][lender_name] += amount
156 else:
157 borrower["owes"][lender_name] = amount
158
159 # Recalculate balances
160 self._recalculate_balance(lender)
161 self._recalculate_balance(borrower)
162
163 # Return updated users sorted by name
164 users = [lender, borrower]
165 users.sort(key=lambda x: x["name"])
166
167 return json.dumps({"users": [self._format_user(user) for user in users]})
168
169 # Edge Case: Invalid URL
170 return json.dumps({"error": "Invalid URL"})
171
172 def _format_user(self, user: Dict[str, Any]) -> Dict[str, Any]:
173 """
174 Format a user object for output.
175
176 Args:
177 user: The user dictionary.
178
179 Returns:
180 Formatted user dictionary.
181 """
182 # Create a copy to avoid modifying the original
183 formatted = {
184 "name": user["name"],
185 "owes": user["owes"].copy(),
186 "owed_by": user["owed_by"].copy(),
187 "balance": user["balance"]
188 }
189
190 # Remove empty entries
191 formatted["owes"] = {k: v for k, v in formatted["owes"].items() if v != 0}
192 formatted["owed_by"] = {k: v for k, v in formatted["owed_by"].items() if v != 0}
193
194 return formatted
195
196 def _recalculate_balance(self, user: Dict[str, Any]) -> None:
197 """
198 Recalculate the balance for a user.
199
200 Args:
201 user: The user dictionary.
202 """
203 total_owed_by = sum(user["owed_by"].values())
204 total_owes = sum(user["owes"].values())
205 user["balance"] = round(total_owed_by - total_owes, 2)
206
207 # Handled Edge Cases: Invalid URL, Missing payload, Invalid JSON payload, Missing user name,
208 # User already exists, Missing required fields, Invalid amount type, Negative amount,
209 # Lender and borrower are the same, Lender or borrower does not exist, Empty users list in payload,
210 # Requested user does not exist
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.