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

escolalms/api

REST API package for the EscolaLMS Laravel e-learning platform, exposing consistent HTTP endpoints for courses, users, and related LMS resources so developers can integrate with or extend the platform from any client or service.

View on GitHub
Deep Wiki
Context7

Getting Started

EscolaLMS API is a Laravel application skeleton that composes a large family of escolalms/* packages (auth, courses, topics, cart, payments, files, notifications, admin panel) into a headless LMS. You rarely edit the API repo itself — you configure it, extend it, and consume its HTTP surface from a separate frontend (Vue/React/mobile).

Prerequisites: PHP 8.1+, Composer 2, MySQL 8 or PostgreSQL, Node 16+ (only needed if you want the bundled admin panel built).

composer create-project escolalms/api my-lms     # or: git clone && composer install
cp .env.example .env
php artisan key:generate
# set DB_*, APP_URL, MAIL_*, and any payment gateway credentials
php artisan migrate --seed
php artisan passport:install                      # OAuth2 clients + encryption keys
php artisan storage:link
php artisan serve

Where to look first, in this order:

  1. .env.example — every package that needs credentials declares them here; it doubles as a feature inventory.
  2. routes/api.php (and the routes/ folder generally) — shows the aggregate route surface and which middleware groups apply.
  3. config/ — each package publishes its own config (courses.php, cart.php, payments.php, …). These are your primary extension knobs.
  4. vendor/escolalms/*/src — with 19 stars and no dependents, the source is the documentation. Read the package's routes/, Contracts/, and Events/ directories before its README.
  5. The OpenAPI/Swagger artifacts — usually served at /api/documentation; treat them as a starting map, not gospel (see Gotchas).

Your first end-to-end use case: authenticate a user, list courses, and assign one.

# 1. Login (OAuth2 password grant via Passport)
curl -X POST $APP_URL/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"secret"}'
# → { "data": { "token": "...", "refresh_token": "..." } }

# 2. Browse the catalogue
curl $APP_URL/api/courses -H "Authorization: Bearer $TOKEN"

# 3. Enroll / assign (admin or trainer token)
curl -X POST $APP_URL/api/courses/$COURSE_ID/assign \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"user_id": 42}'

Once that loop works, you understand 80% of the integration model: bearer token in, JSON data envelope out, permissions enforced by Spatie roles.

Implementation Patterns

Auth and token lifecycle. Passport handles everything; the frontend should own refresh logic and treat the access token as short-lived. Guard protected routes with auth:api. If you need social or additional grant types, escolalms/auth is the package to inspect rather than writing your own controller — it already registers the OAuth routes and user endpoints.

Standard response shape. Responses are Laravel API Resources, so collections arrive as { "data": [...], "meta": { "current_page", "per_page", "total" }, "links": {...} }. Build your frontend client around that envelope once; don't special-case individual endpoints. Filtering/sorting typically rides on query params (?page=, ?per_page=, ?order_by=, ?search=) — confirm exact names per endpoint in the source, since they aren't uniform across packages.

Override contracts, don't fork packages. The packages bind repository interfaces in their service providers (e.g. a CourseRepositoryContract). To change business logic, implement the contract in your own app/ namespace and rebind it in a AppServiceProvider:

public function register(): void
{
    $this->app->bind(
        \EscolaLms\Courses\Contracts\CourseRepositoryContract::class,
        \App\Repositories\CustomCourseRepository::class
    );
}

Rebind in register(), not boot(), and only after the package provider has run — composer dump-autoload plus a config cache clear usually resolves "class not found" surprises here.

Swap Eloquent models via config. This is the cleanest extension point in the EscolaLMS family: several packages let you point a config key at your own model subclass, so you can add columns, casts, or relations without touching vendor code.

// config/courses.php
'models' => [
    'course' => \App\Models\Course::class,   // extends EscolaLms\Courses\Models\Course
],

Always extend the original model rather than reimplementing it — the packages type-hint against the base class and rely on its traits (translations, media, soft deletes).

Hook in with events and listeners. Package events are the sanctioned way to react to domain activity (enrollment, payment settled, course completed). Register listeners in EventServiceProvider and keep them queued (ShouldQueue) — several events fire inside transactional request paths.

protected $listen = [
    \EscolaLms\Courses\Events\CourseAssigned::class => [
        \App\Listeners\SendWelcomeEmail::class,
    ],
];

Feature delivery pattern. Enable a capability by requiring its package, publishing its config and migrations, then re-running migrate. Typical compositions:

  • Commerce: cart + payments with a gateway driver (Stripe / PayU / Przelewy24). The cart holds line items; the payment gateway creates the redirect/confirmation flow; a webhook or return URL finalizes the order. Never grant course access from the frontend return page — always from the server-side confirmation.
  • Content: courses → topic → topic-type (rich text, video, audio, PDF, H5P). If you need a new content type, implement it as a topic-type package rather than a custom field on the course.
  • Live delivery: webinar or stationary-events for scheduled sessions; both build on the same enrollment model, so reuse existing assignment logic.

Write a real module for your own domain. Follow the package conventions: src/, routes/, database/migrations/, config/, a ServiceProvider with mergeConfigFrom + loadMigrationsFrom + loadRoutesFrom. Laravel auto-discovery registers it; no manual provider entry needed. This keeps your code upgradeable when escolalms/* ships a breaking change.

Testing. Use RefreshDatabase and the packages' factories. Because roles and permissions are seeded (escolalms/core ships the permission catalogue), feature tests that hit admin routes need a user with the right role attached — actingAs($user, 'api') plus a givePermissionTo() call is usually faster than re-running the seeders.

Gotchas and Tips

Version alignment across packages is mandatory. The escolalms/* packages are released in lockstep and share internal base classes from escolalms/core. Mixing versions produces cryptic trait-method or contract-signature errors. Upgrade the whole family at once, and pin exact versions in composer.json for production:

composer update "escolalms/*" -W
php artisan vendor:publish --tag=escolalms --force   # re-publish configs after major bumps

Migrations arrive from vendor paths. Package migrations run from vendor/, so ordering is determined at install time and can shift after an update. Never hand-edit published migrations; if you need to alter a package table, add your own migration that runs afterward. In CI, always migrate:fresh rather than migrate to catch ordering problems early.

Passport setup is a one-time trap. Forgetting passport:install yields opaque "Unauthenticated" responses on valid credentials. After a fresh clone or a DB reset, re-run it plus config:clear. If you're on multiple app servers, copy the generated keys and the oauth_clients rows rather than installing per node.

The OpenAPI docs drift. Endpoints get added and renamed faster than the spec is regenerated. When the spec and the source disagree, trust vendor/escolalms/<pkg>/routes/. Generate your own client types from a live /api/documentation in a CI step rather than checking in a hand-maintained SDK.

Cache tags and config caching bite on deploy. The packages cache permissions and settings. On deploy: php artisan config:cache route:cache after migrate, then php artisan cache:clear. A stale config cache is the #1 cause of "I changed the config and nothing happened."

Storage and media URLs are environment-sensitive. Course images, SCORM/H5P assets, and uploaded files resolve through the configured filesystem disk. Local dev with storage:link works; moving to S3 requires updating the disk and APP_URL, otherwise the API returns correct-but-unreachable URLs. Set FILESYSTEM_DRIVER and CDN host together, and test file upload → course display end-to-end on staging.

Localization is per-entity. Courses and topics are translatable; the API selects language from the request (header or ?lang=). If a frontend shows empty titles, it's almost always a missing translation row, not an API bug. Seed the locales you actually support in config rather than assuming a fallback chain.

The admin panel ships in the same repo. If you want the Vue admin UI, it needs npm install && npm run prod, and its assets must be rebuilt on upgrade. Many teams skip it and build their own frontend against the API — that's the intended headless path, but budget for it.

Debugging workflow. Install Laravel Telescope on non-production early; it makes the multi-package request pipeline legible. For 403s, log $user->getAllPermissions() at the point of failure — permission names are namespaced per package and typos are common in seeders. For 500s inside a package, check storage/logs before opening a vendor issue; nine times out of ten it's an unpublished config or a missing column.

Community is small — plan accordingly. With a low star count and no dependents, you won't find many Stack Overflow answers. Mitigations: fork the packages you depend on into a private VCS repo so you can hotfix, keep an UPGRADING.md of your own overrides, and read the changelogs before every composer update. Contribute fixes upstream where you can — it reduces your long-term merge burden.

Extension points, ranked by safety: config values → event listeners → contract rebinding → model swapping → route middleware → forking a vendor file (last resort, never).

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