Skip to content
intermediate Phase 36 · Service Contracts

Service Contracts

API interfaces, data interfaces, repository interfaces, and why they matter for Magento development.

45m
0 problems
Topic Progress 0%

What Are Service Contracts

Service contracts define stable API interfaces for module interactions.

Why service contracts matter:

  • Stable API across versions
  • Decoupled implementation
  • Easy to test
  • REST/GraphQL API generation
  • Third-party integration

Service contract layers:

API Layer (Interfaces)
├── Data Interfaces (PostInterface)
├── Repository Interfaces (PostRepositoryInterface)
└── Service Interfaces (PostServiceInterface)

Implementation Layer
├── Models (Post)
├── Resource Models (Post)
├── Repositories (PostRepository)
└── Service Classes (PostService)

Module structure:

app/code/Vendor/Blog/
├── Api/
│   ├── Data/
│   │   ├── PostInterface.php
│   │   └── PostExtensionInterface.php
│   ├── PostRepositoryInterface.php
│   └── PostServiceInterface.php
├── Model/
│   ├── Post.php
│   ├── PostRepository.php
│   └── ResourceModel/
│       ├── Post.php
│       └── Post/Collection.php
└── etc/
    ├── module.xml
    ├── di.xml
    └── webapi.xml

Data Interfaces

Data interfaces define the structure of data objects.

Data interface:

<?php
namespace Vendor\Blog\Api\Data;

interface PostInterface
{
    const TITLE = 'title';
    const CONTENT = 'content';
    const STATUS = 'status';
    const CREATED_AT = 'created_at';
    const UPDATED_AT = 'updated_at';
    
    public function getId(): ?int;
    public function getTitle(): string;
    public function setTitle(string $title): self;
    public function getContent(): string;
    public function setContent(string $content): self;
    public function getStatus(): int;
    public function setStatus(int $status): self;
    public function getCreatedAt(): ?string;
    public function setCreatedAt(string $createdAt): self;
    public function getUpdatedAt(): ?string;
    public function setUpdatedAt(string $updatedAt): self;
}

Data interface best practices:

// 1. Use constants for field names
const TITLE = 'title';

// 2. Return self for fluent interface
public function setTitle(string $title): self;

// 3. Use nullable for optional fields
public function getCreatedAt(): ?string;

// 4. Type-hint all parameters
public function setStatus(int $status): self;

// 5. Document with PHPDoc
/**
 * Get post title
 * @return string
 */
public function getTitle(): string;

Repository Interfaces

Repository interfaces define CRUD operations for entities.

Repository interface:

<?php
namespace Vendor\Blog\Api;

use Magento\Framework\Api\SearchCriteriaInterface;
use Magento\Framework\Api\SearchResultsInterface;
use Vendor\Blog\Api\Data\PostInterface;

interface PostRepositoryInterface
{
    /**
     * Get post by ID
     * @param int $id
     * @return PostInterface
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    public function get($id): PostInterface;
    
    /**
     * Get list of posts
     * @param SearchCriteriaInterface $searchCriteria
     * @return SearchResultsInterface
     */
    public function getList(SearchCriteriaInterface $searchCriteria): SearchResultsInterface;
    
    /**
     * Save post
     * @param PostInterface $post
     * @return PostInterface
     */
    public function save(PostInterface $post): PostInterface;
    
    /**
     * Delete post
     * @param PostInterface $post
     * @return bool
     */
    public function delete(PostInterface $post): bool;
    
    /**
     * Delete post by ID
     * @param int $id
     * @return bool
     */
    public function deleteById($id): bool;
}

Service interface:

<?php
namespace Vendor\Blog\Api;

interface PostServiceInterface
{
    public function publish(int $id): PostInterface;
    public function archive(int $id): PostInterface;
    public function duplicate(int $id): PostInterface;
}

Service Contract Benefits

Benefits and practical applications of service contracts.

1. API generation:

<!-- webapi.xml automatically uses service contracts -->
<route url="/V1/posts/:id" method="GET">
    <service class="Vendor\Blog\Api\PostRepositoryInterface" method="get"/>
</route>

2. Testing:

// Mock the interface, not the implementation
$mockPost = $this->createMock(PostInterface::class);
$mockRepo = $this->createMock(PostRepositoryInterface::class);
$mockRepo->method('get')->willReturn($mockPost);

// Test against interface
$this->assertEquals($mockPost, $mockRepo->get(1));

3. Version compatibility:

// Interface remains stable across versions
// Implementation can change without breaking API

// Version 1.0
interface PostRepositoryInterface {
    get($id);
    save(PostInterface $post);
}

// Version 2.0 - same interface, new implementation
// Still works with old code

4. Third-party integration:

// Third-party modules can use your interfaces
public function processPost(
    \Vendor\Blog\Api\PostRepositoryInterface $postRepo,
    int $postId
) {
    $post = $postRepo->get($postId);
    // Process...
}

5. REST/GraphQL API:

# Service contracts automatically expose REST API
GET /rest/V1/posts/1
POST /rest/V1/posts
PUT /rest/V1/posts/1
DELETE /rest/V1/posts/1

Implementation binding:

<!-- di.xml -->
<preference for="Vendor\Blog\Api\PostRepositoryInterface"
            type="Vendor\Blog\Model\PostRepository"/>

Quiz

1. What is the main purpose of service contracts?

Question 1 options

2. Where are service contract interfaces placed?

Question 2 options

3. What does the preference element in di.xml do?

Question 3 options

4. What is a key benefit of service contracts?

Question 4 options

Flashcards

Question

What are the three service contract layers?

Answer

Data interfaces, Repository interfaces, Service interfaces

Question

Where are service contracts placed?

Answer

Module/Api/ directory

Question

What does <preference> do in di.xml?

Answer

Binds an interface to its concrete implementation

Question

Why use service contracts?

Answer

Stable API, testability, version compatibility, API generation

Question

What do data interfaces define?

Answer

Structure of data objects with get/set methods

Revision Notes

Key Takeaways

  • 1. Service contracts define stable API interfaces for modules
  • 2. Three layers: Data, Repository, Service interfaces
  • 3. Interfaces go in Api/ directory
  • 4. di.xml <preference> binds interface to implementation
  • 5. Service contracts enable REST/GraphQL API generation
  • 6. Key benefits: stability, testability, version compatibility

Interview Tips

  • Explain why service contracts are important
  • Describe the three layers of service contracts
  • Know how to create and bind interfaces
  • Discuss how service contracts enable API generation

Cheat Sheet

Service Contracts Cheat Sheet

Structure:

Api/
├── Data/
│   └── EntityInterface.php
├── EntityRepositoryInterface.php
└── EntityServiceInterface.php

Binding:

<preference for="Interface" type="Implementation"/>

Benefits:

  • Stable API
  • Testability
  • Version compatibility
  • REST/GraphQL generation

Data interface: Constants + get/set methods
Repository: get, getList, save, delete
Service: Business operations