agent

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 = sorted(self.database["users"], key=lambda x: x["name"])
28 return json.dumps({"users": users})
29 else:
30 # Return specific users sorted by name
31 data = json.loads(payload)
32 user_names = data.get("users", [])
33
34 # Edge Case: Empty user list in payload
35 if not user_names:
36 return json.dumps({"users": []})
37
38 # Filter users by name
39 users = [user for user in self.database["users"] if user["name"] in user_names]
40 users = sorted(users, key=lambda x: x["name"])
41
42 # Edge Case: User in payload not found in database
43 if len(users) != len(user_names):
44 return json.dumps({"users": []})
45
46 return json.dumps({"users": users})
47
48 # Edge Case: Invalid URL
49 return json.dumps({"error": "Invalid URL"})
50
851 def post(self, url: str, payload: str | None = None) -> str:
9 pass
52 """
53 Handle POST requests to the API.
54
55 Args:
56 url: The endpoint URL.
57 payload: JSON payload.
58
59 Returns:
60 A JSON string response.
61 """
62 if payload is None:
63 # Edge Case: Missing payload
64 return json.dumps({"error": "Missing payload"})
65
66 data = json.loads(payload)
67
68 if url == "/add":
69 user_name = data.get("user")
70
71 # Edge Case: Missing user name
72 if not user_name:
73 return json.dumps({"error": "Missing user name"})
74
75 # Edge Case: User already exists - return the existing user
76 for user in self.database["users"]:
77 if user["name"] == user_name:
78 return json.dumps(user)
79
80 # Create new user
81 new_user = {
82 "name": user_name,
83 "owes": {},
84 "owed_by": {},
85 "balance": 0.0
86 }
87 self.database["users"].append(new_user)
88
89 return json.dumps(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 not lender_name or not borrower_name or amount is None:
98 return json.dumps({"error": "Missing required fields"})
99
100 # Edge Case: Invalid amount type
101 if not isinstance(amount, (int, float)):
102 return json.dumps({"error": "Invalid amount"})
103
104 # Edge Case: Negative amount
105 if amount < 0:
106 return json.dumps({"error": "Amount must be positive"})
107
108 # Edge Case: Lender and borrower are the same
109 if lender_name == borrower_name:
110 return json.dumps({"error": "Lender and borrower cannot be the same"})
111
112 # Find lender and borrower, create if they don't exist
113 lender = None
114 borrower = None
115
116 for user in self.database["users"]:
117 if user["name"] == lender_name:
118 lender = user
119 elif user["name"] == borrower_name:
120 borrower = user
121
122 # Create lender if not found
123 if lender is None:
124 lender = {
125 "name": lender_name,
126 "owes": {},
127 "owed_by": {},
128 "balance": 0.0
129 }
130 self.database["users"].append(lender)
131
132 # Create borrower if not found
133 if borrower is None:
134 borrower = {
135 "name": borrower_name,
136 "owes": {},
137 "owed_by": {},
138 "balance": 0.0
139 }
140 self.database["users"].append(borrower)
141
142 # Update owes and owed_by with proper handling of reverse transactions
143
144 # Handle the case where the borrower already owes the lender
145 # This creates a net effect where debts can cancel out or reduce
146
147 # If borrower already owes lender, reduce that amount first
148 if borrower_name in lender["owes"]:
149 existing_owes = lender["owes"][borrower_name]
150 if amount > existing_owes:
151 # New IOU is larger than existing debt, remove the debt and create new owed amount
152 del lender["owes"][borrower_name]
153 del borrower["owed_by"][lender_name]
154
155 # Add the remaining amount to owed_by
156 lender["owed_by"][borrower_name] = amount - existing_owes
157 borrower["owes"][lender_name] = amount - existing_owes
158 else:
159 # New IOU is smaller or equal to existing debt, just reduce the debt
160 lender["owes"][borrower_name] -= amount
161 borrower["owed_by"][lender_name] -= amount
162
163 # Remove entries if they become zero
164 if lender["owes"][borrower_name] == 0:
165 del lender["owes"][borrower_name]
166 del borrower["owed_by"][lender_name]
167 else:
168 # Normal case - update lender's owed_by
169 if borrower_name in lender["owed_by"]:
170 lender["owed_by"][borrower_name] += amount
171 else:
172 lender["owed_by"][borrower_name] = amount
173
174 # Update borrower's owes
175 if lender_name in borrower["owes"]:
176 borrower["owes"][lender_name] += amount
177 else:
178 borrower["owes"][lender_name] = amount
179
180 # Recalculate balances
181 lender_total_owed = sum(lender["owed_by"].values())
182 lender_total_owes = sum(lender["owes"].values())
183 lender["balance"] = lender_total_owed - lender_total_owes
184
185 borrower_total_owed = sum(borrower["owed_by"].values())
186 borrower_total_owes = sum(borrower["owes"].values())
187 borrower["balance"] = borrower_total_owed - borrower_total_owes
188
189 # Return updated users sorted by name
190 users = sorted([lender, borrower], key=lambda x: x["name"])
191 return json.dumps({"users": users})
192
193 # Edge Case: Invalid URL
194 return json.dumps({"error": "Invalid URL"})
195
196 # Handled Edge Cases: Invalid URL, Missing payload, Missing user name, User already exists, Missing required fields, Invalid amount type, Negative amount, Lender and borrower are the same, Lender or borrower not found
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.