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 Client Bundle Laravel Package

realestateconz/api-client-bundle

An API client bundle for realestate.co.nz that simplifies connecting PHP applications to property listing data. It provides configuration and request handling for querying real estate listings and related resources with less boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first: this is a Symfony bundle, not a Laravel package. There is no service provider, no facade, no config/*.php publish tag. A Laravel developer's fastest path is almost always to depend on the underlying realestateconz/api-client library directly and wire it by hand in a service provider, rather than trying to make Symfony's DI container and bundle bootstrapping cooperate with Laravel's container. Treat the bundle as reference documentation for how the client is meant to be configured.

If you are actually in a Symfony app:

composer require realestateconz/api-client-bundle
  1. Register the bundle in config/bundles.php:
    RealestateConz\ApiClientBundle\RealestateConzApiClientBundle::class => ['all' => true],
    
  2. Look first at the bundle's DependencyInjection/Configuration.php and Extension.php (or the README's config block). That file is the authoritative list of what is configurable — base URI, API key/credentials, HTTP client, timeouts, serializer settings. Everything you need to know about the package's surface area is there.
  3. Configure credentials from environment variables, never hardcoded:
    # config/packages/realestate_conz_api_client.yaml
    realestate_conz_api_client:
        api_key: '%env(REALESTATE_API_KEY)%'
    
  4. Inject and call — the bundle's job is to register one or two autowirable services. Type-hint the client interface in a controller or console command and issue your first read (listings/search) to confirm auth works.

First use case: a single read-only integration — pull a page of listings into a local table or a debug route — before touching writes, pagination, or caching. You want to validate key/auth/base-URI correctness in isolation.

Implementation Patterns

Wrap it, don't scatter it (Laravel). Because you're bypassing the bundle, register the underlying client as a singleton in a dedicated service provider and inject an interface, not the concrete client:

// app/Providers/RealestateServiceProvider.php
$this->app->singleton(RealestateClient::class, fn ($app) => new RealestateClient(
    apiKey: config('services.realestate.key'),
    httpClient: $app->make(GuzzleHttp\Client::class),
));

Bind RealestateClient to your own thin PropertyRepository interface so application code never sees vendor types. This is the single most valuable pattern: it lets you swap the client, mock it, and insulate yourself from this package's low maintenance cadence.

Adapter/repository layer for API shape. Put request building, pagination params, and response → domain-model mapping in one class:

final class RealestateRepository implements PropertyRepository
{
    public function search(SearchCriteria $c): PropertyPage
    {
        $response = $this->client->listings($c->toQuery());
        return PropertyPage::fromApi($response); // your DTO, not theirs
    }
}

Job-per-page for bulk sync. Realestate.co.nz listings are paginated. Model sync as queued jobs — one job per page — with RateLimited middleware, rather than a loop inside a single job. This gives you retries, backoff, and horizontal scaling for free:

RateLimited::for('realestate')->allow(10)->every(60)

Cache aggressively on reads. Listing data changes on the order of hours, not seconds. Wrap read calls in Cache::remember keyed by normalized query + page. It cuts quota usage dramatically and makes local development pleasant.

HTTP-level testing. Do not mock your own repository to test the integration; mock at the HTTP boundary with Http::fake() (or Guzzle's MockHandler) and assert on the outgoing request URI/params. Assert your adapter maps a fixture response correctly. Snapshot a couple of real API responses into tests/Fixtures/ early — the API's payload shape is the thing most likely to silently drift.

Config as a first-class boundary. Put base URL, key, timeout, and page size in config/services.php, sourced from .env. Never read env() outside config files (breaks under config:cache).

Symfony-side integration tips (if applicable): inject the registered client service rather than constructing it; use framework.http_client with a scoped client for timeouts/retries; add a kernel.exception listener or middleware for API error → domain exception translation.

Gotchas and Tips

  • Symfony/Laravel impedance mismatch is the headline gotcha. Installing the bundle in a Laravel app adds an unused Symfony dependency tree and does nothing at runtime. Pull in the base client package instead.
  • Zero stars, zero dependents, unspecified maintenance. Pin it in composer.json to an exact version, commit composer.lock, and read the source before relying on it in production. Budget for vendoring or rewriting the thin client if it goes stale. The risk is not the code — it's that nobody else will report the bug you hit.
  • Credentials are not in the repo's example config. You must obtain an API key/agreement from Realestate.co.nz directly; this is a partner API. Expect onboarding friction and possibly IP allowlisting — which will bite you the moment you deploy to a platform with egress IPs that rotate (serverless, some PaaS).
  • Configuration loading order. In Symfony, bundle extension config is only available after the bundle is registered and the config file is in a loaded path — a silently-missing YAML file surfaces as a missing-service error, not a config error. In Laravel, the analogous trap is env() returning null after config:cache.
  • Base URI / environment confusion. Partner APIs often have distinct sandbox and production hosts. Confirm which one the bundle defaults to; do not assume the default is production-safe.
  • Error semantics. HTTP 4xx from these APIs often carries a structured error body, not just a status. Parse and surface it — a generic RequestException message will make debugging auth and parameter errors painful. Wrap in a domain exception early.
  • Timeouts and retries belong at the HTTP client level, not in your application code. Set a connect timeout (~5s) distinct from a read timeout (~15–30s) and only retry idempotent GETs.
  • Extension points, if you need them: the bundle's most useful seam is the injected HTTP client — replacing it with one carrying a logger/middleware gives you request tracing without forking. If the library exposes a serializer or response factory, that's the second seam for adapting to your DTOs.
  • Don't let vendor types leak into controllers, models, or Blade views. Every vendor-type reference outside the adapter is a place a breaking change makes you edit dozens of files.
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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource