fishlium

Finished
1import json
2from typing import Dict, List, Optional, Any
3
14class RestAPI:
5 """
6 A RESTful API for tracking IOUs between users.
7
8 This class manages user accounts and IOU transactions in memory.
9 It supports creating users, creating IOUs between users, and retrieving user information.
10 """
11
212 def __init__(self, database: dict | None = None):
3 pass
4
13 """
14 Initialize the RestAPI with an optional database.
15
16 Args:
17 database: Optional initial database with users data
18 """
19 if database and 'users' in database:
20 # Initialize users from database
21 self.users = {}
22 for user_data in database['users']:
23 self.users[user_data['name']] = {
24 'name': user_data['name'],
25 'owes': user_data.get('owes', {}),
26 'owed_by': user_data.get('owed_by', {}),
27 'balance': user_data.get('balance', 0.0)
28 }
29 else:
30 self.users = {}
31
532 def get(self, url: str, payload: str | None = None) -> str:
6 pass
7
33 """
34 Handle GET requests to the API.
35
36 Args:
37 url: The endpoint URL
38 payload: Optional JSON payload
39
40 Returns:
41 JSON response string
42 """
43 # Edge Case: Invalid URL
44 if url != '/users':
45 return json.dumps({"error": "Invalid URL"})
46
47 # Edge Case: No users in system
48 if not self.users:
49 return json.dumps({"users": []})
50
51 if payload:
52 try:
53 data = json.loads(payload)
54 except json.JSONDecodeError:
55 # Edge Case: Invalid JSON payload
56 return json.dumps({"error": "Invalid JSON payload"})
57
58 # Edge Case: Missing 'users' key in payload
59 if 'users' not in data:
60 return json.dumps({"error": "Missing 'users' key in payload"})
61
62 requested_users = data['users']
63
64 # Edge Case: Empty users list in payload
65 if not requested_users:
66 return json.dumps({"users": []})
67
68 result = []
69 for username in requested_users:
70 # Edge Case: Requested user does not exist
71 if username in self.users:
72 result.append(self._get_user_info(username))
73
74 # Sort by name
75 result.sort(key=lambda x: x['name'])
76 return json.dumps({"users": result})
77 else:
78 # Return all users
79 result = [self._get_user_info(username) for username in self.users]
80 result.sort(key=lambda x: x['name'])
81 return json.dumps({"users": result})
82
883 def post(self, url: str, payload: str | None = None) -> str:
9 pass
84 """
85 Handle POST requests to the API.
86
87 Args:
88 url: The endpoint URL ('/add' or '/iou')
89 payload: JSON payload with request data
90
91 Returns:
92 JSON response string
93 """
94 # Edge Case: Missing payload
95 if not payload:
96 return json.dumps({"error": "Missing payload"})
97
98 try:
99 data = json.loads(payload)
100 except json.JSONDecodeError:
101 # Edge Case: Invalid JSON payload
102 return json.dumps({"error": "Invalid JSON payload"})
103
104 if url == '/add':
105 # Edge Case: Missing 'user' key
106 if 'user' not in data:
107 return json.dumps({"error": "Missing 'user' key"})
108
109 username = data['user']
110
111 # Edge Case: User already exists
112 if username in self.users:
113 return json.dumps({"error": "User already exists"})
114
115 # Create new user
116 self.users[username] = {
117 'name': username,
118 'owes': {},
119 'owed_by': {},
120 'balance': 0.0
121 }
122 return json.dumps(self._get_user_info(username))
123
124 elif url == '/iou':
125 # Edge Case: Missing required keys
126 required_keys = ['lender', 'borrower', 'amount']
127 for key in required_keys:
128 if key not in data:
129 return json.dumps({"error": f"Missing '{key}' key"})
130
131 lender = data['lender']
132 borrower = data['borrower']
133 amount = data['amount']
134
135 # Edge Case: Lender and borrower are the same
136 if lender == borrower:
137 return json.dumps({"error": "Lender and borrower cannot be the same"})
138
139 # Edge Case: Negative amount
140 if amount < 0:
141 return json.dumps({"error": "Amount cannot be negative"})
142
143 # Edge Case: Lender does not exist
144 if lender not in self.users:
145 return json.dumps({"error": "Lender does not exist"})
146
147 # Edge Case: Borrower does not exist
148 if borrower not in self.users:
149 return json.dumps({"error": "Borrower does not exist"})
150
151 # Update IOU relationships
152 # Update lender's owed_by
153 if borrower in self.users[lender]['owed_by']:
154 self.users[lender]['owed_by'][borrower] += amount
155 else:
156 self.users[lender]['owed_by'][borrower] = amount
157
158 # Update borrower's owes
159 if lender in self.users[borrower]['owes']:
160 self.users[borrower]['owes'][lender] += amount
161 else:
162 self.users[borrower]['owes'][lender] = amount
163
164 # Update balances
165 self.users[lender]['balance'] += amount
166 self.users[borrower]['balance'] -= amount
167
168 # Return updated user info
169 result = [
170 self._get_user_info(lender),
171 self._get_user_info(borrower)
172 ]
173 result.sort(key=lambda x: x['name'])
174 return json.dumps({"users": result})
175
176 else:
177 # Edge Case: Invalid URL
178 return json.dumps({"error": "Invalid URL"})
179
180 def _get_user_info(self, username: str) -> Dict[str, Any]:
181 """
182 Get a user's information in the required format.
183
184 Args:
185 username: The name of the user
186
187 Returns:
188 Dictionary with user information
189 """
190 user = self.users[username]
191 # Create a copy to avoid modifying the original
192 result = {
193 'name': user['name'],
194 'owes': {k: v for k, v in user['owes'].items() if v > 0},
195 'owed_by': {k: v for k, v in user['owed_by'].items() if v > 0},
196 'balance': round(user['balance'], 2)
197 }
198 return result
199
200 # Handled Edge Cases: Invalid URL, No users in system, Invalid JSON payload, Missing 'users' key in payload,
201 # Empty users list in payload, Requested user does not exist, Missing payload, Missing 'user' key,
202 # User already exists, Missing required keys, Lender and borrower are the same, Negative amount,
203 # Lender does not exist, Borrower does not exist, Invalid URL
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.