Comprehensive caching system and error handling for efficient resource management and robust error reporting.
All protocol handlers support cache validation to avoid redundant requests when resources haven't changed.
Cache Validation Process:
mtime) from filesystem statsIf-Modified-Since, If-None-Match, Cache-Control, Expires)Usage Pattern:
import { getUri } from "get-uri";
// First request - fetches for real
const stream = await getUri('https://api.example.com/data.json');
try {
// Subsequent request with cache validation
const newStream = await getUri('https://api.example.com/data.json', {
cache: stream
});
} catch (err) {
if (err.code === 'ENOTMODIFIED') {
// Resource unchanged, reuse previous stream
console.log('Using cached data');
// Continue using original stream
} else {
throw err; // Different error
}
}Standardized error handling across all protocols with specific error codes.
Thrown when a resource does not exist at the specified URI.
/**
* Error thrown when resource is not found at the specified endpoint
*/
class NotFoundError extends Error {
/** Error code for not found resources */
code: 'ENOTFOUND';
/**
* @param message - Optional custom error message
* @default "File does not exist at the specified endpoint"
*/
constructor(message?: string);
}Common Scenarios:
Usage Example:
import { getUri } from "get-uri";
try {
const stream = await getUri('file:///nonexistent/file.txt');
} catch (err) {
if (err.code === 'ENOTFOUND') {
console.log('File not found:', err.message);
// Handle missing resource
}
}Thrown when cache validation indicates the resource hasn't changed since the previous request.
/**
* Error thrown when resource has not been modified since the provided cache
*/
class NotModifiedError extends Error {
/** Error code for unmodified resources */
code: 'ENOTMODIFIED';
/**
* @param message - Optional custom error message
* @default "Source has not been modified since the provided \"cache\", re-use previous results"
*/
constructor(message?: string);
}Usage Example:
import { getUri } from "get-uri";
const originalStream = await getUri('https://api.example.com/data.json');
try {
const newStream = await getUri('https://api.example.com/data.json', {
cache: originalStream
});
} catch (err) {
if (err.code === 'ENOTMODIFIED') {
// Resource unchanged, use original stream
return originalStream;
}
throw err;
}Thrown for HTTP-level errors beyond standard not found cases.
/**
* Error thrown for HTTP application errors
*/
class HTTPError extends Error {
/** Formatted error code based on status message */
code: string;
/** HTTP status code */
statusCode: number;
/**
* @param statusCode - HTTP status code
* @param message - Optional message (defaults to HTTP status text)
*/
constructor(statusCode: number, message?: string);
}Usage Example:
import { getUri } from "get-uri";
try {
const stream = await getUri('https://api.example.com/protected');
} catch (err) {
if (err instanceof HTTPError) {
console.log(`HTTP Error ${err.statusCode}: ${err.message}`);
if (err.statusCode === 401) {
// Handle authentication error
} else if (err.statusCode === 403) {
// Handle authorization error
}
}
}The HTTP protocol handler supports standard HTTP caching mechanisms.
// Supported Cache-Control directives:
// - max-age: Sets expiration time relative to response date
// - must-revalidate: Forces revalidation (currently not implemented)
// - no-cache: Forces fresh request, ignores cache
// - no-store: Forces fresh request, ignores cache
const stream = await getUri('https://api.example.com/data', {
headers: {
'Cache-Control': 'max-age=3600' // Cache for 1 hour
}
});When a cache is provided, appropriate conditional request headers are automatically added:
// Automatically adds headers when cache is present:
// - If-Modified-Since: Uses Last-Modified from cache
// - If-None-Match: Uses ETag from cache
const cachedStream = await getUri('https://api.example.com/data', {
cache: previousStream // Adds conditional headers automatically
});import { getUri } from "get-uri";
async function fetchResource(uri: string, cache?: any) {
try {
return await getUri(uri, { cache });
} catch (err) {
switch (err.code) {
case 'ENOTFOUND':
console.log('Resource not found:', uri);
return null;
case 'ENOTMODIFIED':
console.log('Resource unchanged, using cache');
return cache;
default:
// Check for HTTP errors by status code property
if (err.statusCode) {
console.log(`HTTP ${err.statusCode}: ${err.message}`);
// Handle specific HTTP errors
}
throw err; // Re-throw unexpected errors
}
}
}