PHP code example of baraja-core / structured-api

1. Go to this page and download the library: Download baraja-core/structured-api library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

baraja-core / structured-api example snippets




declare(strict_types=1);

namespace App\Api;

use Baraja\StructuredApi\BaseEndpoint;

final class ArticleEndpoint extends BaseEndpoint
{
    public function __construct(
        private ArticleRepository $articleRepository,
    ) {
    }

    public function actionDefault(): array
    {
        return [
            'articles' => $this->articleRepository->findAll(),
        ];
    }

    public function actionDetail(int $id): ArticleResponse
    {
        $article = $this->articleRepository->find($id);

        return new ArticleResponse(
            id: $article->getId(),
            title: $article->getTitle(),
            content: $article->getContent(),
        );
    }
}



declare(strict_types=1);

namespace App\Api\DTO;

final class ArticleResponse
{
    public function __construct(
        public int $id,
        public string $title,
        public string $content,
        public ?\DateTimeInterface $publishedAt = null,
    ) {
    }
}

final class UserEndpoint extends BaseEndpoint
{
    // GET /api/v1/user
    public function actionDefault(): array { }

    // GET /api/v1/user (alternative)
    public function getDefault(): array { }

    // GET /api/v1/user/detail?id=1
    public function actionDetail(int $id): UserResponse { }

    // POST /api/v1/user/create
    public function postCreate(string $name, string $email): UserResponse { }

    // POST /api/v1/user/create (alias)
    public function createCreate(string $name, string $email): UserResponse { }

    // PUT /api/v1/user/update
    public function putUpdate(int $id, string $name): UserResponse { }

    // PUT /api/v1/user/update (alias)
    public function updateUpdate(int $id, string $name): UserResponse { }

    // DELETE /api/v1/user/delete
    public function deleteDelete(int $id): void { }
}

final class ArticleEndpoint extends BaseEndpoint
{
    /**
     * @param string|null $locale in format "cs" or "en"
     * @param int $page real page number, 1 = first page
     * @param int $limit in interval <1, 500>
     */
    public function actionDefault(
        ?string $locale = null,
        int $page = 1,
        int $limit = 32,
        ?string $status = null,
        ?string $query = null,
        ?\DateTimeInterface $filterFrom = null,
        ?\DateTimeInterface $filterTo = null,
        ?string $sort = null,
        ?string $orderBy = null,
    ): ArticleListResponse {
        // All parameters are validated and properly typed
    }
}

public function postProcessOrder(array $data): OrderResponse
{
    // $data contains all raw POST data from the request
}

public function actionDetail(int $id): void
{
    $this->sendJson([
        'id' => $id,
        'title' => 'My Article',
        'content' => '...',
    ]);
}

public function postCreate(string $title): void
{
    $article = $this->repository->create($title);

    $this->sendOk(
        data: ['id' => $article->getId()],
        message: 'Article created successfully',
    );
}

public function actionDetail(int $id): void
{
    $article = $this->repository->find($id);

    if ($article === null) {
        $this->sendError(
            message: 'Article not found',
            code: 404,
            hint: 'Check if the article ID is correct',
        );
    }

    // ...
}

public function actionDefault(int $page = 1): void
{
    $items = $this->repository->findPage($page);
    $paginator = $this->repository->getPaginator();

    $this->sendItems($items, $paginator, [
        'totalCount' => $paginator->getTotalCount(),
    ]);
}

public function actionDetail(int $id): ArticleResponse
{
    $article = $this->repository->find($id);

    return new ArticleResponse(
        id: $article->getId(),
        title: $article->getTitle(),
        content: $article->getContent(),
    );
}

public function postUpdate(int $id, string $title): ArticleResponse
{
    $article = $this->repository->update($id, $title);

    $this->flashMessage('Article updated successfully', self::FlashMessageSuccess);
    $this->flashMessage('Remember to publish your changes', self::FlashMessageInfo);

    return new ArticleResponse($article);
}

use Baraja\StructuredApi\Attributes\PublicEndpoint;

#[PublicEndpoint]
final class ProductEndpoint extends BaseEndpoint
{
    public function actionDefault(): array
    {
        // Accessible without authentication
    }
}

use Baraja\StructuredApi\Attributes\Role;

#[Role(roles: ['admin', 'moderator'])]
final class ArticleEndpoint extends BaseEndpoint
{
    // Only admin or moderator can access any method
}

#[PublicEndpoint]
final class ArticleEndpoint extends BaseEndpoint
{
    public function actionDefault(): array
    {
        // Public access
    }

    #[Role(roles: 'admin')]
    public function actionDelete(int $id): void
    {
        // Only admin can delete
    }

    #[Role(roles: ['admin', 'editor'])]
    public function postCreate(string $title): ArticleResponse
    {
        // Admin or editor can create
    }
}

$convention = $container->getByType(Convention::class);
$convention->setIgnoreDefaultPermission(true);

$convention = $container->getByType(Convention::class);

// Date/time format for serialization (default: 'Y-m-d H:i:s')
$convention->setDateTimeFormat('c'); // ISO 8601

// Default HTTP codes
$convention->setDefaultErrorCode(500);
$convention->setDefaultOkCode(200);

// Remove null values from response to reduce payload size
$convention->setRewriteNullToUndefined(true);

// Keys to hide from response (sensitive data)
$convention->setKeysToHide([
    'password', 'passwd', 'pass', 'pwd',
    'creditcard', 'credit card', 'cc', 'pin',
    'secret', 'token',
]);

// Use __toString() method when serializing objects
$convention->setRewriteTooStringMethod(true);

use Baraja\StructuredApi\Middleware\MatchExtension;
use Baraja\StructuredApi\Endpoint;
use Baraja\StructuredApi\Response;

final class RateLimitExtension implements MatchExtension
{
    public function beforeProcess(
        Endpoint $endpoint,
        array $params,
        string $action,
        string $method,
    ): ?Response {
        if ($this->isRateLimited()) {
            return new JsonResponse($this->convention, [
                'state' => 'error',
                'message' => 'Rate limit exceeded',
            ], 429);
        }

        return null; // Continue processing
    }

    public function afterProcess(
        Endpoint $endpoint,
        array $params,
        ?Response $response,
    ): ?Response {
        // Modify or replace response after processing
        return null; // Use original response
    }
}

$apiManager = $container->getByType(ApiManager::class);
$apiManager->addMatchExtension(new RateLimitExtension());

$apiManager = $container->getByType(ApiManager::class);

// Get response as array
$result = $apiManager->get('article/detail', ['id' => 123]);

// With explicit HTTP method
$result = $apiManager->get('article/create', ['title' => 'New'], 'POST');

// The path is automatically prefixed with 'api/v1/' if not present
$result = $apiManager->get('api/v1/article/detail', ['id' => 123]);

final class ProfileEndpoint extends BaseEndpoint
{
    public function actionDefault(): UserResponse
    {
        // Check if user is logged in
        if (!$this->isUserLoggedIn()) {
            $this->sendError('Not authenticated', 401);
        }

        // Get current user
        $user = $this->getUser();

        // Get user identity entity
        $identity = $this->getUserEntity();

        return new UserResponse($identity);
    }
}

final class ArticleEndpoint extends BaseEndpoint
{
    public function actionDetail(int $id): ArticleResponse
    {
        $article = $this->repository->find($id);

        return new ArticleResponse(
            id: $article->getId(),
            title: $article->getTitle(),
            editUrl: $this->link('Admin:Article:edit', ['id' => $id]),
            viewUrl: $this->linkSafe('Front:Article:detail', ['slug' => $article->getSlug()]),
        );
    }
}
json
{
    "result": "PONG",
    "ip": "127.0.0.1",
    "datetime": "2024-01-15 10:30:00"
}