Skip to main content

SD - REST APIs

· 6 min read

GET Search Requests

ExampleSearch QueriesUse Case
/events?name=bollywood& date=xx-xxQuery ParametersSimple, common searches with 1-2 specific filters.
/events/search?keyword=partyDedicated EndpointAdvanced search. same keyword "party" is matched against multiple fields (title, description, tags) on backend
/events/search with a request bodyPOST with BodyComplex, 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

ExampleRequest TypeUse Case
/eventsSimple CreateBasic resource creation with a single object
/events/batchBatch CreateCreate multiple resources in a single request to reduce API calls
/events/{id}/duplicateAction EndpointPerform 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

ExampleRequest TypeUse Case
/events/{id}/commentsNested ResourceCreate a comment directly related to a specific event
/events/{id}/comments/batchBatch NestedAdd multiple comments to an event in a single request
/commentsIndependent ResourceCreate comments with flexible relationships, useful when commenting on multiple types of content
/comments/reply/{parentId}Threaded CommentsCreate 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

ExampleUse Case
/events/{id}Retrieve detailed information about a specific event
/events/{id}/commentsGet 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-urlRetrieve 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