A.2.1

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.
10 """
11 self.database = database if database is not None else {"users": []}
12
513 def get(self, url: str, payload: str | None = None) -> str:
6 pass
7
14 """
15 Handle GET requests to the API.
16
17 Args:
18 url: The endpoint URL.
19 payload: Optional JSON payload.
20
21 Returns:
22 A JSON string response.
23 """
24 if url == "/users":
25 if payload is None:
26 # Return all users sorted by name
27 users = [self._create_user_object(user) for user in self.database["users"]]
28 users.sort(key=lambda u: u["name"])
29 return json.dumps({"users": users})
30 else:
31 # Return specific users
32 data = json.loads(payload)
33 user_names = data.get("users", [])
34
35 # Edge Case: Empty user list in payload
36 if not user_names:
37 return json.dumps({"users": []})
38
39 # Edge Case: Non-existent users in payload
40 users = []
41 for name in user_names:
42 user = self._find_user(name)
43 if user is not None:
44 users.append(self._create_user_object(user))
45
46 # Sort users by name
47 users.sort(key=lambda u: u["name"])
48 return json.dumps({"users": 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 A JSON string response.
63 """
64 if payload is None:
65 # Edge Case: Missing payload
66 return json.dumps({"error": "Payload required"})
67
68 data = json.loads(payload)
69
70 if url == "/add":
71 user_name = data.get("user")
72
73 # Edge Case: Missing user name
74 if user_name is None:
75 return json.dumps({"error": "User name required"})
76
77 # Edge Case: User already exists
78 if self._find_user(user_name) is not None:
79 return json.dumps({"error": "User already exists"})
80
81 # Create new user
82 new_user = {
83 "name": user_name,
84 "owes": {},
85 "owed_by": {},
86 "balance": 0.0
87 }
88 self.database["users"].append(new_user)
89 return json.dumps(self._create_user_object(new_user))
90
91 elif url == "/iou":
92 lender_name = data.get("lender")
93 borrower_name = data.get("borrower")
94 amount = data.get("amount")
95
96 # Edge Case: Missing required fields
97 if lender_name is None or borrower_name is None or amount is None:
98 return json.dumps({"error": "Lender, borrower, and amount required"})
99
100 # Edge Case: Lender and borrower are the same
101 if lender_name == borrower_name:
102 return json.dumps({"error": "Lender and borrower cannot be the same"})
103
104 lender = self._find_user(lender_name)
105 borrower = self._find_user(borrower_name)
106
107 # Edge Case: Non-existent lender or borrower
108 if lender is None or borrower is None:
109 return json.dumps({"error": "Lender or borrower does not exist"})
110
111 # Update the IOU transaction by properly netting debts
112 # Calculate the net amount that borrower owes lender after this transaction
113 # Net debt = (borrower's existing debt to lender) + amount - (lender's existing debt to borrower)
114
115 # Get current amounts
116 lender_owes_borrower = lender["owes"].get(borrower_name, 0.0)
117 borrower_owes_lender = borrower["owes"].get(lender_name, 0.0)
118
119 # Calculate net debt (positive means borrower owes lender, negative means lender owes borrower)
120 net_debt = (borrower_owes_lender + amount) - lender_owes_borrower
121
122 # Remove all existing debt entries between these users
123 # Clean up lender's records
124 if borrower_name in lender["owes"]:
125 del lender["owes"][borrower_name]
126 if borrower_name in lender["owed_by"]:
127 del lender["owed_by"][borrower_name]
128
129 # Clean up borrower's records
130 if lender_name in borrower["owes"]:
131 del borrower["owes"][lender_name]
132 if lender_name in borrower["owed_by"]:
133 del borrower["owed_by"][lender_name]
134
135 # Set new netted amounts
136 if net_debt > 0:
137 # Borrower owes lender
138 lender["owed_by"][borrower_name] = net_debt
139 borrower["owes"][lender_name] = net_debt
140 elif net_debt < 0:
141 # Lender owes borrower
142 lender["owes"][borrower_name] = -net_debt
143 borrower["owed_by"][lender_name] = -net_debt
144 # If net_debt is 0, no entries are needed (no debt between them)
145
146 # Recalculate balances for both users
147 lender_total_owed = sum(lender["owes"].values())
148 lender_total_owed_by = sum(lender["owed_by"].values())
149 lender["balance"] = lender_total_owed_by - lender_total_owed
150
151 borrower_total_owed = sum(borrower["owes"].values())
152 borrower_total_owed_by = sum(borrower["owed_by"].values())
153 borrower["balance"] = borrower_total_owed_by - borrower_total_owed
154
155 # Return updated users
156 users = [self._create_user_object(lender), self._create_user_object(borrower)]
157 users.sort(key=lambda u: u["name"])
158 return json.dumps({"users": users})
159
160 # Edge Case: Invalid URL
161 return json.dumps({"error": "Invalid URL"})
162
163 def _find_user(self, name: str):
164 """
165 Find a user by name in the database.
166
167 Args:
168 name: The name of the user to find.
169
170 Returns:
171 The user object if found, None otherwise.
172 """
173 for user in self.database["users"]:
174 if user["name"] == name:
175 return user
176 return None
177
178 def _create_user_object(self, user):
179 """
180 Create a user object for API response.
181
182 Args:
183 user: The user data from the database.
184
185 Returns:
186 A user object for API response.
187 """
188 # Calculate balance from owes and owed_by
189 total_owed = sum(user["owes"].values())
190 total_owed_by = sum(user["owed_by"].values())
191 balance = float(total_owed_by - total_owed)
192
193 return {
194 "name": user["name"],
195 "owes": user["owes"],
196 "owed_by": user["owed_by"],
197 "balance": balance
198 }
199 # Handled Edge Cases: Invalid URL, Missing payload, Missing user name, User already exists, Missing required fields, Lender and borrower are the same, Non-existent lender or borrower
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.