Building Harbour's API v2: Resource Design and Modeling (Part 3)

Building Harbour's API v2: Resource Design and Modeling (Part 3)

After establishing our foundation and authentication system, the next critical challenge in building Harbour's API v2 was designing our resources and data models. This article shares our approach to creating a flexible, intuitive resource structure that serves both internal and external needs.

Series Overview:

Context and Challenge

Our existing API had grown organically, leading to inconsistent resource naming, complex relationships that needed to be made easier to navigate, and inflexible query patterns. With API v2, we needed to design a resource model that would:

  • Support complex business relationships without sacrificing simplicity
  • Provide flexible querying capabilities for diverse use cases
  • Maintain consistency across all endpoints
  • Scale effectively as we add new features

Design Considerations

Resource Naming Convention

We established strict naming conventions based on three principles:

  1. Use nouns for resources, never verbs
  2. Prefer plural forms for collection endpoints
  3. Use spinal-case for multi-word resources

This led to endpoints like:

/documents
/versions
/files        

We deliberately avoided endpoints like /getDocuments or /createUser, as these verb-based names violate RESTful principles and make the API less intuitive.

Modeling Business Relationships

Complex business relationships presented a significant challenge. Consider a typical scenario in our domain:

Documents
  -> DocumentVersions
     -> Files
        -> Fields        

Rather than creating deeply nested URLs like

/documents/{id}/versions/{version}/files/{file}        

We opted for flatter resource paths with relationship parameters:

/documents?version_id={version}        

This approach provides several benefits:

  • Simpler URL structure
  • Easier pagination and filtering
  • More flexible querying options
  • Better cache utilization

Query Parameter Design

We implemented a consistent query parameter structure across all endpoints:

  • Filtering:

/documents?status=draft&version=0        

  • Sorting:

/documents?order_by=+created_at        

  • Pagination:

After evaluating various pagination methods, we chose page/size pagination for its simplicity and familiarity. Our implementation includes:

/documents?page=2&size=100        

Response:

{
  "items": [...],
  "total": 300,
  "page": 2,
  "size": 100,
  "pages": 3
}        

This approach provides several advantages:

  • Easy to implement and understand
  • Compatible with most frontend frameworks
  • Allows users to jump to specific pages
  • Provides total count for UI pagination controls

Implementation Details

Query Parameter Parsing

We standardized parameter parsing across all endpoints:

def parse_query_params(request):
    return {
        'filters': _parse_filters(request.args),
        'order_by': _parse_sort(request.args.get('sort')),
        'pagination': {
            'page': int(request.args.get('page', 1)),
            'size': min(int(request.args.get('size', 20)), 100)
        }
    }        

Resource Serialization

We implemented a consistent serialization layer:

class ResourceSerializer:
    def serialize(self, resource):
        return {
            'type': self.resource_type,
            'id': resource.id,
            'attributes': self._get_attributes(resource),
        }        

Lessons Learned

The journey of building our API v2 has taught us several valuable lessons about REST API design and implementation. REST consistency proved to be fundamental to our success. By maintaining strict conventions for resource naming and HTTP methods, we significantly improved the developer experience for both our internal teams and external clients. Our engineers now spend less time debating API design decisions and more time building features.

Documentation quality directly influences adoption rates. The consistent patterns in our REST design made our documentation more intuitive, which could significantly reduce onboarding friction. New team members and external developers could quickly understand and start using our API without extensive support.

Our experience with pagination taught us valuable lessons about performance and usability. While the page/size approach is straightforward, we needed to implement proper limits and optimizations:

  • Maximum page size of 100 items to prevent performance issues
  • Database query optimization for offset pagination
  • Strategic caching for frequently accessed pages

Future Enhancements

Looking ahead, we've identified several opportunities to enhance our API's capabilities while maintaining its simplicity and consistency. We plan to introduce field selection, allowing clients to request specific fields and reduce response payload sizes. This will be particularly valuable for mobile clients and bandwidth-constrained environments.

Resource expansion represents another significant enhancement on our roadmap. This feature will allow clients to reduce the number of API calls by expanding related resources in a single request. Key planned improvements include:

  • Field selection: GET /customers?fields=id,name,email
  • Resource expansion: GET /subscriptions?expand=customer,plan
  • Enhanced filtering: GET /transactions?amount__gt=1000

Next Steps

Our immediate priority is strengthening our API's foundation through comprehensive automated testing. We're developing a suite of performance tests focused on complex query patterns to ensure consistent response times as our dataset grows.

Another key initiative is automating our REST API design enforcement. We're building internal tools to validate that new endpoints adhere to our established conventions, catching potential inconsistencies before they reach production. This tooling will help maintain the high quality of our API as we scale our development team.

Our immediate focus areas include:

  • Automated performance testing for complex queries
  • Tools to enforce REST naming conventions
  • Query optimization based on usage patterns

Watch for Part 4 of this series, where we'll dive into our approach to error handling and validation in API v2.


要查看或添加评论,请登录

Caio Pizzol的更多文章

社区洞察

其他会员也浏览了