Skip to main content

Services

Services are the business logic layer of Tasteful flavors. They contain all the core business rules, orchestrate operations between different components, and provide a clean interface for controllers to interact with your application’s functionality. Services are where ALL business logic should live.

What is a Service?

A Service in Tasteful is a class that inherits from BaseService and encapsulates business logic. Services are responsible for:
  • Business Logic Implementation: All core business rules and operations
  • Data Orchestration: Coordinating operations between repositories and external systems
  • Validation: Ensuring data integrity and business rule compliance
  • Transaction Management: Handling complex operations that span multiple data sources
  • Error Handling: Converting low-level errors into meaningful business exceptions
  • Service Composition: Coordinating with other services for complex workflows
Services act as the single source of truth for business operations and should contain all logic that isn’t purely HTTP-related (controllers) or data-access related (repositories).

Core Concepts

BaseService Foundation

All services inherit from BaseService, which provides the foundation for dependency injection:
Key features of BaseService:
  • Dependency Injection Support: Automatically receives dependencies through constructor injection
  • Clean Architecture: Provides a clear separation between business logic and infrastructure
  • Testability: Easy to mock and test in isolation
  • Composition: Services can depend on other services and repositories

Service Dependencies

Services can depend on repositories, other services, and configuration objects:

Implementation

Basic Service Implementation

Here’s a complete example of a service implementation:

Advanced Patterns

Service Composition

Services can orchestrate complex operations by coordinating with multiple other services:

Service with Repository Integration

Services should always interact with data through repositories:

Integration with Other Components

Service-Controller Relationship

Controllers should always delegate business logic to services:

Service-Repository Relationship

Services should interact with data only through repositories:

Dependency Injection

Services receive their dependencies through constructor injection:

Best Practices

Do’s

  • Put ALL business logic in services - Never put business logic in controllers or repositories
  • Use meaningful method names - Service methods should clearly describe what business operation they perform
  • Validate input data - Services should validate all input according to business rules
  • Handle errors appropriately - Convert low-level errors into meaningful business exceptions
  • Keep services focused - Each service should have a single responsibility
  • Use dependency injection - Let the framework inject dependencies rather than creating them manually

Don’ts

  • Don’t put HTTP logic in services - Services shouldn’t know about HTTP requests/responses
  • Don’t access external APIs directly - Use dedicated service classes for external integrations
  • Don’t handle database connections directly - Always use repositories for data access
  • Don’t make services too large - Break down complex services into smaller, focused services
  • Don’t ignore error handling - Always handle and convert exceptions appropriately

Common Patterns

CRUD Service Pattern

Most services follow standard CRUD patterns with business logic:

Service Orchestration Pattern

Services can orchestrate complex workflows:

Testing

Services are highly testable thanks to dependency injection:
Services are the heart of your Tasteful application’s business logic. They provide a clean, testable, and maintainable way to implement complex business operations while maintaining proper separation of concerns with controllers and repositories.