madcoda/php-youtube-api
A lightweight PHP wrapper for the YouTube Data API v3 (non-OAuth) that makes it easy to fetch public video, channel, and playlist data. No third-party runtime dependencies, and it returns decoded JSON so you can follow the Google docs directly.
Architecture fit. The package is a deliberately thin, non-OAuth pass-through over YouTube Data API v3. Its design contract is "return the decoded JSON as PHP objects, so you read Google's docs instead of ours." That is a good fit for one thing only: read-only retrieval of public YouTube data (video/channel/playlist metadata, search, trending) from a PHP service. It is a poor fit for anything requiring an authenticated user context — uploads, private/unlisted video access, channel management, captions, comments-as-a-user — because the maintainer has explicitly declined to support OAuth endpoints. Architecturally it is a library, not a service: no DI container, no config abstraction, no HTTP client injection, no retry policy, no caching, no typed models. Every one of those concerns becomes ours.
Integration feasibility. High, and cheap. composer require madcoda/php-youtube-api:^1.2, an API key from Google Cloud Console, and a three-line call get you a video payload. It ships Laravel 4/5-era ServiceProvider/Facade support (namespace Madcoda\Youtube\Youtube), which is why it carries a Laravel reputation, and it has no third-party runtime dependencies beyond the cURL extension. Realistic effort to first working call: under a day. Effort to production-grade integration: roughly 1–2 weeks once you add an adapter boundary, caching, quota governance, and observability.
Technical risk. Several items need explicit sign-off before this goes near a roadmap commitment:
| Risk | Severity | Notes |
|---|---|---|
| Upstream abandonment | High | Metadata and repo docs conflict on release recency (source release notes top out around v1.2.6 / 2021; the provided metadata claims a 2026 release). Treat upstream as dormant until verified. The Travis CI badge is a further signal — Travis is effectively dead for OSS, so there is likely no running CI. |
Dependents: 0 and a low composite score |
High | 430 stars with zero observable downstream dependents means we have almost no peer evidence of production use at scale. We would be an early adopter, not a late one. |
| Schema coupling | Medium-High | Returning raw stdClass payloads pushes Google's response shape directly into controllers and views. Any Google field change surfaces as a null-property error deep in app code rather than a typed failure at a boundary. |
| No retry/backoff/rate-limit handling | Medium | We own 429/403/5xx handling, timeouts, and circuit breaking. |
| PHP 8.x compatibility unverified | Medium | Declared floor is PHP 5.3; nothing indicates testing on 8.2/8.3 (dynamic-property deprecations, cURL handle typing). Needs a spike, not an assumption. |
| Incomplete endpoint coverage | Low-Medium | The maintainer states parameters are missing because "I don't need them at this point." Plan for occasional raw-HTTP escapes. |
| Offsetting factor: tiny footprint | — | The codebase is small and dependency-free. Forking and patching is genuinely tractable, which materially reduces abandonment risk. |
Key questions.
googleapis/google-api-php-client.videos.list = 1 unit for up to 50 IDs)? At the default 10,000 units/day, a naïve search-driven UI supports ~100 requests/day.Stack fit. Native PHP/Composer; runs as a plain class or via the bundled Laravel facade. Note the API surface is Madcoda\Youtube\Youtube with methods like getVideoInfo($id) — several published examples in the README and third-party write-ups use a fluent search()->popular() style that does not match this package's actual v1.x API. Validate method signatures against the wiki before writing code; do not trust copy-pasted snippets.
Recommended architecture: wrap it, don't call it. Put an application-owned port in front of the library and treat madcoda as a swappable adapter:
App\Contracts\YouTubeGateway (interface; returns app-owned DTOs)
└─ App\YouTube\MadcodaAdapter (maps stdClass → VideoData, ChannelData)
└─ App\YouTube\GoogleClientAdapter (drop-in alternative)
This is the single most important decision here. It converts an upstream-abandonment risk into a routine adapter swap, contains Google's schema, and gives you one place to cache, retry, log, and meter quota.
Compatibility and configuration.
composer.json; commit the lockfile. Do not allow ^1.2 to float if the repo is dormant and unpredictable.config/services.php sourced from YOUTUBE_API_KEY; support a key rotation list so a revoked key is a config change, not a deploy.FakeYouTubeGateway bound in the test container so feature tests never hit Google.Migration path (if replacing an ad-hoc cURL call).
YouTubeGateway and implement it over the existing code. No behavior change.MadcodaAdapter and run it in shadow mode against a sample of real IDs; diff outputs against the incumbent.Sequencing.
| Phase | Duration | Deliverable | Exit gate |
|---|---|---|---|
| 0. Spike | 2–3 days | Key provisioned; PHP 8.x + target Laravel install; 5 representative calls (video, channel, playlist items, search, trending) | Library instantiates cleanly and returns expected payloads; go/no-go on the fork question |
| 1. Adapter | ~1 week | YouTubeGateway contract + DTOs + MadcodaAdapter + fake for tests |
Feature code has zero direct references to Madcoda\Youtube |
| 2. Pilot | ~1 week | One non-critical, read-only surface (e.g. "related videos" or an internal metadata dashboard) behind a flag | Error rate and p95 latency measured against baseline |
| 3. Hardening | ~1 week | Cache layer, retry/backoff, quota meter and daily alarm, structured logging | Quota consumption forecast documented; alerts fire in staging |
| 4. Decision review | 1 day | Build-vs-buy memo: stay, fork, or migrate to googleapis/google-api-php-client |
Named owner and maintenance policy recorded |
Do not skip Phase 0's compatibility check — the declared PHP floor of 5.3 tells you nothing about whether it runs warning-free on 8.3.
Maintenance. Assume we own this code. Plan for a fork under our org with a documented patch policy: security fixes and breaking Google changes only, no feature work. The small, dependency-free codebase makes this genuinely viable — realistically a few hours per quarter plus unplanned work when Google changes a response shape or deprecates an endpoint. Track Google's YouTube Data API release notes on a recurring calendar item; subscribe the owning team. Budget for one PHP-major-upgrade cycle per year to confirm the fork still runs.
Support. There is no vendor. Issue triage happens on the upstream GitHub repo, which is quiet-to-dormant; Google's own developer support is the practical escalation path for API-level problems, not for library-level problems. Build internal documentation covering: how to rotate the API key, how quota is consumed per endpoint, the difference between 403 quotaExceeded / 403 keyInvalid / 403 forbidden, and the standard "empty items array with HTTP 200" case — that last one produces the majority of false "video deleted" bug reports. Assign a named tech lead as owner for YouTube-API-related incidents.
Scaling. Quota, not compute, is the binding constraint. Every design decision should be evaluated in units:
videos.list, channels.list, playlistItems.list cost 1 unit per call; videos.list accepts up to 50 IDs per call — batch aggressively.search.list costs 100 units — 100× a metadata read. Never put search.list on a synchronous user-facing path.playlistItems.list on the uploads playlist, not search.list.Layer caching by data volatility: trending/popular ~5–15 minutes; video metadata 6–24 hours; channel metadata 24 hours. Push fan-out and bulk backfills through a queue with a rate limiter, not the request cycle. Persist what you fetch (youtube_id indexed) so repeat views cost zero units. Add a quota consumption metric with a daily threshold alarm at 70% and 90%.
Failure modes.
| Failure | Symptom | Impact | Mitigation |
|---|---|---|---|
| Quota exhausted | 403 quotaExceeded across all calls |
All YouTube features dark until midnight PT reset | Quota meter, daily alarm, cache-first reads, degraded UI, optional multi-key/second-project rotation |
| Key revoked or misconfigured | 403 keyInvalid / 400 |
Total outage | IP-restricted keys, key rotation list in config, synthetic canary check every 15 min |
| Google 5xx or timeout | Slow or failed calls | Latency creep, cascading timeouts | Aggressive cURL timeouts, bounded retries with exponential backoff + jitter, circuit breaker, cache-served stale fallback |
| Response schema drift | Null property errors deep in controllers | Silent wrong data, hard-to-trace exceptions | Adapter DTOs with explicit null handling; contract test on a fixed set of known IDs in CI |
Empty items at HTTP 200 |
"No results" rendered as fact | Wrong UX conclusions, bad analytics | Explicit empty-result branch in adapter; distinguish not-found from not-returned |
| Package abandoned / PHP break | Install or runtime failures | Blocks framework upgrades | Version pin, vendored fork under our org, contract tests in CI |
| Region/embargo restrictions | Partial or missing results | Feature appears broken in some markets | Document expected gaps; don't surface as errors |
Ramp-up. A competent Laravel developer is productive in 1–2 days on the library API itself — it is small and the surface mirrors Google's docs. The real ramp is quota economics and caching discipline, which is not in the package's documentation at all: expect 3–5 days of team learning before anyone designs a feature against it unaided. Onboarding artifact should be a one-page internal guide covering adapter usage, quota cost per endpoint, cache TTL table, and the error-code runbook. No formal training, no certification, no platform-team dependency — this is the package's strongest operational property.
How can I help you explore Laravel packages today?