v0.1.0
Article

The Design of Misting URIs: A Journey to Clarity

Introduction

Every infrastructure management system needs a way to uniquely identify resources. In Mistcraft, we designed the Misting URI schema—a standardized way to reference any resource type or instance across all providers. This article tells the story of how we arrived at our current design, the alternatives we considered, and the lessons we learned along the way.

The Challenge: Create a URI schema that is readable, hierarchical, URL-safe, and flexible enough to handle resources from any cloud provider while maintaining consistency.

The Requirements

Before diving into design decisions, we established clear requirements for our URI system:

Unique Identification

Every resource type and instance must have a globally unique identifier

Human Readable

URIs should be understandable at a glance, not cryptic UUIDs

Hierarchical

Support nested resources and clear organizational structure

URL Compatible

Work within standard URL contexts with minimal encoding

Version Aware

Support provider versioning for API evolution

Extensible

Accommodate future providers and resource types

The Final Structure

After extensive iteration, we settled on this URI structure:

TEXT
# General format
mw:<classification>:<provider>[@<version>]/<path>

# Type URIs - identify resource types
mw:type:azure/compute/virtual-machine
mw:type:azure@v1.0.0/storage/storage-account
mw:type:aws/ec2/instance

# Resource URIs - identify specific instances
mw:resource:azure/subscriptions/d4b54c68/resourceGroups/myRg
mw:resource:aws/arn:aws:ec2:us-west-2:123456789012:instance/i-1234567890abcdef0

Let's break down each component and the reasoning behind it:

mw: - The Scheme

We chose mw (Mistwrite/Misting) as our URI scheme identifier. This follows RFC 3986 and immediately identifies these as Mistcraft URIs, preventing any confusion with other systems.

:type: or :resource: - Classification

The second component classifies what kind of URI this is. This clear semantic boundary tells you immediately whether you're looking at a resource type definition or a specific instance reference.

provider - Provider Identifier

Simple, lowercase provider names like azure, aws, or gcp.

@v1.0.0 - Optional Version

Provider API versioning using the familiar @ notation from NPM and Docker. The v prefix makes it unmistakably a version number.

/service/resource - The Path

Standard path notation for the resource hierarchy. Services like compute or storage prevent naming collisions, while the path naturally supports nested resources.

Design Rationale

Why Colons as Delimiters?

The use of colons creates clear semantic boundaries. When you see mw:type:azure, each colon marks a significant transition: scheme → classification → provider. This is more readable than alternatives like mw/type/azure where everything blurs together.

Why Version at the Provider Level?

Cloud providers version their entire API, not individual resources. When Azure releases API version 2021-01-01, it affects all resources. Our versioning scheme reflects this reality:

TEXT
# Provider-level versioning (what we chose)
mw:type:azure@v2.0/compute/virtual-machine
mw:type:azure@v2.0/storage/storage-account

# NOT resource-level versioning
mw:type:azure/compute/virtual-machine@v2.0  # Wrong level!

Why the @ Symbol for Versions?

We considered several version notation options:

Option Example Decision
@ notation azure@v1.0.0 ✓ Chosen - Familiar from NPM/Docker
Query parameter azure?v=1.0.0 Too optional-looking for critical info
Path segment azure/v1.0.0/ Makes paths longer and harder to parse
Colon separator azure:v1.0.0 Too many colons, reduces clarity

The Service Layer

Including a service namespace (like /compute/ or /storage/) prevents naming collisions. Many providers have resources with the same name in different services:

TEXT
# Without service layer - ambiguous!
mw:type:azure/instance  # Is this compute? Container? Database?

# With service layer - clear
mw:type:azure/compute/instance
mw:type:azure/container/instance
mw:type:azure/database/instance

Alternatives We Considered

Alternative 1: Single Delimiter

TEXT
mw/type/azure/compute/virtual-machine

Why we rejected it: Less semantic clarity. The boundary between classification and provider isn't visually distinct. Everything runs together.

Alternative 2: All Colons / URN-Style

TEXT
mw:type:azure:1.0.0:compute:virtual-machine

Why we rejected it: "I didn't like it much" - actual quote from our design doc. More seriously, it's hard to parse visually and doesn't follow any established conventions. URNs are meant for persistent, location-independent names. Our URIs often reference actual cloud resources with locations.

Alternative 3: Fully Hierarchical Paths

TEXT
mw://azure.compute.virtual-machine/v1.0.0

Why we rejected it: The double-slash implies network location (like HTTP), which these aren't. Also, dots don't convey the same hierarchical feeling as slashes.

Real-World Examples

Here's how our URI schema handles various real-world scenarios:

Nested Resources

TEXT
# Storage hierarchy in Azure
mw:type:azure/storage/storage-account
mw:type:azure/storage/storage-account/blob-container
mw:type:azure/storage/storage-account/blob-container/blob

# Kubernetes resources
mw:type:k8s/apps/deployment
mw:type:k8s/apps/deployment/replica-set
mw:type:k8s/apps/deployment/replica-set/pod

Version Evolution

TEXT
# Using latest (no version specified)
resource vm1 = mw:type:azure/compute/virtual-machine { ... }

# Pinning to specific version for stability
resource vm2 = mw:type:azure@v1.0/compute/virtual-machine { ... }

# Testing new beta features
resource vm3 = mw:type:azure@v2.0-beta/compute/virtual-machine { ... }

Cross-Provider Consistency

TEXT
# Similar resources across providers - consistent pattern
mw:type:azure/compute/virtual-machine
mw:type:aws/ec2/instance
mw:type:gcp/compute/instance

# Storage across providers
mw:type:azure/storage/storage-account
mw:type:aws/s3/bucket
mw:type:gcp/storage/bucket

Lessons Learned

1. Familiarity Matters

Using conventions developers already know (like @ for versions) reduces cognitive load. Don't reinvent the wheel unless you have a compelling reason.

2. Visual Hierarchy is Important

The mixed use of colons and slashes creates natural groupings that help the eye parse URIs quickly. mw:type:azure/compute/vm has clear sections, while mw/type/azure/compute/vm is just a blur of slashes.

3. Plan for URL Encoding

While our URIs are elegant on their own, we had to accept that colons become %3A in URLs. It's unfortunate but unavoidable—the clarity in non-URL contexts was worth the trade-off.

4. Validation Patterns Are Critical

We developed comprehensive regex patterns for validation early. This ensured consistency across all implementations and caught many edge cases during development:

REGEX
^mw:type:(?P<provider>[a-z0-9-]+)
  (?:@(?P<version>v\d+(?:\.\d+)?(?:\.\d+)?))?
  /(?P<service>[a-z0-9-]+)
  /(?P<resource_path>[a-z0-9-]+(?:/[a-z0-9-]+)*)$

5. Leave Room for Evolution

The classification component (:type: vs :resource:) gives us room to add new URI types in the future without breaking existing ones. Always design for extensibility.

Conclusion

The Misting URI schema represents dozens of iterations and heated debates. What started as a simple identifier system evolved into a carefully crafted balance between clarity, standards compliance, and practical usability.

Is it perfect? No. The URL encoding issue still bothers us. But it achieves our primary goals: developers can understand URIs at a glance, the system handles complex hierarchies elegantly, and it's flexible enough to grow with Mistcraft's needs.

The Most Important Lesson

Sometimes the best design isn't the most technically elegant—it's the one that makes developers' lives easier. Our URI schema may require URL encoding, and yes, we use multiple delimiter types, but when a developer sees mw:type:azure@v1.0/compute/virtual-machine, they know exactly what it means. That clarity is worth more than technical purity.

Try It Yourself

See the Misting URI schema in action with Mistcraft.