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

Laravel Api Laravel Package

joselfonseca/laravel-api

A Laravel package for building JSON APIs with reusable controllers, resources, response helpers, and consistent error handling. It reduces boilerplate and helps keep API endpoints structured and predictable.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a project skeleton, not a composer require-able library. You consume it by generating a fresh app from it, so the first decision is whether the tag's framework line is one you can live with.

As of V12.0.0 the skeleton targets Laravel 9 (bumped from the Laravel 8 line in 11.x) and therefore requires PHP 8.0+. That's the substantive change in this release — there are no new features, no new endpoints, and no changes to the Dingo/Fractal/JWT architecture. The repo remains archived and unmaintained; V12 is a compatibility bump, not a revival. Laravel 9 itself is already past its security-fix window, so this is still an architecture reference first and a foundation second.

Minimal path:

  1. Check the tag's laravel/framework / php constraints in composer.json before composer create-project — the install fails hard on a mismatch, and V12 raises the floor to PHP 8.0.
  2. composer create-project joselfonseca/laravel-api my-api V12.0.0 — pin the tag explicitly rather than dev-master, and pin V12.0.0 specifically if you're on PHP 8.0+ (11.x is Laravel 8 / PHP 7.3+).
  3. .env from .env.example, set DB credentials, then php artisan key:generate.
  4. Generate the JWT signing secret — the app uses tymon/jwt-auth, and without it every login/token call throws a "secret not set"-class error: php artisan jwt:secret.
  5. php artisan migrate --seed, then php artisan serve (or the bundled Docker setup if present).
  6. Dump the actual route table with php artisan api:routes, not route:list — routes are registered through Dingo, and Laravel's own lister still won't show them on Laravel 9 either.

Where to look first, in this order:

  • The Dingo route file (routes/api.php or app/Api/routes.php) — a $api->version('v1', function ($api) { ... }) block that defines prefix, middleware, and throttling.
  • config/api.php — prefix, version, standardsTree, subtype, and the error-format settings. These, not your routes, determine the final URL shape.
  • The auth controller and the Exception handler — this is where JWT issuing and API error responses live.
  • app/Transformers and app/Http/Requests — the response-shaping and validation layers you'll extend daily.

First use case: exercise the full stack end-to-end before writing any code. Seed a user, POST to the login endpoint, copy the token out of the JSON, and call a protected endpoint with Authorization: Bearer <token> plus Accept: application/json. That single loop validates routing, versioning, JWT config, middleware, transformer output, and exception formatting all at once. Endpoint paths drift between tags, so confirm them from api:routes rather than trusting the README.

Implementation Patterns

The core unit of work is a four-file vertical slice. For any new resource, the intended flow is: a FormRequest for validation → a controller method → a Fractal transformer → a response built with Dingo's $this->response->item(...) / ->collection(...) / ->paginator(...) via the Dingo\Api\Routing\Helpers trait. Keep controllers thin; anything past validation and response assembly belongs in a service or repository, otherwise the slice becomes the whole app.

Versioning is per-group, not per-file. Add $api->version('v2', [...]) alongside the v1 block and give it its own namespace and its own transformers. Never mutate a shipped transformer to add fields for a new client — that's a silent breaking change for v1 consumers. Copy the transformer, extend it, and let the version group pick which one to resolve.

Transformers carry the relationship contract. Use $defaultIncludes for cheap, always-present relations and includeX() methods for everything else, so clients opt in with ?include=comments,author. This is the single biggest ergonomic win in the kit and the part most worth preserving if you later migrate off Fractal.

Auth pattern: login returns a JWT, the client stores it, protected routes sit behind the Dingo auth middleware, and a refresh endpoint issues a new token from a still-valid one. Read the authenticated user through the API guard (auth('api')->user()), not the default guard — mixing them is the most common source of confusing "user is null but I'm authenticated" bugs.

Throttling and errors belong at the group level. Apply the throttle middleware to the $api->version() group so new routes inherit it, and standardize error output with Dingo's $this->response->errorNotFound() / errorUnprocessableEntity() helpers rather than ad-hoc response()->json(['error' => ...]). Consistent error envelopes matter more for APIs than for web apps, and the kit's whole value proposition is that consistency.

Testing: always set Accept: application/json and any version headers in test requests. Dingo's exception handling and content negotiation key off those headers, so a test that passes in the browser can fail under $this->json() if the headers differ.

Upgrading an existing 11.x app to V12: treat it as a hard-cut major. Because the bump moves Laravel 8 → 9 and drags the transitive stack (Symfony Mailer replacing SwiftMailer, tymon/jwt-auth 2.x, Dingo API's Laravel 9 branch) forward with it, budget for the framework's own 8→9 upgrade guide alongside this skeleton's changes. Diff composer.json and config/api.php between the two tags first — they tell you more about what you'll need to reconcile than the release notes do.

Gotchas and Tips

  • Archived and still unmaintained after V12. The release is a Laravel 9 compatibility bump plus StyleCI formatting; it is not a sign of renewed stewardship. Laravel 9 is itself out of security support, so even the newest tag is behind. Treat this as an architecture reference: read it for the request/transformer/versioning discipline, then implement that natively with Sanctum, routes/api.php route groups, and API Resources. If you're inheriting an app built on it, budget for a migration rather than a rewrite.
  • The V12 bump is the breaking change. If you were pinned to 11.x on PHP 7.3/7.4, you cannot cherry-pick this — PHP 8.0 and Laravel 9 arrive together. Plan the PHP upgrade and the framework upgrade as one unit of work, not two.
  • StyleCI commits create diff noise. V12 includes purely cosmetic style fixes across the codebase. If you maintain a downstream fork, either replay those commits first or expect your next rebase to conflict on formatting-only hunks. Don't let them distract you from the real composer.json change when reviewing the tag.
  • Pin PHP and Laravel deliberately. Install into a container matching the tag's constraints (PHP 8.0+ for V12). --ignore-platform-reqs will "work" and then fail at runtime in ways that are far harder to debug than a clean install error.
  • php artisan config:clear after any .env edit if config is cached. The Dingo settings (API_PREFIX, API_DEBUG, API_STRICT, API_STANDARDS_TREE) live in env, and stale caches produce routes that look "missing" or prefixes that look wrong.
  • Double-prefix trap. Setting API_PREFIX=api and a prefix on the version group yields /api/v1/v1/.... Set the prefix in exactly one place.
  • Accept header governs everything. Without Accept: application/json, Dingo falls back to HTML error pages and debugging gets surreal. Set API_DEBUG=true locally, and be aware that API_STRICT changes whether a missing version throws or is inferred from the Accept header — behavior differs between environments if that env var drifts.
  • JWT logout is not logout by default. Token invalidation requires the blacklist to be enabled with a shared store (Redis/cache). Without it, "logout" is purely client-side and a captured token stays valid until expiry. Verify JWT_BLACKLIST_ENABLED and the storage driver before you claim sessions are revocable.
  • Laravel's route:list lies. Use api:routes — on Laravel 9 as much as on 8. Likewise, route caching and Dingo don't always compose cleanly, and Laravel 9's route-cache changes make this worth re-testing on V12 rather than assuming 11.x behaviour carried over. If routes vanish after route:cache, that's the cause.
  • Seeders usually create a known test account. Change or remove it before anything touches a shared environment.
  • Extension point worth using: put your transformers behind a small interface or a resolver so you can swap Fractal for API Resources later without touching controllers. That one seam converts a scary migration into a mechanical one.
  • MIT licensed, so lifting the directory structure, request/transformer split, and versioning conventions into a modern app is entirely legitimate — that's still the highest-value way to "use" this package today, and V12 doesn't change the calculus.
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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo