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

Icobench Client Laravel Package

kami/icobench-client

A PHP client for the ICOBench API that wraps endpoints for ICO listings, ratings, and related data in a simple, framework-friendly interface for Laravel and standalone PHP applications, helping streamline integration of ICOBench data into your projects.

View on GitHub
Deep Wiki
Context7

Getting Started

Before you write a line of application code, spend ten minutes reading the repo rather than trusting the README. Open composer.json first: confirm the PSR-4 namespace, the PHP constraint, and the Laravel/Guzzle version pins — those three lines tell you whether the package will even install on your stack. Then skim src/ alongside the README, because in a package this small the source is the documentation. Everything is likely a handful of files: a service provider, a facade, a client class, and a config stub.

Install into a throwaway branch, not main:

composer require kami/icobench-client
php artisan vendor:publish --provider="KamiLabs\ICOBench\ICOBenchServiceProvider"

The publish step tells you what the package expects: config file name, env variable names, and whether it registers a facade alias. Expect keys like ICOBENCH_PUBLIC_KEY and ICOBENCH_PRIVATE_KEY sourced from icobench.com/developers. Verify they actually land in config('icobench.*') — 2018-era packages are inconsistent about whether config is read at boot or per-call.

Your first use case should be the narrowest one: fetch a single ICO by ID and inspect the raw response.

$ico = ICOBench::ico($id);
dump($ico); // array? DTO? Guzzle response? Find out before designing around it.

Do that before building anything else, because the return type drives every downstream decision (DTO vs. array vs. ResponseInterface).

Critically: treat step one as connectivity validation, not library validation. ICOBench has been offline for years. Run a plain curl or Http::get() against the API host before blaming the package for a timeout. If DNS fails or the domain is parked, the package is functioning correctly and there is simply nothing to talk to — at which point your only viable path is mocking the transport locally or forking the client to point at an archived dataset you control.

Implementation Patterns

Never call the facade from controllers or Blade. Wrap it immediately in a repository/gateway class so the dead upstream is isolated to one file you can gut later:

class IcoRepository
{
    public function __construct(private ICOBench $client) {}

    public function find(int $id): ?IcoData
    {
        try {
            $raw = $this->client->ico($id);
        } catch (\Throwable $e) {
            report($e);
            return null;
        }

        return $raw ? IcoData::fromArray($raw) : null;
    }
}

Hydrate into DTOs (or Eloquent models) at the boundary. Raw arrays from a 2018 client will have inconsistent key casing and missing fields; pin the shape once in a fromArray() factory and let everything downstream depend on the DTO, not the vendor payload.

Cache at the repository boundary, not inside the client. Market/rating data tolerates stubble — 5 to 15 minutes is normal. Cache::remember() in the repository means you can bypass it deliberately for freshness-sensitive paths, and it means a dead API degrades to "stale data" rather than "500 page":

return Cache::remember("ico:{$id}", now()->addMinutes(10), fn () => $this->find($id));

Prefer a scheduled ingestion job over live calls. The most defensible day-to-day pattern for a vendor like this is a one-way pipeline: a queued SyncIcoRatings command pulls pages on a schedule and writes to a local icos table. All user-facing reads hit your database. The package becomes an ingestion tool, not a request-path dependency — which is also the only way an unreliable upstream can be tolerated at all.

Pagination is yours to handle. Thin wrappers of this vintage rarely abstract cursors. Expect limit/offset or page query params passed straight through, and write the loop yourself with a hard page cap so a misbehaving endpoint can't spin forever.

Mock the transport in tests from day one. Inject a Guzzle MockHandler (or bind a fake ClientInterface) via the container so CI never touches the network:

$this->app->bind(ClientInterface::class, fn () => new Client([
    'handler' => HandlerStack::create(new MockHandler([$fixtureResponse])),
]));

Commit a handful of real captured JSON fixtures while you still have them; when the API is gone these are your only ground truth.

Override the base URI if the config allows it. Publish the config and look for base_uri / endpoint. If it's there, you can point the client at a local mock server (WireMock, httpbin, a static JSON server) and develop the whole feature without the real vendor. If it's hardcoded in the client class, fork — it's a two-line change and it unlocks local development.

Gotchas and Tips

The upstream is dead, and that is the whole story. No amount of debugging fixes a defunct endpoint. Confirm with curl -I https://api.icobench.com before opening an issue with yourself. Everything else below assumes you've decided to proceed anyway (archival work, mock server, or a fork pointed elsewhere).

Version compatibility is the first real blocker, not the API. The 2018 release targets Laravel 5.5/5.6, PHP 7.0–7.1, and Guzzle 6. On Laravel 10/11 you'll hit Composer resolution failures or need --ignore-platform-reqs, which then produces runtime breakage. On PHP 8 expect Guzzle ^6 to conflict with anything requiring ^7. In practice a fork that bumps PHP to ^8.0, Guzzle to ^7.0, and refreshes the service provider is faster than fighting the pinned artifact — and there is no upstream to accept that PR, so plan for it as a vendored dependency under your own namespace.

Facade aliasing changed. If the package relies on config/app.php aliases registration rather than package auto-discovery, it will silently not resolve on Laravel 5.5+. If ICOBench:: throws "class not found", check composer.json for extra.laravel.providers — if it's absent, register the provider and alias manually in config/app.php.

Auth is a signature scheme, not a bearer token. ICOBench used a public/private key pair with an SHA-hashed signature over the request. A 401 almost always means key ordering, hashing algorithm, or timestamp skew — not a wrong key. Dump the exact string being signed and compare it against the API docs' example; these schemes are unforgiving about whitespace and parameter ordering.

Errors may not be surfaced cleanly. A 2018 wrapper may return null, return the raw Guzzle response, or let RequestException bubble. Check the client source for http_errors. Wrap every call site in try/catch and translate to a domain exception — don't let a dead vendor's stack trace reach a controller.

Silent staleness is worse than an outage. If any layer caches these responses (Laravel cache, a CDN, your own DB sync), data can freeze at whatever state it was in when the API died. Stamp every synced record with fetched_at and render an "as of" date in the UI. Never label archived ratings as live.

There are no tests, no CI, and zero dependents. You are the only person who has ever run this code in anger. Read every line of src/ before shipping — it's small enough to do in fifteen minutes — and budget for owning it permanently or replacing it quickly.

When you're ready to leave, leave. The migration is short: point the repository at a maintained provider (CoinGecko, CoinMarketCap, CryptoCompare all have current clients or trivial REST surfaces), keep the same IcoData DTO and repository interface, and delete the package. Because you isolated it behind one class on day one, this is a one-file change — that's the entire payoff of the pattern above.

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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin