Building Restful API
Jump to navigation
Jump to search
Introduction
This page is here to remind me of what a good REST API looks like independent of language
REST API Design Considerations
This page outlines key architectural, operational, and maintainability concerns when designing and evolving REST APIs. Each section includes best practices, trade-offs, and onboarding notes for maintainers.
Security
- Use HTTPS for all communication.
- Implement authentication (e.g., OAuth2, JWT).
- Apply role-based authorization.
- Validate all inputs to prevent injection attacks.
- Avoid exposing internal models—use DTOs.
Caching
- Use `Cache-Control`, `ETag`, and `Last-Modified` headers.
- Cache GET responses where appropriate.
- Avoid caching sensitive or user-specific data.
- Consider CDN integration for static resources.
PUT vs PATCH
- PUT: Full resource replacement; idempotent.
- PATCH: Partial update; not guaranteed idempotent.
- Prefer PATCH for user-facing updates; PUT for internal sync.
Code Coverage
- Use `sbt-scoverage` to measure coverage.
- Target 80%+ coverage for core logic.
- Exclude DTOs and boilerplate from metrics.
- Integrate with CI to enforce thresholds.
Unit Testing
- Test logic in isolation.
- Use mocks/stubs for external dependencies.
- Validate edge cases and error paths.
End-to-End (E2E) Testing
- Simulate full request/response lifecycle.
- Use real HTTP calls against a test server.
- Validate integration points and serialization.
Slugs
- Use slugs for human-readable URLs (e.g., `/films/the-godfather`).
- Ensure uniqueness and URL safety.
- Store slugs alongside primary keys.
Performance
- Paginate large datasets.
- Use filtering and sorting on server side.
- Profile endpoints with real-world data.
- Avoid N+1 queries and excessive joins.
Logging
- Log structured events (JSON preferred).
- Include request IDs and timestamps.
- Avoid logging sensitive data.
- Use log levels: DEBUG, INFO, WARN, ERROR.
Versioning
- Use URI-based versioning (`/v1/countries`) or header-based.
- Document breaking changes clearly.
- Deprecate old versions gracefully.
Error Modeling
- Use sealed trait + case classes for errors.
- Return appropriate HTTP status codes.
- Include machine-readable error codes and human-readable messages.
Documentation
- Use OpenAPI (Swagger) for endpoint specs.
- Include examples, error codes, and auth flows.
- Keep docs versioned and discoverable.
Observability
- Integrate metrics (e.g., Prometheus).
- Track latency, error rates, and throughput.
- Use tracing (e.g., OpenTelemetry) for distributed systems.
DTO Modeling
- Separate input/output DTOs from domain models.
- Use Play JSON formats in companion objects.
- Validate DTOs before mapping to domain.
Naming Conventions
- Use plural nouns for collections (`/countries`).
- Use kebab-case or snake_case consistently.
- Avoid verbs in endpoint paths.
Rate Limiting
- Protect endpoints from abuse.
- Use token buckets or leaky buckets.
- Return `429 Too Many Requests` with retry headers.
Pagination
- Use `limit` and `offset` or cursor-based paging.
- Return metadata: total count, next page token.
- Avoid over-fetching.
Monitoring
- Track uptime, latency, and error rates.
- Alert on anomalies.
- Use dashboards for visibility.
Onboarding Clarity
- Tag patterns and decisions in code.
- Maintain a glossary of terms and flows.
- Document legacy boundaries and migration paths.
Checklist
| Concern | Important | Best Practice | Done |
|---|---|---|---|
| Security | ✅ | ✅ | |
| Caching | ✅ | ✅ | |
| PUT vs PATCH | ✅ | ✅ | |
| Code Coverage | ✅ | ✅ | |
| Unit Testing | ✅ | ✅ | |
| E2E Testing | ✅ | ✅ | |
| Slugs | ✅ | ✅ | |
| Performance | ✅ | ✅ | |
| Logging | ✅ | ✅ | |
| Versioning | ✅ | ✅ | |
| Error Modeling | ✅ | ✅ | |
| Documentation | ✅ | ✅ | |
| Observability | ✅ | ✅ | |
| DTO Modeling | ✅ | ✅ | |
| Naming Conventions | ✅ | ✅ | |
| Rate Limiting | ✅ | ✅ | |
| Pagination | ✅ | ✅ | |
| Monitoring | ✅ | ✅ | |
| Onboarding Clarity | ✅ | ✅ |
Tick off each item as you implement or validate it. This page is a living artifact—update it as your API evolves.