Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Api Modeller Bundle Laravel Package

fabricio872/api-modeller-bundle

API Modeller Bundle is a Symfony package for defining and generating API models from your application's entities and schemas. It aims to streamline endpoint scaffolding and keep request/response structures consistent. Early-stage with limited documentation and adoption, so evaluate fit carefully.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal path to first working call:

composer require fabricio872/api-modeller-bundle
  1. Register the bundle. With zero stars and a 2022 last release, Flex has no recipe, so expect to add it manually in config/bundles.php:

    Fabricio872\ApiModellerBundle\ApiModellerBundle::class => ['all' => true],
    
  2. Read the config tree before writing YAML. There is essentially no upstream documentation, so the authoritative source is vendor/fabricio872/api-modeller-bundle/src/DependencyInjection/Configuration.php. Copy the node names from there into config/packages/api_modeller.yaml (base URL, HTTP client service, default headers, etc.). Then verify what actually got wired with:

    bin/console debug:config api_modeller   # node name comes from getAlias() in the Extension
    bin/console debug:container --show-private | grep -i modell
    
  3. Look at these directories first, in this order:

    • src/Attribute/ or src/Annotation/ — this is where the "Doctrine-like" mapping lives (the attributes you put on model classes to describe the foreign field/endpoint).
    • src/DependencyInjection/ — the service wiring and config keys.
    • src/Model/ / src/Factory/ / src/Hydrator/ — the runtime that turns a JSON payload into a typed object.
  4. First use case: map one read-only list endpoint. Pick the simplest foreign resource you consume (a users list, a catalogue index) and model only the fields you actually use for that one screen. Create a plain PHP class, annotate it per src/Attribute/, drop the bundle's factory/modeller service into a controller or a small wrapper service, and call it. Do not start with a POST/PUT endpoint — the package is fundamentally a read-side mapper.

// verify attribute names against src/Attribute/ before trusting this
#[ApiModel(endpoint: '/v1/users', client: 'foreign_api')]
class ForeignUser
{
    #[ApiProperty(name: 'id')]
    public int $id;

    #[ApiProperty(name: 'first_name')]
    public string $firstName;
}

The win is that everything downstream of the fetch works with typed properties and your IDE understands them, instead of array<string, mixed>.

Implementation Patterns

Wrap the bundle behind your own repository service. Never inject the bundle's hydrator/factory directly into controllers. Because the package is unmaintained, you want one seam to change when you eventually replace it:

final class ForeignUserRepository
{
    public function __construct(private ModelFactory $factory) {}

    /** @return ForeignUser[] */
    public function all(): array
    {
        return $this->factory->createMany(ForeignUser::class);
    }
}

Then ForeignUserRepository is the only place that imports a Fabricio872\ namespace.

Treat mapped models as DTOs, not entities. The name says "Doctrine-like", but nothing here persists. Hydrate the foreign model, then map it into your own domain object or entity in an application-layer mapper. This keeps foreign field naming (first_name, createdAt in epoch seconds) out of your templates, forms, and persistence layer, and means a change in the third-party API is a one-file diff.

Split models per endpoint, not per resource. Foreign APIs almost always return different shapes for list vs. detail vs. search. A single "User" model with half its properties nullable is a debugging trap. Define UserListItem and UserDetail separately — the bundle's mapping is declarative, so duplication costs you little and the nullable noise disappears.

Reuse one Symfony HttpClient for the whole foreign API. Configure it once with base_uri, auth headers, retry_failed, and a timeout in config/packages/framework.yaml under http_client, then point the bundle at that client via config. Retries, rate limiting, and logging belong at the transport layer, not in the modeller.

Cache aggressively. These are remote calls on the render path. Put a Symfony cache decorator around your repository service (cache.app with a short TTL for volatile data, cache.app with tags for reference data) so the modeller only runs on a miss. Cache the domain objects, not the raw arrays — you then serialize domain objects, and the bundle stays out of the hot path.

Test with MockHttpClient. Because the mapping is attribute-driven, unit tests that mock the HTTP layer are cheap and fast:

$client = new MockHttpClient(new JsonResponse('[{"id":1,"first_name":"Ada"}]'));
// inject $client, assert $repo->all()[0]->firstName === 'Ada'

This is also your best tool for pinning down what the bundle does with edge payloads, given the missing docs.

Handle pagination explicitly. Expect the bundle to fetch and hydrate one page. Loop over pages in your repository, or use Symfony's HttpClient paginator-style pattern manually — do not assume the bundle follows next links for you.

Gotchas and Tips

  • It is effectively abandoned. Last release June 2022, zero stars, zero dependents. Audit it before adopting: composer show -D fabricio872/api-modeller-bundle and read every file in src/ — it is small enough to read in an hour, and you should, because you will be the maintainer. If it earns its place, consider vendoring or forking it under your own namespace so a future PHP/Symfony bump is a merge you control.
  • Symfony version compatibility is the biggest risk. A 2022 release was built against Symfony 5.4/6.0-era APIs. Expect friction on 6.4/7.x: removed ContainerBuilder methods, ParameterBagInterface changes, and the Doctrine annotations → PHP attributes migration. If the attributes are actually doctrine/annotations, that package is deprecated and will break silently on PHP 8.2+ when annotations are disabled — check src/Attribute/ vs src/Annotation/ on day one.
  • No docs means no contract. Never assume the config schema, service IDs, or exception types. Confirm each with debug:container and debug:config before writing code against them. Pin the exact version in composer.json (e.g. "fabricio872/api-modeller-bundle": "1.0.*") so a stray patch release can't reshape hydration behaviour.
  • Hydration of missing or unexpected keys is the classic failure mode. Foreign APIs love to omit null fields or return "" where you declared ?int. Write one test per edge case (missing key, null, wrong scalar type, empty collection, extra unknown key) before wiring it into a feature; the bundle's error messages will otherwise surface as a generic exception deep inside a controller.
  • Type coercion is silent and dangerous. If id comes back as a string and your property is int, whether that throws or coerces depends on the hydrator implementation. Do not rely on it — declare properties as the type the API actually returns, and cast in your domain mapper.
  • Nested objects and collections are usually shallow. If a payload embeds {"company": {...}}, check whether the bundle recurses into a nested model class or leaves it as an array. If it's the latter, map the nested shape in your repository layer rather than fighting the modeller.
  • Debugging tips. bin/console debug:container --tag=<any tag found in the bundle's services.xml> reveals the extension points; bin/console lint:container catches wiring errors early. When a request fails, dump the raw response from the HTTP client profile in the Symfony web debug toolbar — the modeller's own exceptions rarely include the payload, and the profiler does.
  • Extension points, if any exist, live in the DI definitions. Look for tagged services (a hydrator/transformer/normalizer tag) in Resources/config/services.xml (or config/services.php). The realistic extension points are (a) decorating the hydrator service with your own, and (b) supplying a different HTTP client — both are safe. Editing vendor files is not.
  • Error handling is on you. Non-2xx responses, HTML error pages, and empty bodies probably aren't turned into distinct exception types. Wrap repository calls in your own exception and check $response->getStatusCode() yourself if the bundle doesn't.
  • Don't let it leak. No Fabricio872\ class names in controllers, templates, form types, or — critically — in doctrine mapping. Keeping the boundary at one repository class means the eventual replacement is a refactor of one file, not a codebase-wide hunt.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib