illodev/api-platform-sdk-generator

Generate Zod schemas and typed HTTP repositories from your API Platform backend. Powered by Symfony Validator. Zero config.

Maintainers

Package info

github.com/illodev/api-platform-sdk-generator

Type:symfony-bundle

pkg:composer/illodev/api-platform-sdk-generator

Statistics

Installs: 17

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.1 2026-04-26 17:04 UTC

This package is auto-updated.

Last update: 2026-04-26 17:06:22 UTC


README

Generate Zod schemas and typed HTTP repositories from your API Platform backend. One source of truth (Symfony Validator) → typed clients in your frontend. Zero config.

Why

You already define your domain in API Platform: #[ApiResource] for endpoints, #[ApiProperty] for visibility, #[Assert\*] for validation. That metadata is the single source of truth for what your API accepts and returns.

This bundle reads that metadata and generates a TypeScript SDK against it:

  • Zod schemas (request + response) for full-stack validation.
  • Typed repositories with HTTP CRUD methods, ready to plug into TanStack Query or any data-fetching layer.
  • Resource keys (constants) usable as query keys.
  • Enums mirrored as TypeScript const objects.

No DTOs to keep in sync. No OpenAPI parser in the middle. No type loss at the boundary.

import { productRepository } from "@/sdk/repositories";
import type { ProductResponse } from "@/sdk/schemas";

const products = await productRepository.getCollection();
//    ^? GetCollectionResponse<ProductResponse>

Companion runtime — coming in v0.2.0

Generated repositories import from a thin runtime that defines Repository<TOutput, TInput>. v0.1.0 ships the generator alone: you provide the runtime (interface documented below).

v0.2.0 will publish @illodev/repository to npm — a fully typed, TanStack Query–powered runtime with Repository, useGet, useGetCollection, useSuspenseGet, usePost, usePatch, useDelete, sub-resource hooks, and more.

If you want to ship today, follow the runtime interface below. If you want to wait a week, the npm package lands soon.

Maintenance commitment

This bundle is extracted from Fube, a Spanish invoicing SaaS in production. We use it daily — bugs surface and get fixed under real-world load, not in isolation. As close to "battle-tested" as it gets without writing it yourself.

Requirements

  • PHP 8.2+
  • Symfony 6.4+ (7.x supported)
  • API Platform 4.0+

Install

composer require --dev illodev/api-platform-sdk-generator

With Symfony Flex, the bundle is auto-registered and config/packages/illodev_sdk.yaml is created with sensible defaults. Manual registration:

// config/bundles.php
return [
    // ...
    Illodev\ApiPlatformSdkGenerator\IllodevSdkBundle::class => ['dev' => true, 'test' => true],
];

Usage

bin/console illodev:sdk:generate

Schemas, repositories, keys and enums are written to the configured output path (%kernel.project_dir%/assets/sdk by default).

Configuration

# config/packages/illodev_sdk.yaml
illodev_sdk:
    output:
        path: '%kernel.project_dir%/assets/sdk'
        naming: PascalCase    # PascalCase | camelCase
    resources:
        include: ~            # null = all #[ApiResource] discovered
        exclude: []           # FQCN to exclude explicitly

What it generates

For each #[ApiResource]:

Output Path Description
Zod schemas schemas/<resource>.ts <Resource>RequestSchema, <Resource>ResponseSchema, plus z.infer types.
Repositories repositories/<resource>.repository.ts <resource>Repository = createRepository<Response, Request>(<RESOURCE_KEY>).
Resource keys schemas/keys.ts String constants usable as query keys.
Enums schemas/enums/ TypeScript const objects mirroring PHP enums.

Runtime interface

Until @illodev/repository lands in v0.2.0, generated repositories import createRepository and a Repository type from a path you control. Minimum interface:

export interface Repository<TOutput, TInput> {
  key: string;
  get(args: { identifier: string | number; uriTemplate?: string; request?: RequestInit; params?: SearchParams }): Promise<TOutput>;
  getCollection(args: { params?: SearchParams; request?: RequestInit }): Promise<GetCollectionResponse<TOutput>>;
  post(args: { data: TInput; request?: RequestInit }): Promise<TOutput>;
  postMany(args: { data: TInput[]; request?: RequestInit }): Promise<TOutput[]>;
  patch(args: { identifier: string | number; data: Partial<TInput>; request?: RequestInit }): Promise<TOutput>;
  patchMany(args: { identifiers: string[]; data: Partial<TInput>; request?: RequestInit }): Promise<TOutput[]>;
  delete(args: { identifier: string | number; request?: RequestInit }): Promise<void>;
  deleteMany(args: { identifiers: string[]; request?: RequestInit }): Promise<void>;
  // sub-resources: getSubresource, getSubresourceCollection, postSubresource
}

export interface GetCollectionResponse<T> {
  rows: T[];
  count: number;
}

export type SearchParams = Record<string, string | number | boolean | string[] | undefined>;

export function createRepository<TOutput, TInput>(key: string): Repository<TOutput, TInput>;

Reference implementation will ship as @illodev/repository in v0.2.0.

Known limitations (v0.1.0)

  • Serialization Groups (#[Groups]) are not supported. Property visibility is derived exclusively from #[ApiProperty(readable, writable)]. If your project relies heavily on groups, this bundle is not yet a fit.
  • Nested #[Assert\Collection] and #[Assert\All] for JSON columns may produce partial type extraction at deeper nesting levels. See issues tagged assert-nested for reproducible cases and workarounds.

Roadmap

  • v0.2.0@illodev/repository published to npm: full TanStack Query–powered runtime.
  • v0.3.0+ — driven by community feedback. Likely candidates: alternative schema libraries (Valibot, ArkType), Serialization Groups support if requested.

Contributing

PRs welcome. Please open an issue first describing the change. See CONTRIBUTING.md.

composer install
composer test        # PHPUnit
composer analyse     # PHPStan level 8
composer cs-check    # PHP-CS-Fixer dry-run

Sponsors

If this bundle saves you time, consider sponsoring via GitHub Sponsors (activated after v0.1.0).

License

MIT © Álvaro Jáuregui Pinto. See LICENSE.

Built with care by illodev.