weekends

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: A dictionary containing initial user data.
10 """
11 # Edge Case: Handle None database by initializing empty users dict
12 if database is None:
13 self.users = {}
14 else:
15 self.users = database.get('users', {})
16
17 # Convert users list to dictionary for easier access
18 if isinstance(self.users, list):
19 self.users = {user['name']: user for user in self.users}
20
21 # Ensure all users have the required fields
22 for user in self.users.values():
23 if 'owes' not in user:
24 user['owes'] = {}
25 if 'owed_by' not in user:
26 user['owed_by'] = {}
27 if 'balance' not in user:
28 user['balance'] = 0.0
29
30 def _calculate_balance(self, user):
31 """
32 Calculate the balance for a user based on what they owe and are owed.
33
34 Args:
35 user: The user dictionary to calculate balance for.
36
37 Returns:
38 float: The calculated balance.
39 """
40 total_owed_by_others = sum(user['owed_by'].values())
41 total_owed_to_others = sum(user['owes'].values())
42 return round(total_owed_by_others - total_owed_to_others, 2)
43
44 def _get_user(self, name):
45 """
46 Get a user by name, creating them if they don't exist.
47
48 Args:
49 name: The name of the user to retrieve.
50
51 Returns:
52 dict: The user object.
53 """
54 # Edge Case: Create user if they don't exist
55 if name not in self.users:
56 self.users[name] = {
57 'name': name,
58 'owes': {},
59 'owed_by': {},
60 'balance': 0.0
61 }
62 return self.users[name]
63
564 def get(self, url: str, payload: str | None = None) -> str:
6 pass
7
65 """
66 Handle GET requests to the API.
67
68 Args:
69 url: The endpoint URL.
70 payload: Optional JSON payload.
71
72 Returns:
73 str: JSON response.
74 """
75 # Edge Case: Handle /users endpoint
76 if url == '/users':
77 # Edge Case: Handle payload with specific users
78 if payload is not None:
79 data = json.loads(payload)
80 user_names = data.get('users', [])
81 # Edge Case: Filter users by provided names
82 users_list = [self.users[name] for name in sorted(user_names) if name in self.users]
83 else:
84 # Edge Case: Return all users if no payload
85 users_list = [user for name, user in sorted(self.users.items())]
86
87 # Edge Case: Ensure all users have updated balances
88 for user in users_list:
89 user['balance'] = self._calculate_balance(user)
90
91 return json.dumps({'users': users_list})
92
93 # Edge Case: Handle unknown endpoints
94 return json.dumps({'error': 'Not found'})
95
896 def post(self, url: str, payload: str | None = None) -> str:
9 pass
97 """
98 Handle POST requests to the API.
99
100 Args:
101 url: The endpoint URL.
102 payload: JSON payload.
103
104 Returns:
105 str: JSON response.
106 """
107 # Edge Case: Handle missing payload
108 if payload is None:
109 return json.dumps({'error': 'Payload required'})
110
111 data = json.loads(payload)
112
113 # Edge Case: Handle /add endpoint for creating users
114 if url == '/add':
115 user_name = data.get('user')
116 # Edge Case: Handle missing user name
117 if not user_name:
118 return json.dumps({'error': 'User name required'})
119
120 # Edge Case: Handle duplicate user
121 if user_name in self.users:
122 return json.dumps({'error': 'User already exists'})
123
124 new_user = {
125 'name': user_name,
126 'owes': {},
127 'owed_by': {},
128 'balance': 0.0
129 }
130 self.users[user_name] = new_user
131 return json.dumps(new_user)
132
133 # Edge Case: Handle /iou endpoint for creating IOUs
134 elif url == '/iou':
135 lender_name = data.get('lender')
136 borrower_name = data.get('borrower')
137 amount = data.get('amount')
138
139 # Edge Case: Handle missing required fields
140 if not lender_name or not borrower_name or amount is None:
141 return json.dumps({'error': 'Lender, borrower, and amount required'})
142
143 # Edge Case: Handle invalid amount type
144 if not isinstance(amount, (int, float)):
145 return json.dumps({'error': 'Amount must be a number'})
146
147 # Edge Case: Handle negative amount
148 if amount < 0:
149 return json.dumps({'error': 'Amount must be positive'})
150
151 # Edge Case: Handle lender and borrower being the same person
152 if lender_name == borrower_name:
153 return json.dumps({'error': 'Lender and borrower cannot be the same person'})
154
155 # Get or create users
156 lender = self._get_user(lender_name)
157 borrower = self._get_user(borrower_name)
158
159 # Update lender's owed_by
160 if borrower_name in lender['owed_by']:
161 lender['owed_by'][borrower_name] += amount
162 else:
163 lender['owed_by'][borrower_name] = amount
164
165 # Update borrower's owes
166 if lender_name in borrower['owes']:
167 borrower['owes'][lender_name] += amount
168 else:
169 borrower['owes'][lender_name] = amount
170
171 # Remove entries if amount becomes 0
172 if lender['owed_by'][borrower_name] == 0:
173 del lender['owed_by'][borrower_name]
174
175 if borrower['owes'][lender_name] == 0:
176 del borrower['owes'][lender_name]
177
178 # Update balances
179 lender['balance'] = self._calculate_balance(lender)
180 borrower['balance'] = self._calculate_balance(borrower)
181
182 # Return updated users sorted by name
183 users_list = sorted([lender, borrower], key=lambda u: u['name'])
184 return json.dumps({'users': users_list})
185
186 # Edge Case: Handle unknown endpoints
187 return json.dumps({'error': 'Not found'})
188
189 # Handled Edge Cases: None database, missing payload, /users endpoint, payload with specific users,
190 # all users if no payload, unknown endpoints, missing user name, duplicate user, /iou endpoint,
191 # missing required fields, invalid amount type, negative amount, lender/borrower being same person,
192 # creating users if they don't exist, removing zero amount entries
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.