sourdough

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 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 A JSON string response.
26
27 Edge Cases:
28 - Invalid URL
29 - Malformed payload
30 """
31 # Edge Case: Invalid URL
32 if url != "/users":
33 return json.dumps({"error": "Invalid URL"})
34
35 # Edge Case: Malformed payload
36 if payload is not None:
37 try:
38 payload_data = json.loads(payload)
39 except json.JSONDecodeError:
40 return json.dumps({"error": "Invalid payload"})
41
42 # Edge Case: Missing 'users' key in payload
43 if "users" not in payload_data:
44 return json.dumps({"error": "Missing 'users' key in payload"})
45
46 # Filter users based on payload
47 user_names = payload_data["users"]
48 users = [user for user in self.database["users"] if user["name"] in user_names]
49 users.sort(key=lambda x: x["name"])
50 return json.dumps({"users": users})
51 else:
52 # Return all users sorted by name
53 users = sorted(self.database["users"], key=lambda x: x["name"])
54 return json.dumps({"users": users})
55
56 # Handled Edge Cases: Invalid URL, Malformed payload, Missing 'users' key in payload
57
858 def post(self, url: str, payload: str | None = None) -> str:
9 pass
59 """
60 Handle POST requests to the API.
61
62 Args:
63 url: The endpoint URL.
64 payload: JSON payload.
65
66 Returns:
67 A JSON string response.
68
69 Edge Cases:
70 - Invalid URL
71 - Missing payload
72 - Malformed payload
73 - User already exists (for /add)
74 - Non-existent users (for /iou)
75 - Lender and borrower are the same
76 """
77 # Edge Case: Missing payload
78 if payload is None:
79 return json.dumps({"error": "Missing payload"})
80
81 # Edge Case: Malformed payload
82 try:
83 payload_data = json.loads(payload)
84 except json.JSONDecodeError:
85 return json.dumps({"error": "Invalid payload"})
86
87 if url == "/add":
88 # Edge Case: Missing 'user' key in payload
89 if "user" not in payload_data:
90 return json.dumps({"error": "Missing 'user' key in payload"})
91
92 user_name = payload_data["user"]
93
94 # Edge Case: User already exists
95 for user in self.database["users"]:
96 if user["name"] == user_name:
97 return json.dumps({"error": "User already exists"})
98
99 new_user = {
100 "name": user_name,
101 "owes": {},
102 "owed_by": {},
103 "balance": 0.0
104 }
105 self.database["users"].append(new_user)
106 return json.dumps(new_user)
107
108 elif url == "/iou":
109 # Edge Case: Missing required keys in payload
110 required_keys = ["lender", "borrower", "amount"]
111 for key in required_keys:
112 if key not in payload_data:
113 return json.dumps({"error": f"Missing '{key}' key in payload"})
114
115 lender_name = payload_data["lender"]
116 borrower_name = payload_data["borrower"]
117 amount = payload_data["amount"]
118
119 # Edge Case: Lender and borrower are the same
120 if lender_name == borrower_name:
121 return json.dumps({"error": "Lender and borrower cannot be the same"})
122
123 # Edge Case: Non-existent users
124 lender = None
125 borrower = None
126 for user in self.database["users"]:
127 if user["name"] == lender_name:
128 lender = user
129 if user["name"] == borrower_name:
130 borrower = user
131
132 if lender is None or borrower is None:
133 return json.dumps({"error": "User does not exist"})
134
135 # Update debts - netting out existing debts
136 # If lender already owes borrower, reduce that amount first
137 if borrower_name in lender["owes"]:
138 existing_debt = lender["owes"][borrower_name]
139 if existing_debt > amount:
140 # Lender still owes borrower, just reduce the amount
141 lender["owes"][borrower_name] = existing_debt - amount
142 # Update borrower's owed_by to reflect the reduced amount
143 borrower["owed_by"][lender_name] = existing_debt - amount
144 elif existing_debt == amount:
145 # Debts cancel out
146 del lender["owes"][borrower_name]
147 del borrower["owed_by"][lender_name]
148 else:
149 # New debt direction: borrower owes lender
150 del lender["owes"][borrower_name]
151 del borrower["owed_by"][lender_name]
152 new_debt = amount - existing_debt
153 lender["owed_by"][borrower_name] = new_debt
154 borrower["owes"][lender_name] = new_debt
155 elif lender_name in borrower["owes"]:
156 # Borrower already owes lender, increase that amount
157 existing_debt = borrower["owes"][lender_name]
158 borrower["owes"][lender_name] = existing_debt + amount
159 lender["owed_by"][lender_name] = existing_debt + amount
160 else:
161 # No existing debt, create new debt
162 lender["owed_by"][borrower_name] = amount
163 borrower["owes"][lender_name] = amount
164
165 # Recalculate balances
166 lender_total_owed = sum(lender["owed_by"].values())
167 lender_total_owes = sum(lender["owes"].values())
168 lender["balance"] = lender_total_owed - lender_total_owes
169
170 borrower_total_owed = sum(borrower["owed_by"].values())
171 borrower_total_owes = sum(borrower["owes"].values())
172 borrower["balance"] = borrower_total_owed - borrower_total_owes
173
174 # Return updated users sorted by name
175 updated_users = sorted([lender, borrower], key=lambda x: x["name"])
176 return json.dumps({"users": updated_users})
177 else:
178 # Edge Case: Invalid URL
179 return json.dumps({"error": "Invalid URL"})
180
181 # Handled Edge Cases: Invalid URL, Missing payload, Malformed payload, User already exists (for /add),
182 # Non-existent users (for /iou), Lender and borrower are the same, Missing required keys 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.