corpus

Finished
1import json
2
13class RestAPI:
24 def __init__(self, database: dict | None = None):
3 pass
4
5 """
6 Initialize the REST API with an optional database.
7
8 Args:
9 database: Optional initial database dictionary containing user data.
10 """
11 if database is None:
12 self.database = {"users": []}
13 else:
14 self.database = database
15
516 def get(self, url: str, payload: str | None = None) -> str:
6 pass
7
17 """
18 Handle GET requests to the API.
19
20 Args:
21 url: The endpoint URL.
22 payload: Optional JSON payload.
23
24 Returns:
25 JSON string response.
26
27 Raises:
28 ValueError: If the URL is not recognized.
29 """
30 if url == "/users":
31 if payload is None:
32 # Return all users
33 return json.dumps({"users": self._get_all_users()})
34 else:
35 # Return specific users
36 data = json.loads(payload)
37 user_names = data.get("users", [])
38 return json.dumps({"users": self._get_users_by_names(user_names)})
39 else:
40 raise ValueError(f"Unknown GET URL: {url}")
41
842 def post(self, url: str, payload: str | None = None) -> str:
9 pass
43 """
44 Handle POST requests to the API.
45
46 Args:
47 url: The endpoint URL.
48 payload: JSON payload.
49
50 Returns:
51 JSON string response.
52
53 Raises:
54 ValueError: If the URL is not recognized or if there are validation errors.
55 """
56 if url == "/add":
57 if payload is None:
58 raise ValueError("Payload required for /add endpoint")
59
60 data = json.loads(payload)
61 user_name = data.get("user")
62
63 # Edge Case: Missing user name in payload
64 if user_name is None:
65 raise ValueError("User name is required")
66
67 # Edge Case: User already exists
68 if self._find_user(user_name) is not None:
69 raise ValueError(f"User {user_name} already exists")
70
71 new_user = {
72 "name": user_name,
73 "owes": {},
74 "owed_by": {},
75 "balance": 0.0
76 }
77
78 self.database["users"].append(new_user)
79
80 # Edge Case: Return the new user object
81 return json.dumps(new_user)
82
83 elif url == "/iou":
84 if payload is None:
85 raise ValueError("Payload required for /iou endpoint")
86
87 data = json.loads(payload)
88 lender_name = data.get("lender")
89 borrower_name = data.get("borrower")
90 amount = data.get("amount")
91
92 # Edge Case: Missing required fields
93 if lender_name is None or borrower_name is None or amount is None:
94 raise ValueError("Lender, borrower, and amount are required")
95
96 # Edge Case: Lender and borrower are the same person
97 if lender_name == borrower_name:
98 raise ValueError("Lender and borrower cannot be the same person")
99
100 # Edge Case: Amount is negative
101 if amount < 0:
102 raise ValueError("Amount must be non-negative")
103
104 lender = self._find_user(lender_name)
105 borrower = self._find_user(borrower_name)
106
107 # Edge Case: Lender or borrower does not exist
108 if lender is None:
109 raise ValueError(f"User {lender_name} does not exist")
110 if borrower is None:
111 raise ValueError(f"User {borrower_name} does not exist")
112
113 # Update lender's owed_by
114 if borrower_name in lender["owed_by"]:
115 lender["owed_by"][borrower_name] += amount
116 else:
117 lender["owed_by"][borrower_name] = amount
118
119 # Update borrower's owes
120 if lender_name in borrower["owes"]:
121 borrower["owes"][lender_name] += amount
122 else:
123 borrower["owes"][lender_name] = amount
124
125 # Recalculate balances
126 self._recalculate_balance(lender)
127 self._recalculate_balance(borrower)
128
129 # Return updated users sorted by name
130 users = [lender, borrower]
131 users.sort(key=lambda u: u["name"])
132
133 return json.dumps({"users": users})
134
135 else:
136 raise ValueError(f"Unknown POST URL: {url}")
137
138 def _find_user(self, name: str):
139 """
140 Find a user by name in the database.
141
142 Args:
143 name: The name of the user to find.
144
145 Returns:
146 The user dictionary if found, None otherwise.
147 """
148 for user in self.database["users"]:
149 if user["name"] == name:
150 return user
151 return None
152
153 def _recalculate_balance(self, user):
154 """
155 Recalculate the balance for a user based on their owes and owed_by.
156
157 Args:
158 user: The user dictionary to update.
159 """
160 total_owed_by = sum(user["owed_by"].values())
161 total_owes = sum(user["owes"].values())
162 user["balance"] = round(total_owed_by - total_owes, 2)
163
164 def _get_all_users(self):
165 """
166 Get all users from the database, sorted by name.
167
168 Returns:
169 List of user dictionaries sorted by name.
170 """
171 return sorted(self.database["users"], key=lambda u: u["name"])
172
173 def _get_users_by_names(self, names):
174 """
175 Get specific users by their names.
176
177 Args:
178 names: List of user names to retrieve.
179
180 Returns:
181 List of user dictionaries sorted by name.
182 """
183 users = []
184 for name in names:
185 user = self._find_user(name)
186 # Edge Case: User not found - skip silently as per specification
187 if user is not None:
188 users.append(user)
189 return sorted(users, key=lambda u: u["name"])
190
191 # Handled Edge Cases: Missing user name in payload, user already exists,
192 # missing required fields, lender and borrower are the same person,
193 # amount is negative, lender or borrower does not exist,
194 # user not found when retrieving specific users
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.