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 representing the initial database state.
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
27 users = [self._create_user_object(user) for user in self.database["users"]]
28 return json.dumps({"users": users})
29 else:
30 # Return specific users
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 # Edge Case: Non-existent users in payload
39 users = []
40 for name in user_names:
41 user = self._find_user(name)
42 if user is not None:
43 users.append(self._create_user_object(user))
44
45 # Sort users by name
46 users.sort(key=lambda u: u["name"])
47 return json.dumps({"users": users})
48
49 # Edge Case: Invalid URL
50 return json.dumps({"error": "Invalid URL"})
51
852 def post(self, url: str, payload: str | None = None) -> str:
9 pass
53 """
54 Handle POST requests to the API.
55
56 Args:
57 url: The endpoint URL.
58 payload: JSON payload.
59
60 Returns:
61 A JSON string response.
62 """
63 if payload is None:
64 # Edge Case: Missing payload
65 return json.dumps({"error": "Payload required"})
66
67 data = json.loads(payload)
68
69 if url == "/add":
70 user_name = data.get("user")
71
72 # Edge Case: Missing user name
73 if user_name is None:
74 return json.dumps({"error": "User name required"})
75
76 # Edge Case: User already exists
77 if self._find_user(user_name) is not None:
78 return json.dumps({"error": "User already exists"})
79
80 new_user = {
81 "name": user_name,
82 "owes": {},
83 "owed_by": {}
84 }
85 self.database["users"].append(new_user)
86 return json.dumps(self._create_user_object(new_user))
87
88 elif url == "/iou":
89 lender_name = data.get("lender")
90 borrower_name = data.get("borrower")
91 amount = data.get("amount")
92
93 # Edge Case: Missing required fields
94 if lender_name is None or borrower_name is None or amount is None:
95 return json.dumps({"error": "Lender, borrower, and amount required"})
96
97 # Edge Case: Lender and borrower are the same
98 if lender_name == borrower_name:
99 return json.dumps({"error": "Lender and borrower cannot be the same"})
100
101 lender = self._find_user(lender_name)
102 borrower = self._find_user(borrower_name)
103
104 # Edge Case: Non-existent lender or borrower
105 if lender is None or borrower is None:
106 return json.dumps({"error": "Lender or borrower does not exist"})
107
108 # Edge Case: Invalid amount type or negative amount
109 if not isinstance(amount, (int, float)) or amount < 0:
110 return json.dumps({"error": "Invalid amount"})
111
112 # Handle debt consolidation between lender and borrower
113 # If lender already owes borrower money
114 if borrower_name in lender["owes"]:
115 existing_debt = lender["owes"][borrower_name]
116 if amount > existing_debt:
117 # New loan is greater than existing debt, reverse the debt direction
118 del lender["owes"][borrower_name]
119 lender["owed_by"][borrower_name] = amount - existing_debt
120
121 # Update borrower's records
122 del borrower["owed_by"][lender_name]
123 borrower["owes"][lender_name] = amount - existing_debt
124 elif amount < existing_debt:
125 # New loan is less than existing debt, reduce the debt
126 lender["owes"][borrower_name] = existing_debt - amount
127 borrower["owed_by"][lender_name] = existing_debt - amount
128 else:
129 # New loan equals existing debt, cancel out the debt
130 del lender["owes"][borrower_name]
131 del borrower["owed_by"][lender_name]
132 # If borrower already owes lender money
133 elif borrower_name in lender["owed_by"]:
134 # Add to existing amount owed by borrower
135 lender["owed_by"][borrower_name] += amount
136 borrower["owes"][lender_name] += amount
137 # If there's no existing debt relationship
138 else:
139 lender["owed_by"][borrower_name] = amount
140 borrower["owes"][lender_name] = amount
141
142 # Return updated user objects
143 updated_users = [
144 self._create_user_object(lender),
145 self._create_user_object(borrower)
146 ]
147 updated_users.sort(key=lambda u: u["name"])
148 return json.dumps({"users": updated_users})
149
150 # Edge Case: Invalid URL
151 return json.dumps({"error": "Invalid URL"})
152
153 def _find_user(self, name: str):
154 """
155 Find a user by name in the database.
156
157 Args:
158 name: The name of the user to find.
159
160 Returns:
161 The user dictionary if found, None otherwise.
162 """
163 for user in self.database["users"]:
164 if user["name"] == name:
165 return user
166 return None
167
168 def _create_user_object(self, user):
169 """
170 Create a user object with calculated balance.
171
172 Args:
173 user: The user dictionary from the database.
174
175 Returns:
176 A user object with name, owes, owed_by, and balance.
177 """
178 total_owed_by = sum(user["owed_by"].values())
179 total_owes = sum(user["owes"].values())
180 balance = round(total_owed_by - total_owes, 2)
181
182 return {
183 "name": user["name"],
184 "owes": user["owes"],
185 "owed_by": user["owed_by"],
186 "balance": balance
187 }
188
189 # Handled Edge Cases: Invalid URL, Missing payload, Missing user name, User already exists,
190 # Missing required fields, Lender and borrower are the same, Non-existent lender or borrower,
191 # Invalid amount type or negative amount, Empty user list in payload, Non-existent users in payload
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.