Skip to content

Commit b8a3619

Browse files
committed
Add centralized API endpoints configuration and refactor API calls
- Introduced a new `endpoints.ts` file to centralize all API endpoint paths for better maintainability and type safety. - Updated various components and services to utilize the new centralized endpoints, enhancing consistency across the codebase. - Created a comprehensive `API_ENDPOINTS_REFACTORING.md` guide detailing the refactoring process and usage patterns for the new endpoints. - Removed hardcoded URLs in favor of the centralized configuration, improving code readability and reducing the risk of errors.
1 parent 8ca20aa commit b8a3619

File tree

16 files changed

+420
-78
lines changed

16 files changed

+420
-78
lines changed
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
# API Endpoints Refactoring Guide
2+
3+
This document explains how to refactor API URLs to use the centralized endpoints configuration.
4+
5+
## Overview
6+
7+
All API endpoints are now centralized in `src/api/endpoints.ts`. This makes it:
8+
- **Maintainable**: Change URLs in one place
9+
- **Type-safe**: TypeScript ensures correct usage
10+
- **Discoverable**: All endpoints are documented in one file
11+
- **Consistent**: No more typos or inconsistent paths
12+
13+
## Usage Patterns
14+
15+
### 1. Simple Static Endpoints
16+
17+
**Before:**
18+
```typescript
19+
const url = `/api/v1/api/feedback/`;
20+
await publicApi.post(url, data);
21+
```
22+
23+
**After:**
24+
```typescript
25+
import { V1_API_ENDPOINTS } from "../api/endpoints";
26+
27+
await publicApi.post(V1_API_ENDPOINTS.FEEDBACK, data);
28+
```
29+
30+
### 2. Dynamic Endpoints with Parameters
31+
32+
**Before:**
33+
```typescript
34+
const url = `/api/v1/api/uploadFile/${guid}`;
35+
await fetch(url);
36+
```
37+
38+
**After:**
39+
```typescript
40+
import { endpoints } from "../api/endpoints";
41+
42+
const url = endpoints.uploadFile(guid);
43+
await fetch(url);
44+
```
45+
46+
### 3. Endpoints with Query Parameters
47+
48+
**Before:**
49+
```typescript
50+
const endpoint = guid
51+
? `/api/v1/api/embeddings/ask_embeddings?guid=${guid}`
52+
: '/api/v1/api/embeddings/ask_embeddings';
53+
```
54+
55+
**After:**
56+
```typescript
57+
import { endpoints } from "../api/endpoints";
58+
59+
const endpoint = endpoints.embeddingsAsk(guid);
60+
```
61+
62+
## Available Endpoint Groups
63+
64+
### Authentication Endpoints
65+
```typescript
66+
import { AUTH_ENDPOINTS } from "../api/endpoints";
67+
68+
AUTH_ENDPOINTS.JWT_VERIFY
69+
AUTH_ENDPOINTS.JWT_CREATE
70+
AUTH_ENDPOINTS.USER_ME
71+
AUTH_ENDPOINTS.RESET_PASSWORD
72+
AUTH_ENDPOINTS.RESET_PASSWORD_CONFIRM
73+
```
74+
75+
### V1 API Endpoints
76+
```typescript
77+
import { V1_API_ENDPOINTS } from "../api/endpoints";
78+
79+
V1_API_ENDPOINTS.FEEDBACK
80+
V1_API_ENDPOINTS.UPLOAD_FILE
81+
V1_API_ENDPOINTS.GET_FULL_LIST_MED
82+
V1_API_ENDPOINTS.MED_RULES
83+
// ... and more
84+
```
85+
86+
### Conversation Endpoints
87+
```typescript
88+
import { CONVERSATION_ENDPOINTS } from "../api/endpoints";
89+
90+
CONVERSATION_ENDPOINTS.CONVERSATIONS
91+
CONVERSATION_ENDPOINTS.EXTRACT_TEXT
92+
```
93+
94+
### AI Settings Endpoints
95+
```typescript
96+
import { AI_SETTINGS_ENDPOINTS } from "../api/endpoints";
97+
98+
AI_SETTINGS_ENDPOINTS.SETTINGS
99+
```
100+
101+
### Helper Functions
102+
```typescript
103+
import { endpoints } from "../api/endpoints";
104+
105+
endpoints.embeddingsAsk(guid?)
106+
endpoints.embeddingsAskStream(guid?)
107+
endpoints.ruleExtraction(guid)
108+
endpoints.conversation(id)
109+
endpoints.continueConversation(id)
110+
endpoints.updateConversationTitle(id)
111+
endpoints.uploadFile(guid)
112+
endpoints.editMetadata(guid)
113+
```
114+
115+
## Files to Refactor
116+
117+
The following files still need to be updated to use the centralized endpoints:
118+
119+
1. `src/pages/Settings/SettingsManager.tsx` - Use `AI_SETTINGS_ENDPOINTS.SETTINGS`
120+
2. `src/pages/RulesManager/RulesManager.tsx` - Use `V1_API_ENDPOINTS.MED_RULES`
121+
3. `src/pages/PatientManager/NewPatientForm.tsx` - Use `V1_API_ENDPOINTS.GET_MED_RECOMMEND`
122+
4. `src/pages/ManageMeds/ManageMeds.tsx` - Use `V1_API_ENDPOINTS.*` for all medication endpoints
123+
5. `src/pages/ListMeds/useMedications.tsx` - Use `V1_API_ENDPOINTS.GET_FULL_LIST_MED`
124+
6. `src/pages/Layout/Layout_V2_Sidebar.tsx` - Use `V1_API_ENDPOINTS.UPLOAD_FILE`
125+
7. `src/pages/Files/ListOfFiles.tsx` - Use `V1_API_ENDPOINTS.UPLOAD_FILE`
126+
8. `src/pages/DocumentManager/UploadFile.tsx` - Use `V1_API_ENDPOINTS.UPLOAD_FILE`
127+
9. `src/pages/Files/FileRow.tsx` - Use `endpoints.editMetadata(guid)`
128+
10. `src/pages/DrugSummary/PDFViewer.tsx` - Use `endpoints.uploadFile(guid)`
129+
11. `src/pages/PatientManager/PatientSummary.tsx` - Use `endpoints.uploadFile(guid)`
130+
131+
## Example Refactoring
132+
133+
### Example 1: SettingsManager.tsx
134+
135+
**Before:**
136+
```typescript
137+
const baseUrl = import.meta.env.VITE_API_BASE_URL || "http://localhost:8000";
138+
const url = `${baseUrl}/ai_settings/settings/`;
139+
```
140+
141+
**After:**
142+
```typescript
143+
import { AI_SETTINGS_ENDPOINTS } from "../../api/endpoints";
144+
145+
const url = AI_SETTINGS_ENDPOINTS.SETTINGS;
146+
```
147+
148+
### Example 2: FileRow.tsx
149+
150+
**Before:**
151+
```typescript
152+
const baseUrl = import.meta.env.VITE_API_BASE_URL as string;
153+
await fetch(`${baseUrl}/v1/api/editmetadata/${file.guid}`, {
154+
```
155+
156+
**After:**
157+
```typescript
158+
import { endpoints } from "../../api/endpoints";
159+
160+
await fetch(endpoints.editMetadata(file.guid), {
161+
```
162+
163+
### Example 3: ManageMeds.tsx
164+
165+
**Before:**
166+
```typescript
167+
const baseUrl = import.meta.env.VITE_API_BASE_URL;
168+
const url = `${baseUrl}/v1/api/get_full_list_med`;
169+
await adminApi.delete(`${baseUrl}/v1/api/delete_med`, { data: { name } });
170+
await adminApi.post(`${baseUrl}/v1/api/add_medication`, { ... });
171+
```
172+
173+
**After:**
174+
```typescript
175+
import { V1_API_ENDPOINTS } from "../../api/endpoints";
176+
177+
const url = V1_API_ENDPOINTS.GET_FULL_LIST_MED;
178+
await adminApi.delete(V1_API_ENDPOINTS.DELETE_MED, { data: { name } });
179+
await adminApi.post(V1_API_ENDPOINTS.ADD_MEDICATION, { ... });
180+
```
181+
182+
## Benefits
183+
184+
1. **Single Source of Truth**: All endpoints defined in one place
185+
2. **Easy Updates**: Change an endpoint once, updates everywhere
186+
3. **Type Safety**: TypeScript catches typos and incorrect usage
187+
4. **Better IDE Support**: Autocomplete for all available endpoints
188+
5. **Documentation**: Endpoints are self-documenting with clear names
189+
6. **Refactoring Safety**: Rename endpoints safely across the codebase
190+
191+
## Adding New Endpoints
192+
193+
When adding a new endpoint:
194+
195+
1. Add it to the appropriate group in `src/api/endpoints.ts`
196+
2. If it needs dynamic parameters, add a helper function to `endpoints` object
197+
3. Use the new endpoint in your code
198+
4. Update this guide if needed
199+
200+
Example:
201+
```typescript
202+
// In endpoints.ts
203+
export const V1_API_ENDPOINTS = {
204+
// ... existing endpoints
205+
NEW_ENDPOINT: `${API_BASE}/v1/api/new_endpoint`,
206+
} as const;
207+
208+
// If it needs parameters:
209+
export const endpoints = {
210+
// ... existing helpers
211+
newEndpoint: (id: string, param: string): string => {
212+
return `${V1_API_ENDPOINTS.NEW_ENDPOINT}/${id}?param=${param}`;
213+
},
214+
} as const;
215+
```
216+

frontend/src/api/apiClient.ts

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import axios from "axios";
22
import { FormValues } from "../pages/Feedback/FeedbackForm";
33
import { Conversation } from "../components/Header/Chat";
4-
const baseURL = import.meta.env.VITE_API_BASE_URL;
4+
import {
5+
V1_API_ENDPOINTS,
6+
CONVERSATION_ENDPOINTS,
7+
endpoints,
8+
} from "./endpoints";
9+
10+
// Use empty string for relative URLs - all API calls will be relative to current domain
11+
const baseURL = "";
512

613
export const publicApi = axios.create({ baseURL });
714

@@ -31,7 +38,7 @@ const handleSubmitFeedback = async (
3138
message: FormValues["message"],
3239
) => {
3340
try {
34-
const response = await publicApi.post(`/v1/api/feedback/`, {
41+
const response = await publicApi.post(V1_API_ENDPOINTS.FEEDBACK, {
3542
feedbacktype: feedbackType,
3643
name,
3744
email,
@@ -49,7 +56,7 @@ const handleSendDrugSummary = async (
4956
guid: string,
5057
) => {
5158
try {
52-
const endpoint = guid ? `/v1/api/embeddings/ask_embeddings?guid=${guid}` : '/v1/api/embeddings/ask_embeddings';
59+
const endpoint = endpoints.embeddingsAsk(guid);
5360
const response = await adminApi.post(endpoint, {
5461
message,
5562
});
@@ -63,7 +70,7 @@ const handleSendDrugSummary = async (
6370

6471
const handleRuleExtraction = async (guid: string) => {
6572
try {
66-
const response = await adminApi.get(`/v1/api/rule_extraction_openai?guid=${guid}`);
73+
const response = await adminApi.get(endpoints.ruleExtraction(guid));
6774
// console.log("Rule extraction response:", JSON.stringify(response.data, null, 2));
6875
return response.data;
6976
} catch (error) {
@@ -77,7 +84,7 @@ const fetchRiskDataWithSources = async (
7784
source: "include" | "diagnosis" | "diagnosis_depressed" = "include",
7885
) => {
7986
try {
80-
const response = await publicApi.post(`/v1/api/riskWithSources`, {
87+
const response = await publicApi.post(V1_API_ENDPOINTS.RISK_WITH_SOURCES, {
8188
drug: medication,
8289
source: source,
8390
});
@@ -101,12 +108,10 @@ const handleSendDrugSummaryStream = async (
101108
callbacks: StreamCallbacks,
102109
): Promise<void> => {
103110
const token = localStorage.getItem("access");
104-
const endpoint = `/v1/api/embeddings/ask_embeddings?stream=true${
105-
guid ? `&guid=${guid}` : ""
106-
}`;
111+
const endpoint = endpoints.embeddingsAskStream(guid);
107112

108113
try {
109-
const response = await fetch(baseURL + endpoint, {
114+
const response = await fetch(endpoint, {
110115
method: "POST",
111116
headers: {
112117
"Content-Type": "application/json",
@@ -206,7 +211,7 @@ const handleSendDrugSummaryStreamLegacy = async (
206211

207212
const fetchConversations = async (): Promise<Conversation[]> => {
208213
try {
209-
const response = await publicApi.get(`/chatgpt/conversations/`);
214+
const response = await publicApi.get(CONVERSATION_ENDPOINTS.CONVERSATIONS);
210215
return response.data;
211216
} catch (error) {
212217
console.error("Error(s) during getConversations: ", error);
@@ -216,7 +221,7 @@ const fetchConversations = async (): Promise<Conversation[]> => {
216221

217222
const fetchConversation = async (id: string): Promise<Conversation> => {
218223
try {
219-
const response = await publicApi.get(`/chatgpt/conversations/${id}/`);
224+
const response = await publicApi.get(endpoints.conversation(id));
220225
return response.data;
221226
} catch (error) {
222227
console.error("Error(s) during getConversation: ", error);
@@ -226,7 +231,7 @@ const fetchConversation = async (id: string): Promise<Conversation> => {
226231

227232
const newConversation = async (): Promise<Conversation> => {
228233
try {
229-
const response = await adminApi.post(`/chatgpt/conversations/`, {
234+
const response = await adminApi.post(CONVERSATION_ENDPOINTS.CONVERSATIONS, {
230235
messages: [],
231236
});
232237
return response.data;
@@ -243,7 +248,7 @@ const continueConversation = async (
243248
): Promise<{ response: string; title: Conversation["title"] }> => {
244249
try {
245250
const response = await adminApi.post(
246-
`/chatgpt/conversations/${id}/continue_conversation/`,
251+
endpoints.continueConversation(id),
247252
{
248253
message,
249254
page_context,
@@ -258,7 +263,7 @@ const continueConversation = async (
258263

259264
const deleteConversation = async (id: string) => {
260265
try {
261-
const response = await adminApi.delete(`/chatgpt/conversations/${id}/`);
266+
const response = await adminApi.delete(endpoints.conversation(id));
262267
return response.data;
263268
} catch (error) {
264269
console.error("Error(s) during deleteConversation: ", error);
@@ -273,7 +278,7 @@ const updateConversationTitle = async (
273278
{ status: string; title: Conversation["title"] } | { error: string }
274279
> => {
275280
try {
276-
const response = await adminApi.patch(`/chatgpt/conversations/${id}/update_title/`, {
281+
const response = await adminApi.patch(endpoints.updateConversationTitle(id), {
277282
title: newTitle,
278283
});
279284
return response.data;
@@ -289,7 +294,7 @@ const sendAssistantMessage = async (
289294
previousResponseId?: string,
290295
) => {
291296
try {
292-
const response = await publicApi.post(`/v1/api/assistant`, {
297+
const response = await publicApi.post(V1_API_ENDPOINTS.ASSISTANT, {
293298
message,
294299
previous_response_id: previousResponseId,
295300
});

0 commit comments

Comments
 (0)