Add Generic STAC Resource Fetching
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 42/100
- Issue type
- Feature
- Clarity
- Mostly clear
- Activity status
- Stale
- Tech stack
- react, typescript
Research direction
Start by reviewing the existing useCollection and useItem hooks, then consider the standalone-hooks work referenced in issue #34. Define the scope for fetching catalogs, collections, items, and item collections, including type determination, errors, relative links, and the listed hook options. Done should include tests for each resource type, invalid STAC and href handling, plus hook documentation and examples.
Written by the indexing model from the issue text.
Description
Problem
Currently, stac-react assumes you're working with a structured STAC API with known endpoints (/collections, /search, etc.). There's no way to fetch an arbitrary STAC resource (catalog, collection, or item) from any URL without knowing its type in advance.
This is problematic when:
- Following STAC links where the target type is unknown
- Exploring static STAC catalogs
- Working with STAC resources from various sources
- Building generic STAC browsers/explorers
Current Behavior
You must know the resource type and use the specific hook:
// Must know it's a collection
const { collection } = useCollection('collection-id');
// Must know it's an item
const { item } = useItem(itemUrl);
// No way to fetch "whatever is at this URL"
Desired Behavior
import { useStacValue } from '@developmentseed/stac-react';
function StacResourceViewer({ url }) {
const { value, type, isLoading, error } = useStacValue(url);
// value could be Catalog, Collection, Item, or ItemCollection
// type indicates what was fetched: 'Catalog' | 'Collection' | 'Feature' | 'FeatureCollection'
switch (type) {
case 'Catalog':
return <CatalogView catalog={value} />;
case 'Collection':
return <CollectionView collection={value} />;
case 'Feature':
return <ItemView item={value} />;
case 'FeatureCollection':
return <ItemCollectionView items={value} />;
}
}
Use Cases from stac-map
stac-map has a useStacValue hook that:
const { value, error, items, table } = useStacValue({
href: 'https://any-stac-url.com/resource.json',
fileUpload,
datetimeBounds,
stacGeoparquetItemId,
});
// value is automatically typed based on what was fetched
// Works with URLs, file uploads, and geoparquet
Proposed Solution
Hook Signature
type StacValueType = 'Catalog' | 'Collection' | 'Feature' | 'FeatureCollection';
type StacValue = StacCatalog | StacCollection | StacItem | StacItemCollection;
type UseStacValueResult = {
value?: StacValue;
type?: StacValueType;
isLoading: boolean;
isFetching: boolean;
error?: ApiErrorType;
refetch: () => Promise<void>;
};
function useStacValue(
url: string,
options?: {
headers?: Record<string, string>;
method?: 'GET' | 'POST';
body?: unknown;
}
): UseStacValueResult;
Implementation
import { useQuery } from '@tanstack/react-query';
function useStacValue(url: string, options = {}): UseStacValueResult {
const { data, error, isLoading, isFetching, refetch } = useQuery({
queryKey: ['stac-value', url, options],
queryFn: async () => {
const response = await fetch(url, {
method: options.method || 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
...options.headers,
},
body: options.body ? JSON.stringify(options.body) : undefined,
});
if (!response.ok) {
throw new ApiError(
response.statusText,
response.status,
await response.text(),
response.url
);
}
const json = await response.json();
return {
value: json,
type: determineStacType(json),
};
},
enabled: !!url,
retry: false,
});
return {
value: data?.value,
type: data?.type,
isLoading,
isFetching,
error,
refetch,
};
}
function determineStacType(json: any): StacValueType {
if (json.type === 'Feature') return 'Feature';
if (json.type === 'FeatureCollection') return 'FeatureCollection';
if (json.type === 'Collection') return 'Collection';
if (json.type === 'Catalog') return 'Catalog';
// Fallback: try to infer from structure
if (json.extent && json.license) return 'Collection';
if (json.links && !json.features) return 'Catalog';
throw new Error('Unable to determine STAC type from resource');
}
Advanced Features
Type Guards
export function isStacCatalog(value: StacValue): value is StacCatalog {
return value.type === 'Catalog';
}
export function isStacCollection(value: StacValue): value is StacCollection {
return value.type === 'Collection';
}
export function isStacItem(value: StacValue): value is StacItem {
return value.type === 'Feature';
}
export function isStacItemCollection(value: StacValue): value is StacItemCollection {
return value.type === 'FeatureCollection';
}
Link Resolution
Optionally resolve relative hrefs to absolute:
function makeHrefsAbsolute(value: StacValue, baseUrl: string): StacValue {
if (!value.links) return value;
return {
...value,
links: value.links.map(link => ({
...link,
href: new URL(link.href, baseUrl).toString(),
})),
};
}
Benefits
- ✅ Generic STAC resource fetching
- ✅ Type-safe handling of different STAC types
- ✅ Simplifies link following in STAC catalogs
- ✅ Enables building generic STAC explorers
- ✅ Matches patterns used in other STAC tools
Breaking Changes
None - this is new functionality.
Related Issues
- #34 - Add Standalone Hooks (Context-Free Mode)
Testing Requirements
- Test with STAC catalogs
- Test with STAC collections
- Test with STAC items
- Test with item collections
- Test type determination logic
- Test error handling for invalid STAC
- Test with relative and absolute hrefs
Documentation Requirements
- Document the
useStacValuehook - Provide examples for each STAC type
- Document type guards and utilities
- Show link following patterns
- Dominant language
- TypeScript
- Stars
- 34
- Forks
- 4
- PR merge metrics
- No merged PRs in 30d
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from developmentseed/stac-react
-
Difficulty 3/5 1-2 days Newbie friendliness 55/100
-
Difficulty 5/5 Over a week Newbie friendliness 35/100
-
Difficulty 5/5 Over a week Newbie friendliness 30/100
-
Difficulty 5/5 Over a week Newbie friendliness 35/100
-
Difficulty 5/5 Over a week Newbie friendliness 30/100
All issues in developmentseed/stac-react
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
copse-dev/agent-pane#2953 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Eynzof/Hermes-CN-Desktop#610 ·
-
bug clawsweeper:linked-pr-open clawsweeper:needs-live-repro clawsweeper:no-new-fix-pr impact:message-loss issue-rating: 🐚 platinum hermit P2 regression
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
calcite-components needs triage refactor
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Esri/calcite-design-system#15203 ·