mk990 / mkapi
JSON:API scaffolding with Scramble docs and JWT auth for Laravel
Requires
- php: >=8.3
- illuminate/support: ^13.0
Requires (Dev)
- dedoc/scramble: ^0.13.45
- orchestra/testbench: ^11
- php-open-source-saver/jwt-auth: ^2.9
- phpunit/phpunit: ^11|^12
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
๐ API Development with Laravel MkApi
MkApi is a Laravel 13 CLI tool that scaffolds a JSON:API with JWT authentication. It reads your migrations and generates JSON:API resources, form requests, controllers and routes, and Scramble turns that code into OpenAPI documentation. No annotations required. ๐งฐโจ
Requires Laravel 13+. Earlier MkApi releases (v0.1.x) used l5-swagger;
mkapi:initmigrates such projects automatically (see Upgrading from Swagger).
๐ฆ Packages Used
This project utilizes the following packages to boost development and maintain high standards:
| ๐ฆ Package Name | ๐ Description | ๐ข Version |
|---|---|---|
scramble |
OpenAPI documentation generated from your code, no annotations needed. | ^0.13 |
jwt-auth |
JSON Web Token (JWT) authentication for secure APIs. | ^2.7 |
larastan |
Static analysis tool to catch bugs early using PHPStan for Laravel. | ^3.0 |
laravel-backup |
Seamless backup of databases and files in Laravel apps. | ^9.1 |
laravel-pulse |
Real-time performance insights for Laravel applications. | ^1.4 |
laravel-telescope |
Debugging assistant for Laravel. Monitors requests, logs, queries, mail, jobs, and more. | ^5.8 |
laravel-persian-validation |
Persian-specific validation rules for form requests. | ^2.0 |
verta |
Date handling between Solar and Gregorian calendars. | ^8.5 |
turnstile |
Easy integration with Cloudflare Turnstile for bot protection. | ^2.0 |
โ๏ธ Installation
๐ฅ Install MkApi Tool
composer require mk990/mkapi --dev php artisan mkapi:init
๐ง The following packages are installed by default:
scramblejwt-authlarastan
๐ API docs are served at /docs/api (the OpenAPI JSON at /docs/api.json). They are public by default; to restrict them, add Dedoc\Scramble\Http\Middleware\RestrictedDocsAccess::class back to middleware in config/scramble.php.
The installer also:
- publishes
app/Exceptions/JsonApiExceptionRenderer.phpand registers it inbootstrap/app.php, so every error under/apiis a JSON:API error document - makes unauthenticated API requests return
401instead of redirecting to aloginroute - publishes an
AuthController(register, login, refresh, me, password reset, email verification) and aUserResource
๐๏ธ Install Optional Packages
Use the interactive install command to choose additional tools:
php artisan mkapi:init --package
๐ Available packages:
laravel-backuplaravel-pulselaravel-telescopelaravel-persian-validationvertaturnstile
๐ ๏ธ Usage
MkApi runs your migrations against a temporary database on your default MySQL/MariaDB connection and reads each table's columns. Every command takes a table or model name (post, Post, BlogPost, blog_posts) or all.
๐งฑ Generate a model
php artisan mkapi:model post php artisan mkapi:model all
Writes app/Models/Post.php with $fillable (every column but keys and timestamps) and casts() derived from the column types.
๐ฎ Generate a controller
php artisan mkapi:controller post php artisan mkapi:controller post --code php artisan mkapi:controller all --code
Without --code you get app/Http/Controllers/PostController.php with empty index / store / show / update / destroy methods to fill in yourself. With --code MkApi writes the CRUD code and the classes it uses:
| File | Contents |
|---|---|
app/Http/Resources/PostResource.php |
JsonApiResource exposing every column except id, password, remember_token, deleted_at |
app/Http/Requests/StorePostRequest.php |
Validation rules derived from the column types, nullability and defaults |
app/Http/Requests/UpdatePostRequest.php |
The same rules, each field optional (sometimes) |
app/Http/Controllers/PostController.php |
index / store / show / update / destroy using route model binding |
Either way Route::apiResource('posts', PostController::class); is added to routes/api.php.
๐ง The generated controller:
public function store(StorePostRequest $request): JsonResponse { $post = Post::create($request->validated())->refresh(); return (new PostResource($post))->response()->setStatusCode(201); } public function show(Post $post): PostResource { return new PostResource($post); }
Scramble documents it from those types alone: the request body from StorePostRequest, the response from PostResource, and 401/404/422 from the middleware and bindings.
๐งฉ Options
| Option | Commands | Effect |
|---|---|---|
--force |
mkapi:model, mkapi:controller |
Overwrite existing files |
--code |
mkapi:controller |
Generate the CRUD code, resource and form requests instead of an empty controller |
--public |
mkapi:controller |
Do not put the controller behind the auth middleware |
๐ Response format
Everything under /api speaks JSON:API with Content-Type: application/vnd.api+json. Request bodies are plain JSON objects.
// GET /api/posts/1 { "data": { "id": "1", "type": "posts", "attributes": { "title": "Hello", "status": "draft" } } } // POST /api/auth/login { "meta": { "access_token": "eyJโฆ", "token_type": "bearer", "expires_in": 604800 } } // 422 { "errors": [{ "status": "422", "title": "Validation Error", "detail": "The title field is required.", "source": { "pointer": "/title" } }] }
Lists are paginated with ?page= and ?per_page= (max 100) and support sparse fieldsets (?fields[posts]=title) and includes (?include=author) for relationships declared in the resource's $relationships.
In your own controllers, return resources directly or use the base controller helpers:
$this->success($data): a resource or a model (as a JSON:API resource), a paginator/collection of models (as a JSON:API collection), anything else as a meta document$this->meta(['message' => 'โฆ']): a meta-only document$this->error('message', status: 403): a JSON:API error document
โฌ๏ธ Upgrading from Swagger
Running php artisan mkapi:init in a project set up by an older MkApi:
- strips every
#[OA\โฆ]attribute,@OA\โฆdocblock anduse OpenApi\โฆimport fromapp/ - deletes
config/l5-swagger.php,resources/views/vendor/l5-swaggerandstorage/api-docs - removes the
L5_SWAGGER_*lines from.envand.env.example - runs
composer remove darkaonline/l5-swagger - replaces the base
Controllerwith the JSON:API one (success()anderror()keep their signatures)
The old mkapi:modelSWG and mkapi:controllerSWG commands are gone; use mkapi:model and mkapi:controller --code. Existing controllers keep working, but return JSON:API documents through the new success()/error().
๐งช Testing
composer test # everything composer test-unit # generator and stripping logic only, no Laravel app composer test-coverage # HTML report in coverage/ (needs Xdebug)
The feature tests install MkApi into a throwaway Laravel 13 skeleton with Testbench and a fake composer binary (no network needed). They then send real HTTP requests to the generated API: auth, CRUD, validation and error documents, middlewares, and the Scramble output.
Reading the schema needs MySQL or MariaDB. Without a server those tests are skipped; to run them, point them at a user allowed to create databases:
docker run -d --rm --name mkapi-db -e MARIADB_ROOT_PASSWORD=secret -p 127.0.0.1:3307:3306 mariadb:lts
MKAPI_TEST_MYSQL_HOST=127.0.0.1 MKAPI_TEST_MYSQL_PORT=3307 MKAPI_TEST_MYSQL_PASSWORD=secret composer test
๐ค Contributing
We love contributions! If you have ideas or improvements, feel free to:
- ๐ Create an Issue
- ๐ Submit a Pull Request
๐ License
This project is licensed under the MIT License.
๐ฅ Contributors
- ๐จโ๐ป mk990
- ๐จโ๐ป Emad Shirzad
