SD - REST APIs
· 6 min read
GET Search Requests
Example | Search Queries | Use Case |
---|---|---|
/events?name=bollywood& date=xx-xx | Query Parameters | Simple, common searches with 1-2 specific filters. |
/events/search?keyword=party | Dedicated Endpoint | Advanced search. same keyword "party" is matched against multiple fields (title, description, tags) on backend |
/events/search with a request body | POST with Body | Complex, nested, or structured search criteria |
Sample Example
POST /events/search // POST for complex search
{
"keyword": "bollywood",
"location": "Delhi",
"dateRange": {
"from": "2025-01-01",
"to": "2025-01-31"
},
"maxParticipants": 100
}
POST Requests
Example | Request Type | Use Case |
---|---|---|
/events | Simple Create | Basic resource creation with a single object |
/events/batch | Batch Create | Create multiple resources in a single request to reduce API calls |
/events/{id}/duplicate | Action Endpoint | Perform specific actions that don't fit CRUD operations |
Sample Example
// Simple Create
POST /events
{
"title": "Summer Music Festival",
"date": "2025-07-15",
"location": "Central Park"
}
// Batch Create
POST /events/batch
{
"events": [
{
"title": "Workshop 1",
"date": "2025-08-01"
},
{
"title": "Workshop 2",
"date": "2025-08-02"
}
]
}
// Action Endpoint
POST /events/123/duplicate
{
"newDate": "2025-09-15",
"preserveAttendees": false
}
POST Requests for Nested Resources
Example | Request Type | Use Case |
---|---|---|
/events/{id}/comments | Nested Resource | Create a comment directly related to a specific event |
/events/{id}/comments/batch | Batch Nested | Add multiple comments to an event in a single request |
/comments | Independent Resource | Create comments with flexible relationships, useful when commenting on multiple types of content |
/comments/reply/{parentId} | Threaded Comments | Create nested/reply comments, supporting comment threads |
Sample Example
// Simple Comment Creation
POST /events/123/comments
{
"content": "Great event! Looking forward to it.",
"userId": "456"
}
// Independent Comment Creation
POST /comments
{
"content": "Can't wait!",
"userId": "456",
"resourceType": "event",
"resourceId": "123"
}
// Batch Comment Creation
POST /events/123/comments/batch
{
"comments": [
{
"content": "Is parking available?",
"userId": "456"
},
{
"content": "What's the dress code?",
"userId": "789"
}
]
}
// Threaded Comment Reply
POST /comments/reply/789
{
"content": "Yes, there's a parking garage next door",
"userId": "101",
"eventId": "123"
}
GET Details Requests
Example | Use Case |
---|---|
/events/{id} | Retrieve detailed information about a specific event |
/events/{id}/comments | Get all comments related to a specific event |
/events/{id}/comments/{commentId} | Retrieve a specific comment related to an event |
/comments/{commentId} | Retrieve a specific comment without requiring event context |
/files/{fileId}/presigned-url | Retrieve a presigned URL to access a specific file. GET as it's a read only operation |
Sample Example
// Get Event Details
GET /events/123
// Get Event Comments
GET /events/123/comments
// Get Specific Comment (Event Context)
GET /events/123/comments/456
// This pattern may be appropriate in cases where the parent-child relationship needs to be explicitly validated or enforced.
// Get Specific Comment (Independent Access)
GET /comments/456
// Get Presigned URL for a File
GET /files/789/presigned-url
// Use this pattern when the file is a standalone entity, and a temporary URL is required to access it.
Making Fetch Requests using Promises
function fetchWithPromises(query, pageNum) {
const queryParams = new URLSearchParams({
q: query,
per_page: 10,
page: pageNum,
order: 'desc',
sort: 'stars'
});
return fetch(`https://api.github.com/search/repositories?${queryParams}`)
.then(response => {
if (!response.ok) {
throw new Error(`Error ${response.status}: ${response.statusText}`);
}
return response.json();
})
.then(result => {
return result.items || [];
});
}
Making Fetch Requests using Async/Await
async function fetchWithAsyncAwait(query, pageNum) {
const queryParams = new URLSearchParams({
q: query,
per_page: 10,
page: pageNum,
order: 'desc',
sort: 'stars'
});
try {
const response = await fetch(`https://api.github.com/search/repositories?${queryParams}`);
if (!response.ok) {
throw new Error(`Error ${response.status}: ${response.statusText}`);
}
const result = await response.json();
return result.items || [];
} catch (error) {
console.error('Error fetching data:', error);
return [];
}
}
Making Fetch Requests using Promises with Request Cancellation
function fetchWithPromises(contributorsUrl, pageNum, abortControllerRef) {
const queryParams = new URLSearchParams({
per_page: 10,
page: pageNum
});
// Create new AbortController for this request
abortControllerRef.current = new AbortController();
return fetch(`${contributorsUrl}?${queryParams}`,
{
signal: abortControllerRef.current.signal
})
.then(response => {
if (!response.ok) {
throw new Error(`Error while fetching ${response.status}: ${response.statusText}`)
}
return response.json();
})
.then(result => {
return result || []
})
.catch(error => {
// Don't set error state if request was aborted
if (error.name === 'AbortError') {
console.log('Request was aborted');
return [];
}
throw error; // Re-throw other errors
})
}
// React Hook Usage Example - Focused on Cancellation
function useContributors() {
// useRef keeps AbortController alive between renders
// Without useRef, the controller would be recreated on every render
const abortControllerRef = useRef(null);
// useCallback prevents infinite re-renders when this function is passed as prop
// Without it, child components would re-render on every parent render
const fetchContributors = useCallback(async (url, pageNum) => {
// Cancel any existing request before starting a new one
if (abortControllerRef.current) {
abortControllerRef.current.abort();
}
const data = await fetchWithPromises(url, pageNum, abortControllerRef);
return data;
}, []);
// useCallback prevents this function from being recreated on every render
// This is important for performance and preventing unnecessary re-renders
const cancelRequest = useCallback(() => {
if (abortControllerRef.current) {
abortControllerRef.current.abort();
}
}, []);
// Cleanup on unmount - cancel any ongoing requests
useEffect(() => {
return () => {
if (abortControllerRef.current) {
abortControllerRef.current.abort();
}
};
}, []);
return { fetchContributors, cancelRequest };
}
// When to use useCallback
//
// ❌ DON'T need useCallback (local fetch function):
// function MyComponent() {
// const fetchData = async () => {
// return await fetchWithPromises('/api/data', 1, abortControllerRef);
// }; // No useCallback needed - only used locally
// return <button onClick={fetchData}>Fetch</button>;
// }
//
// ✅ NEED useCallback (fetch function passed as prop):
// function Parent() {
// const fetchData = useCallback(async () => {
// return await fetchWithPromises('/api/data', 1, abortControllerRef);
// }, []); // Prevents child re-renders
// return <Child onFetch={fetchData} />;
// }
//
// In our example: fetchContributors might be passed to child components,
// so we use useCallback to prevent unnecessary re-renders