LaraPoints is a REST API skeleton using Laravel framework.
The goal of this project is to create a ready to use REST API skeleton to help developers get their API's up and runining and focus on business logic implementation instead of investing time implementing the commonly needed endpoints and functionalities.
⚠️ ATTENTION: This project is in under development!
Installing the project:
- clone the project on your machine:
$ git clone https://github.com/ihamzehald/larapoints.git
- cd to the project directory (larapoints) and Install the required libraries using composer:
$ cd larapoints
$ composer install
- Configure your environment:
Rename .env.example to .env
Configure your database connection by changing the values of the following variables:
DB_DATABASE={ Your DB name }
DB_USERNAME={ Your DB user name }
DB_PASSWORD={ Your DB password }
Supporting API key (Recommended for mobile applications and private APIs) :
If you are developing an API for a mobile application or your API is private your API client should send API key using x-api-key header, this is disabled by default, to enable that change the following variables values.
First change ACTIVATE_API_KEY=false to ACTIVATE_API_KEY=true
Then change the value of API_KEY to your secured API key.
This tool is recommended to generate secure API key, it is recommended to generate a complex key greater than or equal to 64 characters.
https://passwordsgenerator.net
Then share this key securely with your API clients.
Note: once ACTIVATE_API_KEY set to true, all your API clients should send (x-api-key) header and it's value should match API_KEY.
Apply the database migrations:
$ php artisan migrate
Configure your MailGun integration by changing the values of the following variables:
MAIL_USERNAME={ Your MailGun username}
MAIL_PASSWORD={ Your MailGun password}
MAIL_FROM_ADDRESS={ Your from address }
Change the value of JWT_SECRET to a private JWT secret key.
- Configure your web server
Apache2 virtual host:
Note: this is a sample Apache2 virtual host for local testing, you should always configure your virtual hosts with SSL, but this is out of this documentation scope.
$ cd /etc/apache2/sites-available
Create the a virtual host config file (larapoints.loc.conf) for example.
larapoints.loc.conf sample:
<VirtualHost *:80>
DocumentRoot "/var/www/html/larapoints/public/"
ServerName larapoints.loc
ErrorLog ${APACHE_LOG_DIR}/larapoints.loc.error.log
CustomLog ${APACHE_LOG_DIR}/larapoints.loc.access.log combined
<Directory /var/www/html/larapoints/public/>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
</Directory>
</VirtualHost>
Enable larapoints virtual host:
$ a2ensite larapoints.loc.conf
Add the virtual host server name to the hosts file (/etc/hosts):
127.0.1.1 larapoints.loc
Auth:
- /auth/jwt/register
- /auth/jwt/login
- /auth/jwt/logout
- /auth/jwt/refresh
- /auth/jwt/password/request/reset
- /auth/jwt/password/otp/verify
- /auth/jwt/password/reset
User:
- /user/me
- /user/update
There is a lot of methods to support versioning in your API, LaraPoints use URI versioning and directory structure and OOP inheritance to support backward compatibility and DRY principle when it is possible.
- Directory structure and namespaces:
To support versioning the application main controllers places in a directory with the same verizon name (v1 for example) to handle v1 API implementation under the following path (app/Http/Controllers/API/V1), if you want to implement V2 of your API for example you create V2 folder in (app/Http/Controllers/API) directory path and make your implementation there.
All namespaces of your controllers should have a namespace related to the directory version of your API.
Example : namespace App\Http\Controllers\API\V1;
- Routing:
To support URI versioning LaraPoints use the following methodology :
1- In routes folder there is a new folder created (api) and inside this folder the routes distributed based on the API version in a file for each version, v1.php for version one for example.
2- RouteServiceProvider.php file modified to load the routes on the previous step and inject the appropriate namespace for each version.
- V2 implementation:
When you face breaking changes, you will have to release a new version of your API, LaraPoints already contains a suggested implementation of V2, this implementation placed under (app/Http/Controllers/API/V2), this implementation supporting backward compatibility and applying DRY principle when it is possible, you can use the same methodology or use your own way that fits your application needs better.
- Postman :
When it comes to an API documentation it is recommended to use Postman, it is highly powerful and flexible tool and easy to implement and one of the best tools to test your API.
LaraPoints has available Postman implementation ready to use here :
https://documenter.getpostman.com/view/3215735/SzRxXWdP?version=latest
- Swagger UI :
LaraPoints supports Swagger UI using OpenApi tags as the following:
- API documentation path:
http://larapoints.loc/api/documentation
- Auto generating API documentation:
LaraPoints integrated with L5-Swagger library to auto generate the documentation of the API endpoints using Open API Annotations.
Example:
GET request:
/**
* Get a user profile
*
* @return mixed
*
* Swagger UI documentation (OA)
*
* @OA\Get(
* path="/user/me",
* tags={"User"},
* summary="Get the authenticated User",
* description="Get the authenticated User",
* operationId="UserMe",
* @OA\Response(
* response="200",
* description="ok",
* content={
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* @OA\Property(
* property="message",
* type="string",
* description="Response message",
* ),
* @OA\Property(
* property="data",
* type="object",
* description="Response data",
* ref="#/components/schemas/User"
* ),
* @OA\Property(
* property="errors",
* type="null",
* description="response errors",
* ),
* example={
* "message": "JWT token refresh successfully",
* "data": {
* "id": 1,
* "name": "Hamza al darawsheh",
* "email": "[email protected]",
* "email_verified_at": null,
* "created_at": "2020-03-20T09:10:32.000000Z",
* "updated_at": "2020-05-08T20:39:06.000000Z"
* },
* "errors": null
* }
* )
* )
* }
* ),
* @OA\Response(
* response="401",
* description="Unauthorized",
* content={
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* @OA\Property(
* property="message",
* type="string",
* description="Response message",
* ),
* @OA\Property(
* property="data",
* type="null",
* description="Response data",
* ),
* @OA\Property(
* property="errors",
* type="object",
* description="response errors",
* @OA\Property(
* property="unauthorized",
* type="string",
* description="Unauthorized error message",
* ),
* ),
* example={
* "message": "Unauthorized",
* "data": null,
* "errors": {
* "unauthorized": "Unauthorized request"
* }
*
* }
* )
* )
* }
* ),
* security={
* {"bearerJWTAuth": {}}
* }
* )
*/
POST request:
/**
* Get a JWT via given credentials.
*
* @return mixed
*
* Swagger UI documentation (OA)
*
* @OA\Post(
* path="/auth/jwt/login",
* tags={"Auth"},
* summary="JWT login",
* description="Login a user and generate JWT token",
* operationId="jwtLogin",
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property="email",
* description="User email",
* type="string",
* example="[email protected]"
* ),
* @OA\Property(
* property="password",
* description="User password",
* type="string",
* example="larapoints123"
* ),
* )
* )
* ),
* @OA\Response(
* response="200",
* description="ok",
* content={
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* @OA\Property(
* property="message",
* type="string",
* description="Response message",
* ),
* @OA\Property(
* property="data",
* type="object",
* description="Response data",
* @OA\Property(
* property="access_token",
* type="string",
* description="JWT access token",
* ),
* @OA\Property(
* property="token_type",
* type="string",
* description="Token type"
* ),
* @OA\Property(
* property="expires_in",
* type="integer",
* description="Token expiration in miliseconds",
* ),
* ),
* @OA\Property(
* property="errors",
* type="null",
* description="response errors",
* ),
* example={
* "message": "User logged in successfully",
* "data": {
* "access_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
* "token_type": "bearer",
* "expires_in": 3600
* },
* "errors": null
* }
* )
* )
* }
* ),
* @OA\Response(
* response="401",
* description="Unauthorized",
* content={
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* @OA\Property(
* property="message",
* type="string",
* description="Response message",
* ),
* @OA\Property(
* property="data",
* type="null",
* description="Response data",
* ),
* @OA\Property(
* property="errors",
* type="object",
* description="response errors",
* @OA\Property(
* property="wrong_credentials",
* type="string",
* description="Wrong credentials error message",
* ),
* ),
* example={
* "message": "Wrong credentials",
* "data": null,
* "errors": {
* "wrong_credentials": "The provided credentials don't match our records"
* }
*
* }
* )
* )
* }
* ),
* security={
* {"bearerJWTAuth": {}}
* }
* )
*/
Model example:
/**
* @OA\Schema(@OA\Xml(name="User"))
*
* @OA\Property(
* property="id",
* type="string",
* description="User ID"
* )
*
* @OA\Property(
* property="name",
* type="string",
* description="User name"
* )
*
* @OA\Property(
* property="email",
* type="string",
* description="User email"
* )
*
* @OA\Property(
* property="email_verified_at",
* type="string",
* description="Email verified at"
* )
*
* @OA\Property(
* property="created_at",
* type="string",
* description="Created at"
* )
*
* @OA\Property(
* property="updated_at",
* type="string",
* description="Updated at"
* )
*
*/
To generate the API documentation apply the following command:
$ php artisan l5-swagger:generate