URI System
The URI (Uniform Resource Identifier) system in the content model provides a consistent addressing scheme for content across different storage adapters. It serves as the foundation for content identification, retrieval, and referencing.
Core Concepts
URI Structure
Content URIs follow a consistent structure:
[scheme:][//authority/]path[?query][#fragment]
- Scheme: Optional protocol identifier (e.g.,
file:
,http:
,memory:
) - Authority: Optional host/authority component
- Path: Required path component that identifies the content location
- Query: Optional query parameters
- Fragment: Optional fragment identifier for addressing parts of content
Relative vs. Absolute URIs
The content system supports both relative and absolute URIs:
- Absolute URIs: Include scheme and complete addressing information
- Examples:
file:///content/articles/intro.md
,http://api.example.com/content/data.json
- Examples:
- Relative URIs: Resolved against a base URI
- Examples:
articles/intro.md
,../shared/header.md
- Examples:
URI Resolution
Relative URIs are resolved against a base URI using standard URI resolution algorithms:
- If the URI is absolute, use it as-is
- If the URI is relative, combine it with the base URI according to RFC 3986 rules
- Normalize the resulting path (resolve
.
and..
segments)
URI Components
Path Component
The path component is the most fundamental part of a content URI:
- Follows a hierarchical structure (directories/subdirectories)
- Uses forward slashes (
/
) as separators - May include file extensions to indicate content type
- Special paths:
- Root path (
/
) - Current path (
.
) - Parent path (
..
)
- Root path (
Scheme Component
The scheme identifies the adapter type and protocol:
file:
- Filesystem adaptermemory:
- Memory adapterhttp:
orhttps:
- HTTP adapterindexeddb:
- IndexedDB adapterlocalStorage:
- LocalStorage adapter
When no scheme is specified, the default adapter is used.
Query Component
The query component provides additional parameters for content operations:
- Format specification:
?format=json
- Version selection:
?version=2.1
- Filtering:
?tags=important&status=published
- Projection:
?fields=title,summary,publishedDate
Fragment Component
The fragment component addresses specific parts within content:
- Section references:
#introduction
- Line numbers:
#L42-L50
- Time positions (for media):
#t=10,20
- Selection ranges:
#char=0,100
URI Patterns
URI patterns allow matching multiple content items using glob-like syntax:
**/*.md
- All Markdown files in any directoryarticles/*.json
- All JSON files in the articles directorydata/{users,products}/*.json
- All JSON files in users or products directories*.{md,mdx}
- All Markdown and MDX files in the current directory
Patterns are used for:
- Listing content with
store.list(pattern)
- Content watching with
store.watch(pattern, callback)
- Batch operations
URI Mapping
URIs can be mapped between different representations:
Physical to Logical Mapping
Content adapters map physical storage locations to logical URIs:
- Filesystem paths:
/var/content/articles/intro.md
→articles/intro.md
- Database records:
db:collection:12345
→articles/intro.md
- Remote resources:
https://api.example.com/v1/content/12345
→articles/intro.md
URI Normalization
URIs are normalized to ensure consistent addressing:
- Path normalization: Resolve
.
and..
segments - Case normalization: Convert to lowercase if case-insensitive
- Trailing slash handling: Remove or add consistently
- Extension normalization: Add default extensions when missing
Working with URIs
URI Parsing
The content system provides utilities for URI parsing:
import { parseUri } from '@lib/content/uri'
const uri = 'file:///content/articles/intro.md?version=latest#summary'
const parsed = parseUri(uri)
// Result:
// {
// scheme: 'file',
// authority: '',
// path: '/content/articles/intro.md',
// query: 'version=latest',
// fragment: 'summary',
// params: { version: 'latest' }
// }
URI Building
Creating URIs programmatically:
import { buildUri } from '@lib/content/uri'
const uri = buildUri({
scheme: 'memory',
path: 'articles/intro.md',
query: { version: 'latest' },
fragment: 'summary',
})
// Result: memory:articles/intro.md?version=latest#summary
URI Resolution
Resolving relative URIs against a base URI:
import { resolveUri } from '@lib/content/uri'
const baseUri = 'articles/guides/'
const relativeUri = '../tutorials/getting-started.md'
const resolved = resolveUri(baseUri, relativeUri)
// Result: articles/tutorials/getting-started.md
Pattern Matching
Testing if a URI matches a pattern:
import { matchesPattern } from '@lib/content/uri'
const pattern = 'articles/**/*.md'
const uri = 'articles/guides/intro.md'
const matches = matchesPattern(uri, pattern)
// Result: true
URI Handling in Adapters
Each adapter implements URI handling specific to its storage mechanism:
- FileSystemAdapter: Maps between filesystem paths and logical URIs
- MemoryAdapter: Uses URIs as keys in an in-memory map
- HttpAdapter: Maps between HTTP URLs and logical URIs
- IndexedDBAdapter: Uses URIs as keys in object stores
Best Practices
URI Design
- Use descriptive, hierarchical paths that reflect content organization
- Prefer lowercase URIs for consistency
- Use file extensions to indicate content type
- Keep URIs reasonably short and human-readable
- Avoid special characters that might require encoding
URI Management
- Store canonical URIs with content references
- Use relative URIs for content references when possible
- Prefer patterns over enumeration for batch operations
- Cache URI resolution results when processing multiple references
URI Stability
- Maintain stable URIs for important content
- Implement redirects when URIs must change
- Use content identifiers separate from URIs for permanent references
- Consider versioning in the URI scheme for immutable content
Integration with Web Standards
The content URI system aligns with web standards:
- Compatible with RFC 3986 URI syntax
- Supports glob patterns for content matching
- Works with standard URL objects in browser environments
- Integrates with Web API URL for parsing