├── .gitignore ├── .scrutinizer.yml ├── README.md ├── composer.json ├── phpunit.xml ├── src ├── Generator │ ├── ApiMakeCommand.php │ └── stubs │ │ ├── controller.stub │ │ ├── route.stub │ │ └── transformer.stub ├── ServiceProvider.php ├── Skeleton │ └── BaseController.php └── config │ └── config.php └── templates └── Api ├── Controllers └── Controller.php ├── Transformers └── .gitkeep └── routes.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.phar 3 | composer.lock 4 | .DS_Store 5 | /.idea 6 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | filter: 2 | paths: 3 | - 'src/*' 4 | excluded_paths: 5 | - 'src/config/*' 6 | - 'vendor/*' 7 | tools: 8 | php_cs_fixer: 9 | config: { level: psr2 } 10 | checks: 11 | php: 12 | code_rating: true 13 | duplication: true 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Total Downloads](https://img.shields.io/packagist/dt/Arrilot/laravel-api-generator.svg?style=flat)](https://packagist.org/packages/Arrilot/laravel-api-generator) 2 | [![Scrutinizer Quality Score](https://img.shields.io/scrutinizer/g/Arrilot/laravel-api-generator/master.svg?style=flat)](https://scrutinizer-ci.com/g/Arrilot/laravel-api-generator/) 3 | [![MIT License](https://img.shields.io/packagist/l/Arrilot/laravel-api-generator.svg?style=flat)](https://packagist.org/packages/Arrilot/laravel-api-generator) 4 | 5 | # Laravel Api Generator (No longer supported) 6 | 7 | *Two simple tools for building REST APIs with fractal: console generator and API skeleton* 8 | 9 | ## Introduction 10 | 11 | This package provides two features 12 | 13 | 1. Console generator which creates Controller, Fractal Transformer and routes in a single command. 14 | 15 | 2. Basic REST API skeleton that can be really helpful if you need something standard. It's 100% optional. 16 | 17 | If you do not use Fractal for your transformation layer, this package is probably not the right choice for you. 18 | 19 | ## Installation 20 | 21 | 1) Run ```composer require arrilot/laravel-api-generator``` 22 | 23 | 2) Register a service provider in the `app.php` configuration file 24 | 25 | ```php 26 | [ 29 | ... 30 | 'Arrilot\Api\ServiceProvider', 31 | ], 32 | ?> 33 | ``` 34 | 35 | 3) Copy basic folder structure to app/Api ```cp -R vendor/arrilot/laravel-api-generator/templates/Api app/Api``` and check what you got there. 36 | If you need you can use different paths later. 37 | 38 | 39 | ## Usage 40 | 41 | ### Generator 42 | 43 | The only console command that is added is ```artisan make:api ```. 44 | 45 | Imagine you need to create a rest api to list/create/update etc users from users table. 46 | To achieve that you need to do lots of boilerplate operations - create controller, transformer, set up needed routes. 47 | 48 | ```php artisan make:api User``` does all the work for you. 49 | 50 | 1) You may have noticed that after installation you already have a routes file `app/Api/routes.php` which looks like that: 51 | 52 | ```php 53 | 'api/v1', 'namespace' => 'App\Api\Controllers'], function () { 56 | // 57 | }); 58 | 59 | ``` 60 | 61 | Feel free to change it if you like. 62 | 63 | The generator adds ```Route::resource('users', 'UserController');``` to the end of this file. 64 | 65 | ```php 66 | 'api/v1', 'namespace' => 'App\Api\Controllers'], function () { 69 | // 70 | Route::resource('users', 'UserController'); 71 | }); 72 | 73 | ``` 74 | 75 | As you can see it's smart enough to detect some route groups and treat this situation properly. 76 | 77 | 2) Then the generator creates a controller that extends base api controller. 78 | 79 | ```php 80 | (int)$item->id, 138 | 'created_at' => (string)$item->created_at, 139 | 'updated_at' => (string)$item->updated_at, 140 | ]; 141 | } 142 | } 143 | 144 | ``` 145 | 146 | This stub is customizable too. 147 | 148 | ### Skeleton 149 | 150 | You may have noticed that controller which has just been generated includes two public methods - `model()` and `transformer()` 151 | That's because those methods are the only thing that you need in your controller to set up a basic REST API if you use the Skeleton. 152 | 153 | The list of routes that are available out of the box: 154 | 155 | 1. `GET api/v1/users` 156 | 2. `GET api/v1/users/{id}` 157 | 3. `POST api/v1/users` 158 | 4. `PUT api/v1/users/{id}` 159 | 5. `DELETE api/v1/users/{id}` 160 | 161 | Request and respone format is json 162 | Fractal includes are supported via $_GET['include']. 163 | Validation rules for create and update can be set by overwriting `rulesForCreate` and `rulesForUpdate` in your controller. 164 | 165 | This skeleton is not a silver bullet but in many cases it can be either exactly what you need or can be used as a decent starting point for your api. 166 | 167 | You can check https://github.com/Arrilot/laravel-api-generator/blob/master/src/Skeleton/BaseController.php for more info. 168 | 169 | If you don't like the Skeleton just stop inheriting it in the base controller - `Api\Controllers\Controller` and overwrite the controller stub in your config to remove `model()` and `transformer()` methods. 170 | 171 | 172 | ### Configuration 173 | 174 | All paths and generator's stubs are configurable. 175 | 176 | https://github.com/Arrilot/laravel-api-generator/blob/master/src/config/config.php 177 | 178 | 179 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "arrilot/laravel-api-generator", 3 | "description": "Two simple tools for building REST APIs with fractal: console generator and API skeleton", 4 | "license": "MIT", 5 | "keywords": ["rest", "api", "fractal", "generator"], 6 | "authors": [ 7 | { 8 | "name": "Nekrasov Ilya", 9 | "email": "nekrasov.ilya90@gmail.com" 10 | } 11 | ], 12 | "homepage": "https://github.com/Arrilot/laravel-api-generator", 13 | "require": { 14 | "php": ">=5.4.0", 15 | "illuminate/support": ">=5.5", 16 | "league/fractal": "0.*" 17 | }, 18 | "autoload": { 19 | "psr-4": { 20 | "Arrilot\\Api\\": "src/" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Generator/ApiMakeCommand.php: -------------------------------------------------------------------------------- 1 | [], 42 | 'model' => [], 43 | 'controller' => [], 44 | 'transformer' => [], 45 | 'route' => [], 46 | ]; 47 | 48 | protected $modelsBaseNamespace; 49 | 50 | /** 51 | * Create a new controller creator command instance. 52 | * 53 | * @param \Illuminate\Filesystem\Filesystem $files 54 | */ 55 | public function __construct(Filesystem $files) 56 | { 57 | parent::__construct(); 58 | 59 | $this->files = $files; 60 | } 61 | 62 | /** 63 | * Execute the console command. 64 | * 65 | * @return void 66 | */ 67 | public function handle() 68 | { 69 | $this->prepareVariablesForStubs($this->argument('name')); 70 | 71 | $this->createController(); 72 | 73 | $this->createTransformer(); 74 | 75 | $this->addRoutes(); 76 | } 77 | 78 | /** 79 | * Prepare names, paths and namespaces for stubs. 80 | * 81 | * @param $name 82 | */ 83 | protected function prepareVariablesForStubs($name) 84 | { 85 | $this->stubVariables['app']['namespace'] = $this->getAppNamespace(); 86 | 87 | $baseDir = config('laravel-api-generator.models_base_dir'); 88 | 89 | $this->modelsBaseNamespace = $baseDir ? trim($baseDir, '\\').'\\' : ''; 90 | 91 | $this->setModelData($name) 92 | ->setControllerData() 93 | ->setRouteData() 94 | ->setTransformerData(); 95 | } 96 | 97 | /** 98 | * Set the model name and namespace. 99 | * 100 | * @return $this 101 | */ 102 | protected function setModelData($name) 103 | { 104 | if (str_contains($name, '/')) { 105 | $name = $this->convertSlashes($name); 106 | } 107 | 108 | $name = trim($name, '\\'); 109 | 110 | $this->stubVariables['model']['fullNameWithoutRoot'] = $name; 111 | $this->stubVariables['model']['fullName'] = $this->stubVariables['app']['namespace'].$this->modelsBaseNamespace.$name; 112 | 113 | $exploded = explode('\\', $this->stubVariables['model']['fullName']); 114 | $this->stubVariables['model']['name'] = array_pop($exploded); 115 | $this->stubVariables['model']['namespace'] = implode('\\', $exploded); 116 | 117 | $exploded = explode('\\', $this->stubVariables['model']['fullNameWithoutRoot']); 118 | array_pop($exploded); 119 | $this->stubVariables['model']['additionalNamespace'] = implode('\\', $exploded); 120 | 121 | return $this; 122 | } 123 | 124 | /** 125 | * Set the controller names and namespaces. 126 | * 127 | * @return $this 128 | */ 129 | protected function setControllerData() 130 | { 131 | return $this->setDataForEntity('controller'); 132 | } 133 | 134 | /** 135 | * Set route data for a given model. 136 | * "Profile\Payer" -> "profile_payers". 137 | * 138 | * @return $this 139 | */ 140 | protected function setRouteData() 141 | { 142 | $name = str_replace('\\', '', $this->stubVariables['model']['fullNameWithoutRoot']); 143 | $name = snake_case($name); 144 | 145 | $this->stubVariables['route']['name'] = str_plural($name); 146 | 147 | return $this; 148 | } 149 | 150 | /** 151 | * Set the transformer names and namespaces. 152 | * 153 | * @return $this 154 | */ 155 | protected function setTransformerData() 156 | { 157 | return $this->setDataForEntity('transformer'); 158 | } 159 | 160 | /** 161 | * Set entity's names and namespaces. 162 | * 163 | * @param string $entity 164 | * 165 | * @return $this 166 | */ 167 | protected function setDataForEntity($entity) 168 | { 169 | $entityNamespace = $this->convertSlashes(config("laravel-api-generator.{$entity}s_dir")); 170 | $this->stubVariables[$entity]['name'] = $this->stubVariables['model']['name'].ucfirst($entity); 171 | 172 | $this->stubVariables[$entity]['namespaceWithoutRoot'] = implode('\\', array_filter([ 173 | $entityNamespace, 174 | $this->stubVariables['model']['additionalNamespace'], 175 | ])); 176 | 177 | $this->stubVariables[$entity]['namespaceBase'] = $this->stubVariables['app']['namespace'].$entityNamespace; 178 | 179 | $this->stubVariables[$entity]['namespace'] = $this->stubVariables['app']['namespace'].$this->stubVariables[$entity]['namespaceWithoutRoot']; 180 | 181 | $this->stubVariables[$entity]['fullNameWithoutRoot'] = $this->stubVariables[$entity]['namespaceWithoutRoot'].'\\'.$this->stubVariables[$entity]['name']; 182 | 183 | $this->stubVariables[$entity]['fullName'] = $this->stubVariables[$entity]['namespace'].'\\'.$this->stubVariables[$entity]['name']; 184 | 185 | return $this; 186 | } 187 | 188 | /** 189 | * Create controller class file from a stub. 190 | */ 191 | protected function createController() 192 | { 193 | $this->createClass('controller'); 194 | } 195 | 196 | /** 197 | * Create controller class file from a stub. 198 | */ 199 | protected function createTransformer() 200 | { 201 | $this->createClass('transformer'); 202 | } 203 | 204 | /** 205 | * Add routes to routes file. 206 | */ 207 | protected function addRoutes() 208 | { 209 | $stub = $this->constructStub(base_path(config('laravel-api-generator.route_stub'))); 210 | 211 | $routesFile = app_path(config('laravel-api-generator.routes_file')); 212 | 213 | // read file 214 | $lines = file($routesFile); 215 | $lastLine = trim($lines[count($lines) - 1]); 216 | 217 | // modify file 218 | if (strcmp($lastLine, '});') === 0) { 219 | $lines[count($lines) - 1] = ' '.$stub; 220 | $lines[] = "\r\n});\r\n"; 221 | } else { 222 | $lines[] = "$stub\r\n"; 223 | } 224 | 225 | // save file 226 | $fp = fopen($routesFile, 'w'); 227 | fwrite($fp, implode('', $lines)); 228 | fclose($fp); 229 | 230 | $this->info('Routes added successfully.'); 231 | } 232 | 233 | /** 234 | * Create class with a given type. 235 | * 236 | * @param $type 237 | * 238 | * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException 239 | */ 240 | protected function createClass($type) 241 | { 242 | $path = $this->getPath($this->stubVariables[$type]['fullNameWithoutRoot']); 243 | if ($this->files->exists($path)) { 244 | $this->error(ucfirst($type).' already exists!'); 245 | 246 | return; 247 | } 248 | 249 | $this->makeDirectoryIfNeeded($path); 250 | 251 | $this->files->put($path, $this->constructStub(base_path(config('laravel-api-generator.'.$type.'_stub')))); 252 | 253 | $this->info(ucfirst($type).' created successfully.'); 254 | } 255 | 256 | /** 257 | * Get the destination file path. 258 | * 259 | * @param string $name 260 | * 261 | * @return string 262 | */ 263 | protected function getPath($name) 264 | { 265 | $name = str_replace($this->stubVariables['app']['namespace'], '', $name); 266 | 267 | return $this->laravel['path'].'/'.str_replace('\\', '/', $name).'.php'; 268 | } 269 | 270 | /** 271 | * Build the directory for the class if needed. 272 | * 273 | * @param string $path 274 | * 275 | * @return string 276 | */ 277 | protected function makeDirectoryIfNeeded($path) 278 | { 279 | if (!$this->files->isDirectory(dirname($path))) { 280 | $this->files->makeDirectory(dirname($path), 0777, true, true); 281 | } 282 | } 283 | 284 | /** 285 | * Get stub content and replace all stub placeholders 286 | * with data from $this->stubData. 287 | * 288 | * @param string $path 289 | * 290 | * @return string 291 | */ 292 | protected function constructStub($path) 293 | { 294 | $stub = $this->files->get($path); 295 | 296 | foreach ($this->stubVariables as $entity => $fields) { 297 | foreach ($fields as $field => $value) { 298 | $stub = str_replace("{{{$entity}.{$field}}}", $value, $stub); 299 | } 300 | } 301 | 302 | return $stub; 303 | } 304 | 305 | /** 306 | * Get the console command arguments. 307 | * 308 | * @return array 309 | */ 310 | protected function getArguments() 311 | { 312 | return [ 313 | ['name', InputArgument::REQUIRED, 'The name of the model'], 314 | ]; 315 | } 316 | 317 | /** 318 | * Convert "/" to "\". 319 | * 320 | * @param $string 321 | * 322 | * @return string 323 | */ 324 | protected function convertSlashes($string) 325 | { 326 | return str_replace('/', '\\', $string); 327 | } 328 | } 329 | -------------------------------------------------------------------------------- /src/Generator/stubs/controller.stub: -------------------------------------------------------------------------------- 1 | (int)$item->id, 18 | 'created_at' => (string)$item->created_at, 19 | 'updated_at' => (string)$item->updated_at, 20 | ]; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/ServiceProvider.php: -------------------------------------------------------------------------------- 1 | mergeConfigFrom( 17 | __DIR__.'/config/config.php', 'laravel-api-generator' 18 | ); 19 | 20 | $this->app->singleton('command.api.make', function ($app) { 21 | return new ApiMakeCommand($app['files']); 22 | }); 23 | 24 | $this->commands('command.api.make'); 25 | } 26 | 27 | /** 28 | * Bootstrap the application events. 29 | */ 30 | public function boot() 31 | { 32 | $this->publishes([ 33 | __DIR__.'/config/config.php' => config_path('laravel-api-generator.php'), 34 | ]); 35 | 36 | require app_path(config('laravel-api-generator.routes_file')); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Skeleton/BaseController.php: -------------------------------------------------------------------------------- 1 | model = $this->model(); 96 | $this->transformer = $this->transformer(); 97 | 98 | $this->fractal = new Manager(); 99 | $this->fractal->setSerializer($this->serializer()); 100 | 101 | $this->request = $request; 102 | 103 | if ($this->request->has('include')) { 104 | $this->fractal->parseIncludes(camel_case($this->request->input('include'))); 105 | } 106 | } 107 | 108 | /** 109 | * Eloquent model. 110 | * 111 | * @return \Illuminate\Database\Eloquent\Model 112 | */ 113 | abstract protected function model(); 114 | 115 | /** 116 | * Transformer for the current model. 117 | * 118 | * @return \League\Fractal\TransformerAbstract 119 | */ 120 | abstract protected function transformer(); 121 | 122 | /** 123 | * Serializer for the current model. 124 | * 125 | * @return \League\Fractal\Serializer\SerializerAbstract 126 | */ 127 | protected function serializer() 128 | { 129 | return new DataArraySerializer(); 130 | } 131 | 132 | /** 133 | * Display a listing of the resource. 134 | * GET /api/{resource}. 135 | * 136 | * @return Response 137 | */ 138 | public function index() 139 | { 140 | $with = $this->getEagerLoad(); 141 | $skip = (int) $this->request->input('skip', 0); 142 | $limit = $this->calculateLimit(); 143 | 144 | $items = $limit 145 | ? $this->model->with($with)->skip($skip)->limit($limit)->get() 146 | : $this->model->with($with)->get(); 147 | 148 | return $this->respondWithCollection($items, $skip, $limit); 149 | } 150 | 151 | /** 152 | * Store a newly created resource in storage. 153 | * POST /api/{resource}. 154 | * 155 | * @return Response 156 | */ 157 | public function store() 158 | { 159 | $data = $this->request->json()->get($this->resourceKeySingular); 160 | 161 | if (!$data) { 162 | return $this->errorWrongArgs('Empty data'); 163 | } 164 | 165 | $validator = Validator::make($data, $this->rulesForCreate()); 166 | if ($validator->fails()) { 167 | return $this->errorWrongArgs($validator->messages()); 168 | } 169 | 170 | $this->unguardIfNeeded(); 171 | 172 | $item = $this->model->create($data); 173 | 174 | return $this->respondWithItem($item); 175 | } 176 | 177 | /** 178 | * Display the specified resource. 179 | * GET /api/{resource}/{id}. 180 | * 181 | * @param int $id 182 | * 183 | * @return Response 184 | */ 185 | public function show($id) 186 | { 187 | $with = $this->getEagerLoad(); 188 | 189 | $item = $this->findItem($id, $with); 190 | if (!$item) { 191 | return $this->errorNotFound(); 192 | } 193 | 194 | return $this->respondWithItem($item); 195 | } 196 | 197 | /** 198 | * Update the specified resource in storage. 199 | * PUT /api/{resource}/{id}. 200 | * 201 | * @param int $id 202 | * 203 | * @return Response 204 | */ 205 | public function update($id) 206 | { 207 | $data = $this->request->json()->get($this->resourceKeySingular); 208 | 209 | if (!$data) { 210 | return $this->errorWrongArgs('Empty data'); 211 | } 212 | 213 | $item = $this->findItem($id); 214 | if (!$item) { 215 | return $this->errorNotFound(); 216 | } 217 | 218 | $validator = Validator::make($data, $this->rulesForUpdate($item->id)); 219 | if ($validator->fails()) { 220 | return $this->errorWrongArgs($validator->messages()); 221 | } 222 | 223 | $this->unguardIfNeeded(); 224 | 225 | $item->fill($data); 226 | $item->save(); 227 | 228 | return $this->respondWithItem($item); 229 | } 230 | 231 | /** 232 | * Remove the specified resource from storage. 233 | * DELETE /api/{resource}/{id}. 234 | * 235 | * @param int $id 236 | * 237 | * @return Response 238 | */ 239 | public function destroy($id) 240 | { 241 | $item = $this->findItem($id); 242 | 243 | if (!$item) { 244 | return $this->errorNotFound(); 245 | } 246 | 247 | $item->delete(); 248 | 249 | return response()->json(['message' => 'Deleted']); 250 | } 251 | 252 | /** 253 | * Show the form for creating the specified resource. 254 | * 255 | * @return Response 256 | */ 257 | public function create() 258 | { 259 | return $this->errorNotImplemented(); 260 | } 261 | 262 | /** 263 | * Show the form for editing the specified resource. 264 | * 265 | * @param int $id 266 | * 267 | * @return Response 268 | */ 269 | public function edit($id) 270 | { 271 | return $this->errorNotImplemented(); 272 | } 273 | 274 | /** 275 | * Getter for statusCode. 276 | * 277 | * @return int 278 | */ 279 | protected function getStatusCode() 280 | { 281 | return $this->statusCode; 282 | } 283 | 284 | /** 285 | * Setter for statusCode. 286 | * 287 | * @param int $statusCode Value to set 288 | * 289 | * @return self 290 | */ 291 | protected function setStatusCode($statusCode) 292 | { 293 | $this->statusCode = $statusCode; 294 | 295 | return $this; 296 | } 297 | 298 | /** 299 | * Respond with a given item. 300 | * 301 | * @param $item 302 | * 303 | * @return mixed 304 | */ 305 | protected function respondWithItem($item) 306 | { 307 | $resource = new Item($item, $this->transformer, $this->resourceKeySingular); 308 | 309 | $rootScope = $this->prepareRootScope($resource); 310 | 311 | return $this->respondWithArray($rootScope->toArray()); 312 | } 313 | 314 | /** 315 | * Respond with a given collection. 316 | * 317 | * @param $collection 318 | * @param int $skip 319 | * @param int $limit 320 | * 321 | * @return mixed 322 | */ 323 | protected function respondWithCollection($collection, $skip = 0, $limit = 0) 324 | { 325 | $resource = new Collection($collection, $this->transformer, $this->resourceKeyPlural); 326 | 327 | if ($limit) { 328 | $cursor = new Cursor($skip, $skip + $limit, $collection->count()); 329 | $resource->setCursor($cursor); 330 | } 331 | 332 | $rootScope = $this->prepareRootScope($resource); 333 | 334 | return $this->respondWithArray($rootScope->toArray()); 335 | } 336 | 337 | /** 338 | * Respond with a given array of items. 339 | * 340 | * @param array $array 341 | * @param array $headers 342 | * 343 | * @return mixed 344 | */ 345 | protected function respondWithArray(array $array, array $headers = []) 346 | { 347 | return response()->json($array, $this->statusCode, $headers); 348 | } 349 | 350 | /** 351 | * Response with the current error. 352 | * 353 | * @param string $message 354 | * 355 | * @return mixed 356 | */ 357 | protected function respondWithError($message) 358 | { 359 | return $this->respondWithArray([ 360 | 'error' => [ 361 | 'http_code' => $this->statusCode, 362 | 'message' => $message, 363 | ], 364 | ]); 365 | } 366 | 367 | /** 368 | * Prepare root scope and set some meta information. 369 | * 370 | * @param Item|Collection $resource 371 | * 372 | * @return \League\Fractal\Scope 373 | */ 374 | protected function prepareRootScope($resource) 375 | { 376 | $resource->setMetaValue('available_includes', $this->transformer->getAvailableIncludes()); 377 | $resource->setMetaValue('default_includes', $this->transformer->getDefaultIncludes()); 378 | 379 | return $this->fractal->createData($resource); 380 | } 381 | 382 | /** 383 | * Get the validation rules for create. 384 | * 385 | * @return array 386 | */ 387 | protected function rulesForCreate() 388 | { 389 | return []; 390 | } 391 | 392 | /** 393 | * Get the validation rules for update. 394 | * 395 | * @param int $id 396 | * 397 | * @return array 398 | */ 399 | protected function rulesForUpdate($id) 400 | { 401 | return []; 402 | } 403 | 404 | /** 405 | * Generate a Response with a 403 HTTP header and a given message. 406 | * 407 | * @param $message 408 | * 409 | * @return Response 410 | */ 411 | protected function errorForbidden($message = 'Forbidden') 412 | { 413 | return $this->setStatusCode(403)->respondWithError($message); 414 | } 415 | 416 | /** 417 | * Generate a Response with a 500 HTTP header and a given message. 418 | * 419 | * @param string $message 420 | * 421 | * @return Response 422 | */ 423 | protected function errorInternalError($message = 'Internal Error') 424 | { 425 | return $this->setStatusCode(500)->respondWithError($message); 426 | } 427 | 428 | /** 429 | * Generate a Response with a 404 HTTP header and a given message. 430 | * 431 | * @param string $message 432 | * 433 | * @return Response 434 | */ 435 | protected function errorNotFound($message = 'Resource Not Found') 436 | { 437 | return $this->setStatusCode(404)->respondWithError($message); 438 | } 439 | 440 | /** 441 | * Generate a Response with a 401 HTTP header and a given message. 442 | * 443 | * @param string $message 444 | * 445 | * @return Response 446 | */ 447 | protected function errorUnauthorized($message = 'Unauthorized') 448 | { 449 | return $this->setStatusCode(401)->respondWithError($message); 450 | } 451 | 452 | /** 453 | * Generate a Response with a 400 HTTP header and a given message. 454 | * 455 | * @param string$message 456 | * 457 | * @return Response 458 | */ 459 | protected function errorWrongArgs($message = 'Wrong Arguments') 460 | { 461 | return $this->setStatusCode(400)->respondWithError($message); 462 | } 463 | 464 | /** 465 | * Generate a Response with a 501 HTTP header and a given message. 466 | * 467 | * @param string $message 468 | * 469 | * @return Response 470 | */ 471 | protected function errorNotImplemented($message = 'Not implemented') 472 | { 473 | return $this->setStatusCode(501)->respondWithError($message); 474 | } 475 | 476 | /** 477 | * Specify relations for eager loading. 478 | * 479 | * @return array 480 | */ 481 | protected function getEagerLoad() 482 | { 483 | $include = camel_case($this->request->input('include', '')); 484 | $includes = explode(',', $include); 485 | $includes = array_filter($includes); 486 | 487 | return $includes ?: []; 488 | } 489 | 490 | /** 491 | * Get item according to mode. 492 | * 493 | * @param int $id 494 | * @param array $with 495 | * 496 | * @return mixed 497 | */ 498 | protected function findItem($id, array $with = []) 499 | { 500 | if ($this->request->has('use_as_id')) { 501 | return $this->model->with($with)->where($this->request->input('use_as_id'), '=', $id)->first(); 502 | } 503 | 504 | return $this->model->with($with)->find($id); 505 | } 506 | 507 | /** 508 | * Unguard eloquent model if needed. 509 | */ 510 | protected function unguardIfNeeded() 511 | { 512 | if ($this->unguard) { 513 | $this->model->unguard(); 514 | } 515 | } 516 | 517 | /** 518 | * Calculates limit for a number of items displayed in list. 519 | * 520 | * @return int 521 | */ 522 | protected function calculateLimit() 523 | { 524 | $limit = (int) $this->request->input('limit', $this->defaultLimit); 525 | 526 | return ($this->maximumLimit && $this->maximumLimit < $limit) ? $this->maximumLimit : $limit; 527 | } 528 | } -------------------------------------------------------------------------------- /src/config/config.php: -------------------------------------------------------------------------------- 1 | 'Api/Controllers', 9 | 10 | /* 11 | * Relative path from the app directory to transformers directory. 12 | */ 13 | 'transformers_dir' => 'Api/Transformers', 14 | 15 | /* 16 | * Relative path from the app directory to the api routes file. 17 | */ 18 | 'routes_file' => 'Api/routes.php', 19 | 20 | /* 21 | * Relative path from the app directory to the models directory. Typically it's either 'Models' or ''. 22 | */ 23 | 'models_base_dir' => '', 24 | 25 | /* 26 | * Relative path from the base directory to the api controller stub. 27 | */ 28 | 'controller_stub' => 'vendor/arrilot/laravel-api-generator/src/Generator/stubs/controller.stub', 29 | 30 | /* 31 | * Relative path from the base directory to the route stub. 32 | */ 33 | 'route_stub' => 'vendor/arrilot/laravel-api-generator/src/Generator/stubs/route.stub', 34 | 35 | /* 36 | * Relative path from the base directory to the transformer stub. 37 | */ 38 | 'transformer_stub' => 'vendor/arrilot/laravel-api-generator/src/Generator/stubs/transformer.stub', 39 | ]; 40 | -------------------------------------------------------------------------------- /templates/Api/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | 'api/v1', 'namespace' => 'App\Api\Controllers'], function () { 4 | // 5 | }); 6 | --------------------------------------------------------------------------------