{"id":13453144,"url":"https://github.com/hasib32/rest-api-with-lumen","last_synced_at":"2025-04-05T11:12:32.084Z","repository":{"id":72222420,"uuid":"82973144","full_name":"hasib32/rest-api-with-lumen","owner":"hasib32","description":"Rest API boilerplate for Lumen micro-framework.","archived":false,"fork":false,"pushed_at":"2018-02-09T15:08:40.000Z","size":627,"stargazers_count":486,"open_issues_count":17,"forks_count":143,"subscribers_count":40,"default_branch":"master","last_synced_at":"2025-03-29T10:11:20.352Z","etag":null,"topics":["boilerplate","fractal","laravel","lumen","lumen-fractal","lumen-generator","lumen-micro-framework","lumen-php-framework","oauth2","php-rest-api","php7","rest-api"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hasib32.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2017-02-23T21:28:23.000Z","updated_at":"2025-03-21T09:22:30.000Z","dependencies_parsed_at":"2023-05-19T12:45:31.403Z","dependency_job_id":null,"html_url":"https://github.com/hasib32/rest-api-with-lumen","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hasib32%2Frest-api-with-lumen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hasib32%2Frest-api-with-lumen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hasib32%2Frest-api-with-lumen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hasib32%2Frest-api-with-lumen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hasib32","download_url":"https://codeload.github.com/hasib32/rest-api-with-lumen/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247325694,"owners_count":20920714,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["boilerplate","fractal","laravel","lumen","lumen-fractal","lumen-generator","lumen-micro-framework","lumen-php-framework","oauth2","php-rest-api","php7","rest-api"],"created_at":"2024-07-31T08:00:33.685Z","updated_at":"2025-04-05T11:12:32.040Z","avatar_url":"https://github.com/hasib32.png","language":"PHP","funding_links":[],"categories":["Starter Projects","Tools","Packages and Middleware"],"sub_categories":["Videos"],"readme":"\n# REST API with Lumen 5.5 [![Build Status](https://travis-ci.org/hasib32/rest-api-with-lumen.svg?branch=master)](https://travis-ci.org/hasib32/rest-api-with-lumen)\n\nA RESTful API boilerplate for Lumen micro-framework. Features included:\n\n- Users Resource\n- OAuth2 Authentication using Laravel Passport\n- Scope based Authorization\n- Validation\n- [Repository Pattern](https://msdn.microsoft.com/en-us/library/ff649690.aspx)\n- API Response with [Fractal](http://fractal.thephpleague.com/)\n- Pagination\n- Seeding Database With Model Factory\n- Event Handling\n- Sending Mail using Mailable class\n- [CORS](https://github.com/barryvdh/laravel-cors) Support\n- [Rate Limit API Requests](https://mattstauffer.co/blog/api-rate-limiting-in-laravel-5-2)\n- Endpoint Tests and Unit Tests\n- Build Process with [Travis CI](https://travis-ci.org/)\n\n## Getting Started\nFirst, clone the repo:\n```bash\n$ git clone git@github.com:hasib32/rest-api-with-lumen.git\n```\n\n#### Laravel Homestead\nYou can use Laravel Homestead globally or per project for local development. Follow the [Installation Guide](https://laravel.com/docs/5.5/homestead#installation-and-setup).\n\n#### Install dependencies\n```\n$ cd rest-api-with-lumen\n$ composer install\n```\n\n#### Configure the Environment\nCreate `.env` file:\n```\n$ cat .env.example \u003e .env\n```\nIf you want you can edit database name, database username and database password.\n\n#### Migrations and Seed the database with fake data\nFirst, we need connect to the database. For homestead user, login using default homestead username and password:\n```bash\n$ mysql -uhomestead -psecret\n```\n\nThen create a database:\n```bash\nmysql\u003e CREATE DATABASE restapi;\n```\n\nAnd also create test database:\n```bash\nmysql\u003e CREATE DATABASE restapi_test;\n```\n\nRun the Artisan migrate command with seed:\n```bash\n$ php artisan migrate --seed\n```\n\nCreate \"personal access\" and \"password grant\" clients which will be used to generate access tokens:\n```bash\n$ php artisan passport:install\n```\n\nYou can find those clients in ```oauth_clients``` table.\n\n### API Routes\n| HTTP Method\t| Path | Action | Scope | Desciption  |\n| ----- | ----- | ----- | ---- |------------- |\n| GET      | /users | index | users:list | Get all users\n| POST     | /users | store | users:create | Create an user\n| GET      | /users/{user_id} | show | users:read |  Fetch an user by id\n| PUT      | /users/{user_id} | update | users:write | Update an user by id\n| DELETE      | /users/{user_id} | destroy | users:delete | Delete an user by id\n\nNote: ```users/me``` is a special route for getting current authenticated user.\nAnd for all User routes 'users' scope is available if you want to perform all actions.\n\n### OAuth2 Routes\nVisit [dusterio/lumen-passport](https://github.com/dusterio/lumen-passport/blob/master/README.md#installed-routes) to see all the available ```OAuth2``` routes.\n\n### Creating access_token\nSince Laravel Passport doesn't restrict any user creating any valid scope. I had to create a route and controller to restrict user creating access token only with permitted scopes. For creating access_token we have to use the ```accessToken``` route. Here is an example of creating access_token for grant_type password with [Postman.](https://www.getpostman.com/)\n\nhttp://stackoverflow.com/questions/39436509/laravel-passport-scopes\n\n![access_token creation](/public/images/accessTokenCreation.png?raw=true \"access_token creation example\")\n\n## Creating a New Resource\nCreating a new resource is very easy and straight-forward. Follow these simple steps to create a new resource.\n\n### Step 1: Create Route\nCreate a new route name ```messages```. Open the ```routes/web.php``` file and add the following code:\n\n```php\n$route-\u003epost('messages', [\n    'uses'       =\u003e 'MessageController@store',\n    'middleware' =\u003e \"scope:messages,messages:create\"\n]);\n$route-\u003eget('messages',  [\n    'uses'       =\u003e 'MessageController@index',\n    'middleware' =\u003e \"scope:messages,messages:list\"\n]);\n$route-\u003eget('messages/{id}', [\n    'uses'       =\u003e 'MessageController@show',\n    'middleware' =\u003e \"scope:messages,messages:read\"\n]);\n$route-\u003eput('messages/{id}', [\n    'uses'       =\u003e 'MessageController@update',\n    'middleware' =\u003e \"scope:messages,messages:write\"\n]);\n$route-\u003edelete('messages/{id}', [\n    'uses'       =\u003e 'MessageController@destroy',\n    'middleware' =\u003e \"scope:messages,messages:delete\"\n]);\n```\n\nFor more info please visit Lumen [Routing](https://lumen.laravel.com/docs/5.5/routing) page.\n\n### Step 2: Create Model and Migration for the Table\nCreate ```Message``` Model inside ```App/Models``` directory and create migration using Lumen Artisan command.\n\n**Message Model**\n\n```php\n\u003c?php\n\nnamespace App\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\n\nclass Message extends Model\n{\n    /**\n     * The database table used by the model.\n     *\n     * @var string\n     */\n    protected $table = 'messages';\n\n    /**\n     * The attributes that are mass assignable.\n     *\n     * @var array\n     */\n    protected $fillable = [\n        'uid',\n        'userId',\n        'subject',\n        'message',\n    ];\n}\n```\n\nVisit Laravel [Eloquent](https://laravel.com/docs/5.5/eloquent) Page for more info about Model.\n\n**Create migration for messages table**\n\n```bash\nphp artisan make:migration create_messages_table --create=messages\n```\n**Migration file**\n\n```php\nclass CreateMessagesTable extends Migration\n{\n    public function up()\n    {\n        Schema::create('messages', function (Blueprint $table) {\n            $table-\u003eincrements('id');\n            $table-\u003estring('uid', 36)-\u003eunique();\n            $table-\u003einteger('userId')-\u003eunsigned();\n            $table-\u003estring('subject')-\u003enullable();\n            $table-\u003elongText('message');\n            $table-\u003etimestamps();\n\n            $table-\u003eforeign('userId')\n                -\u003ereferences('id')-\u003eon('users')\n                -\u003eonDelete('cascade')\n                -\u003eonUpdate('cascade');\n        });\n    }\n}\n```\n\nFor more info visit Laravel [Migration](https://laravel.com/docs/5.5/migrations) page.\n\n### Step 3: Create Repository\nCreate ```MessageRepository``` and implementation of the repository name ```EloquentMessageRepository```.\n\n**MessageRepository**\n\n```php\n\u003c?php\n\nnamespace App\\Repositories\\Contracts;\n\ninterface MessageRepository extends BaseRepository\n{\n}\n```\n\n**EloquentMessageRepository**\n\n```php\n\u003c?php\n\nnamespace App\\Repositories;\n\nuse App\\Models\\Message;\nuse App\\Repositories\\Contracts\\MessageRepository;\n\nclass EloquentMessageRepository extends AbstractEloquentRepository implements MessageRepository\n{\n    /**\n     * Model name.\n     *\n     * @var string\n     */\n    protected $modelName = Message::class;\n}\n```\n\nNext, update ```RepositoriesServiceProvider``` to bind the implementation:\n\n```php\n\u003c?php\n\nnamespace App\\Providers;\n\nuse Illuminate\\Support\\ServiceProvider;\nuse App\\Repositories\\Contracts\\UserRepository;\nuse App\\Repositories\\EloquentUserRepository;\nuse App\\Repositories\\Contracts\\MessageRepository;\nuse App\\Repositories\\EloquentMessageRepository;\n\nclass RepositoriesServiceProvider extends ServiceProvider\n{\n    /**\n     * Indicates if loading of the provider is deferred.\n     *\n     * @var bool\n     */\n    protected $defer = true;\n\n    /**\n     * Register any application services.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        $this-\u003eapp-\u003ebind(UserRepository::class, function () {\n            return new EloquentUserRepository(new User());\n        });\n        $this-\u003eapp-\u003ebind(MessageRepository::class, function () {\n            return new EloquentMessageRepository(new Message());\n        });\n    }\n\n    /**\n     * Get the services provided by the provider.\n     *\n     * @return array\n     */\n    public function provides()\n    {\n        return [\n            UserRepository::class,\n            MessageRepository::class,\n        ];\n    }\n}\n```\n\nVisit Lumen documentation for more info about [Service Provider](https://lumen.laravel.com/docs/5.5/providers).\n\n### Step 4: Create Fractal Transformer\nFractal provides a presentation and transformation layer for complex data output, the like found in RESTful APIs, and works really well with JSON. Think of this as a view layer for your JSON/YAML/etc.\n\nCreate a new Transformer name ```MessageTransformer``` inside ```app/Transformers``` directory:\n\n```php\n\u003c?php\n\nnamespace App\\Transformers;\n\nuse App\\Models\\Message;\nuse League\\Fractal\\TransformerAbstract;\n\nclass MessageTransformer extends TransformerAbstract\n{\n    public function transform(Message $message)\n    {\n        return [\n            'id'        =\u003e $message-\u003euid,\n            'userId'    =\u003e $message-\u003euserId,\n            'subject'   =\u003e $message-\u003esubject,\n            'message'   =\u003e $message-\u003emessage,\n            'createdAt' =\u003e (string) $message-\u003ecreated_at,\n            'updatedAt' =\u003e (string) $message-\u003eupdated_at,\n        ];\n    }\n}\n```\nVisit [Fractal](http://fractal.thephpleague.com/) official page for more information.\n\n### Step 5: Create Policy\nFor authorization we need to create policy that way basic user can't show or edit other user messages.\n\n**MessagePolicy**\n\n```php\n\u003c?php\n\nnamespace App\\Policies;\n\nuse App\\Models\\User;\nuse App\\Models\\Message;\n\nclass MessagePolicy\n{\n    /**\n     * Intercept checks.\n     *\n     * @param User $currentUser\n     * @return bool\n     */\n    public function before(User $currentUser)\n    {\n        if ($currentUser-\u003eisAdmin() \u0026\u0026 (!$currentUser-\u003etokenCan('basic') || $currentUser-\u003etokenCan('undefined'))) {\n            return true;\n        }\n    }\n\n    /**\n     * Determine if a given user has permission to show.\n     *\n     * @param User $currentUser\n     * @param Message $message\n     * @return bool\n     */\n    public function show(User $currentUser, Message $message)\n    {\n        return $currentUser-\u003eid === $message-\u003euserId;\n    }\n\n    /**\n     * Determine if a given user can update.\n     *\n     * @param User $currentUser\n     * @param Message $message\n     * @return bool\n     */\n    public function update(User $currentUser, Message $message)\n    {\n        return $currentUser-\u003eid === $message-\u003euserId;\n    }\n\n    /**\n     * Determine if a given user can delete.\n     *\n     * @param User $currentUser\n     * @param Message $message\n     * @return bool\n     */\n    public function destroy(User $currentUser, Message $message)\n    {\n        return $currentUser-\u003eid === $message-\u003euserId;\n    }\n}\n```\nNext, update ```AuthServiceProvider``` to use the policy:\n```\nGate::policy(Message::class, MessagePolicy::class);\n```\nAnd add scopes to ``Passport::tokensCan``:\n```\n[\n    'messages' =\u003e 'Messages scope',\n    'messages:list' =\u003e 'Messages scope',\n    'messages:read' =\u003e 'Messages scope for reading records',\n    'messages:write' =\u003e 'Messages scope for writing records',\n    'messages:create' =\u003e 'Messages scope for creating records',\n    'messages:delete' =\u003e 'Messages scope for deleting records'\n]\n```\nVisit Lumen [Authorization Page](https://lumen.laravel.com/docs/5.5/authorization) for more info about Policy.\n\n### Last Step: Create Controller\n \nFinally, let's create the ```MessageController```. Here we're using **MessageRepository, MessageTransformer and MessagePolicy**.\n\n```php\n\u003c?php\n\nnamespace App\\Http\\Controllers;\n\nuse App\\Models\\Message;\nuse App\\Repositories\\Contracts\\MessageRepository;\nuse Illuminate\\Http\\Request;\nuse App\\Transformers\\MessageTransformer;\n\nclass MessageController extends Controller\n{\n    /**\n     * Instance of MessageRepository.\n     *\n     * @var MessageRepository\n     */\n    private $messageRepository;\n\n    /**\n     * Instanceof MessageTransformer.\n     *\n     * @var MessageTransformer\n     */\n    private $messageTransformer;\n\n    /**\n     * Constructor.\n     *\n     * @param MessageRepository $messageRepository\n     * @param MessageTransformer $messageTransformer\n     */\n    public function __construct(MessageRepository $messageRepository, MessageTransformer $messageTransformer)\n    {\n        $this-\u003emessageRepository = $messageRepository;\n        $this-\u003emessageTransformer = $messageTransformer;\n\n        parent::__construct();\n    }\n\n    /**\n     * Display a listing of the resource.\n     *\n     * @param Request $request\n     * @return \\Illuminate\\Http\\JsonResponse\n     */\n    public function index(Request $request)\n    {\n        $messages = $this-\u003emessageRepository-\u003efindBy($request-\u003eall());\n\n        return $this-\u003erespondWithCollection($messages, $this-\u003emessageTransformer);\n    }\n\n    /**\n     * Display the specified resource.\n     *\n     * @param $id\n     * @return \\Illuminate\\Http\\JsonResponse|string\n     */\n    public function show($id)\n    {\n        $message = $this-\u003emessageRepository-\u003efindOne($id);\n\n        if (!$message instanceof Message) {\n            return $this-\u003esendNotFoundResponse(\"The message with id {$id} doesn't exist\");\n        }\n\n        // Authorization\n        $this-\u003eauthorize('show', $message);\n\n        return $this-\u003erespondWithItem($message, $this-\u003emessageTransformer);\n    }\n\n    /**\n     * Store a newly created resource in storage.\n     *\n     * @param Request $request\n     * @return \\Illuminate\\Http\\JsonResponse|string\n     */\n    public function store(Request $request)\n    {\n        // Validation\n        $validatorResponse = $this-\u003evalidateRequest($request, $this-\u003estoreRequestValidationRules($request));\n\n        // Send failed response if validation fails\n        if ($validatorResponse !== true) {\n            return $this-\u003esendInvalidFieldResponse($validatorResponse);\n        }\n\n        $message = $this-\u003emessageRepository-\u003esave($request-\u003eall());\n\n        if (!$message instanceof Message) {\n            return $this-\u003esendCustomResponse(500, 'Error occurred on creating Message');\n        }\n\n        return $this-\u003esetStatusCode(201)-\u003erespondWithItem($message, $this-\u003emessageTransformer);\n    }\n\n    /**\n     * Update the specified resource in storage.\n     *\n     * @param Request $request\n     * @param $id\n     * @return \\Illuminate\\Http\\JsonResponse\n     */\n    public function update(Request $request, $id)\n    {\n        // Validation\n        $validatorResponse = $this-\u003evalidateRequest($request, $this-\u003eupdateRequestValidationRules($request));\n\n        // Send failed response if validation fails\n        if ($validatorResponse !== true) {\n            return $this-\u003esendInvalidFieldResponse($validatorResponse);\n        }\n\n        $message = $this-\u003emessageRepository-\u003efindOne($id);\n\n        if (!$message instanceof Message) {\n            return $this-\u003esendNotFoundResponse(\"The message with id {$id} doesn't exist\");\n        }\n\n        // Authorization\n        $this-\u003eauthorize('update', $message);\n\n\n        $message = $this-\u003emessageRepository-\u003eupdate($message, $request-\u003eall());\n\n        return $this-\u003erespondWithItem($message, $this-\u003emessageTransformer);\n    }\n\n    /**\n     * Remove the specified resource from storage.\n     *\n     * @param $id\n     * @return \\Illuminate\\Http\\JsonResponse|string\n     */\n    public function destroy($id)\n    {\n        $message = $this-\u003emessageRepository-\u003efindOne($id);\n\n        if (!$message instanceof Message) {\n            return $this-\u003esendNotFoundResponse(\"The message with id {$id} doesn't exist\");\n        }\n\n        // Authorization\n        $this-\u003eauthorize('destroy', $message);\n\n        $this-\u003emessageRepository-\u003edelete($message);\n\n        return response()-\u003ejson(null, 204);\n    }\n\n    /**\n     * Store Request Validation Rules\n     *\n     * @param Request $request\n     * @return array\n     */\n    private function storeRequestValidationRules(Request $request)\n    {\n       return [\n           'userId'     =\u003e 'required|exists:users,id',\n           'subject'    =\u003e 'required',\n           'message'    =\u003e 'required',\n        ];\n    }\n\n    /**\n     * Update Request validation Rules\n     *\n     * @param Request $request\n     * @return array\n     */\n    private function updateRequestValidationRules(Request $request)\n    {\n        return [\n            'subject'    =\u003e '',\n            'message'    =\u003e '',\n        ];\n    }\n}\n```\n\nVisit Lumen [Controller](https://lumen.laravel.com/docs/5.5/controllers) page for more info about Controller.\n\n## Tutorial\nTo see the step-by-step tutorial how I created this boilerplate please visit our blog [devnootes.net](https://devnotes.net/rest-api-development-with-lumen-part-one/).\n\n## Contributing\nContributions, questions and comments are all welcome and encouraged. For code contributions submit a pull request.\n\n## Credits\n[Taylor Otwell](https://github.com/taylorotwell), [Shahriar Mahmood](https://github.com/shahriar1), [Fractal](http://fractal.thephpleague.com/), [Phil Sturgeon](https://github.com/philsturgeon)\n## License\n\n [MIT license](http://opensource.org/licenses/MIT)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhasib32%2Frest-api-with-lumen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhasib32%2Frest-api-with-lumen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhasib32%2Frest-api-with-lumen/lists"}