Skip to content

LaraPoints is a REST API skeleton using Laravel framework.

License

Notifications You must be signed in to change notification settings

ihamzehald/larapoints

Repository files navigation

LaraPoints

LaraPoints is a REST API skeleton using Laravel framework.

LaraPoints project goal

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!


How to use

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

Available endpoints

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

API versioning

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.

API Documentation

  • 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