Skip to content

This is a basic API REST skeleton written on Phalcon PHP. Great For building an MVP for your frontend app (Vue, react, angular, or anything that can consume an API)

License

Notifications You must be signed in to change notification settings

davellanedam/phalcon-micro-rest-api-skeleton

Repository files navigation

Phalcon Micro REST API Basic Project Skeleton

Author Software License Release

Getting started

This is a basic API REST skeleton written on the ultra hyper mega fastest framework for PHP phalcon. A full-stack PHP framework delivered as a C-extension. Its innovative architecture makes Phalcon the fastest PHP framework ever built!

This project is created to help other developers create a basic REST API in an easy way with phalcon. This basic example shows how powerful and simple phalcon can be. Do you want to contribute? Pull requests are always welcome to show more features of phalcon.

Features

  • JWT Tokens, provide login with Authorization header with value Basic username:password where username:password MUST BE ENCODED with Base64.
  • Make requests with a token after login with Authorization header with value Bearer yourToken where yourToken is the signed and encrypted token given in the response from the login process.
  • Use ACL so you can have roles for users.
  • Timezone ready: Work UTC time (GMT+0). Responses with iso8601 date/time format.
  • Pagination ready.
  • Filters (JSON).
  • Easy deploy to staging and production environments with rsync.
  • Internationalization ready. API responses use JSON format to make life easier at the frontend.
  • Separate database for logs.
  • User profile.
  • Users list.
  • Cities. (Example of use: call cities API, then send name of the city when creating or updating a user.
  • Integrated tests

Requirements

  • Apache 2
  • PHP 5.6+
  • Phalcon 3.2+
  • MySQL 5.5+

How to install

Using Git (recommended)

  1. First you need to install composer if you haven´t already.
  2. Clone the project from github. Change 'myproject' to you project name.
git clone https://github.com/davellanedam/phalcon-micro-api.git ./myproject

Using manual download ZIP

  1. Download repository
  2. Uncompress to your desired directory

Install composer dependencies after installing (Git or manual download)

cd myproject
composer install
composer update

Database Configuration and Security

There are 3 files in the /myproject/config directory, (development, staging and production) each one is meant to be used on different environments to make your life easier on deployment.

  1. Create a MySQL database with your custom name and then import myproject.sql (in the /schemas directory)
  2. Create a second MySQL database with your custom name and then import myproject_log.sql (in the /schemas directory).
  3. Open /myproject/config/server.development.php and setup your DEVELOPMENT (local) database connection credentials
  4. Open /myproject/config/server.staging.php and setup your STAGING (testing server) database connection credentials
  5. Open /myproject/config/server.production.php and setup your PRODUCTION (production server) database connection credentials

This is the structure of those 3 files, remember to change values for yours.

return [
    'database' => [
        'adapter' => 'Mysql', /* Possible Values: Mysql, Postgres, Sqlite */
        'host' => 'your_ip_or_hostname',
        'username' => 'your_db_username',
        'password' => 'your_db_password',
        'dbname' => 'your_database_schema',
        'charset' => 'utf8',
    ],
    'log_database' => [
        'adapter' => 'Mysql', /* Possible Values: Mysql, Postgres, Sqlite */
        'host' => 'your_ip_or_hostname',
        'username' => 'your_db_username',
        'password' => 'your_db_password',
        'dbname' => 'myproject_log',
        'charset' => 'utf8',
    ],
    'authentication' => [
        'secret' => 'your secret key to SIGN token', // This will sign the token. (still insecure)
        'encryption_key' => 'Your ultra secret key to ENCRYPT the token', // Secure token with an ultra password
        'expiration_time' => 86400 * 7, // One week till token expires
        'iss' => 'myproject', // Token issuer eg. www.myproject.com
        'aud' => 'myproject', // Token audience eg. www.myproject.com
    ]
];

Setting up environments

The ENV variable is set on an .htaccess file located at /public/.htaccess that you must upload once to each server you use. Change the environment variable on each server to what you need. To make your life easy this .htaccess file is on the excluded files list to upload when you make a deploy. Possible values are: development, staging and production.

############################################################
# Possible values: development, staging, production        #
# Change value and upload ONCE to your server              #
# AVOID re-uploading when deployment, things will go crazy #
############################################################
SetEnv APPLICATION_ENV "development"

Usage

Once everything is set up to test API routes either use Postman or any other api testing application. Remember to change the URL of the provided example Postman JSON file. Default username/password combination for login is admin/admin1234.

If you use Postman please go to manage environments and then create one for each of your servers. Create a new key authToken with token value (the token you got from the login process), each time you make a request to the API it will send Authorization header with the token value in the request, you can check this on the headers of users or cities endpoints in the Postman example.

This is a REST API, so it works using the following HTTP methods:

  • GET (Read): Gets a list of items, or a single item
  • POST (Create): Creates an item
  • PATCH (Update): Updates an item
  • DELETE: Deletes an item

Testing

There are some tests included, to run tests you need to go to the command line and type:

composer test

Creating new models

If you need to add more models to the project there´s an easy way to do it with phalcondevtools (If you did composer install, you already have this). Step into a terminal window and open your project folder, then type the following and you are set!

phalcon model --name=your_table_name --schema=your_database --mapcolumn

Creating new controllers

If you need to add more controllers to the project there´s an easy way to do it with phalcondevtools (If you did composer install, you already have this). Step into a terminal window and open your project folder, then type the following.

phalcon controller --name=your_controller_name_without_the_controller_word

When it´s done, it creates your new controller, but if you want to use ControllerBase.php functions in your newly created controller you must change the following line in the new controller:

class MyNewController extends \Phalcon\Mvc\Controller

to this:

class MyNewController extends ControllerBase

Creating new routes

You can add more routes to your project by adding them into the /app.php file. This is an example of /users routes:

/**
* Users
*/
$users = new MicroCollection();
$users->setHandler('UsersController', true);
$users->setPrefix('/users');
// Gets all users
$users->get('/', 'index');
// Creates a new user
$users->post('/create', 'create');
// Gets user based on unique key
$users->get('/get/{id}', 'get');
// Updates user based on unique key
$users->patch('/update/{id}', 'update');
// Changes user password
$users->patch('/change-password/{id}', 'changePassword');
// Adds users routes to $app
$app->mount($users);

Remember to add the controller (without the controller word) and methods of endpoints to the /config/acl.phpfile. Otherwise you will get this response from the API: 'common.YOUR_USER_ROLE_DOES_NOT_HAVE_THIS_FEATURE',

/*
 * RESOURCES
 * for each user, specify the 'controller' and 'method' they have access to ('user_type'=>['controller'=>['method','method','...']],...)
 * */
$arrResources = [
    'Guest'=>[
        'Users'=>['login'],
    ],
    'User'=>[
        'Profile'=>['index','update','changePassword'],
        'Users'=>['index','create','get','search','update','logout'],
        'Cities'=>['index','create','get','ajax','update','delete'],
    ],
    'Superuser'=>[
        'Users'=>['changePassword'],
    ]
];

Always keep in mind the following:

/*
 * ROLES
 * Superuser - can do anything (Guest, User, and own things)
 * User - can do most things (Guest and own things)
 * Guest - Public
 * */

Internationalization

API is designed to response with a JSON, so at the FRONTEND you can use lang files like this: Put your language files in 'langs' directory at frontend:

  • en.json
  • es.json

Example of language file en.json :

{
  "common": {
    "HEADER_AUTHORIZATION_NOT_SENT": "Header Authorization not sent",
    "EMPTY_TOKEN_OR_NOT_RECEIVED": "Empty token or not received",
    "YOUR_USER_ROLE_DOES_NOT_HAVE_THIS_FEATURE": "Your user role does not have this feature",
    "BAD_TOKEN_GET_A_NEW_ONE": "Bad token, get a new one",
    "SUCCESSFUL_REQUEST": "Succesfull request",
    "CREATED_SUCCESSFULLY": "Created successfully",
    "THERE_IS_ALREADY_A_RECORD_WITH_THAT_NAME": "There is already a record with that name",
    "UPDATED_SUCCESSFULLY": "Updated successfully",
    "DELETED_SUCCESSFULLY": "Deleted successfully",
    "THERE_HAS_BEEN_AN_ERROR": "There has been an error",
    "INCOMPLETE_DATA_RECEIVED": "Incomplete data received",
    "NO_RECORDS": "No records",
    "COULD_NOT_BE_CREATED": "Could not be created",
    "NOT_FOUND": "Not found",
    "COULD_NOT_BE_DELETED": "Could not be deleted",
    "COULD_NOT_BE_UPDATED": "Could not be updated"
  },
  "login": {
    "USER_IS_NOT_REGISTERED": "User is not registered",
    "USER_BLOCKED": "User blocked",
    "USER_UNAUTHORIZED": "User unauthorized",
    "WRONG_USER_PASSWORD": "Wrong user password",
    "TOO_MANY_FAILED_LOGIN_ATTEMPTS": "Too many failed login attempts"
  },
  "profile": {
    "PROFILE_NOT_FOUND": "Profile not found",
    "PROFILE_UPDATED": "Profile updated",
    "PROFILE_COULD_NOT_BE_UPDATED": "Profile could not be updated",
    "ANOTHER_USER_ALREADY_REGISTERED_WITH_THIS_USERNAME": "Another user already registered with this username"
  },
  "change-password": {
    "PASSWORD_COULD_NOT_BE_UPDATED": "Password could not be updated",
    "PASSWORD_SUCCESSFULLY_UPDATED": "Password updated successfully",
    "WRONG_CURRENT_PASSWORD": "Wrong current password"
  }
}

Example of language file es.json :

{
  "common": {
    "HEADER_AUTHORIZATION_NOT_SENT": "Cabezote Authorization no enviado",
    "EMPTY_TOKEN_OR_NOT_RECEIVED": "Token vacío o no recibido",
    "YOUR_USER_ROLE_DOES_NOT_HAVE_THIS_FEATURE": "Tu rol de usuario no tiene esta característica",
    "BAD_TOKEN_GET_A_NEW_ONE": "Token errado, solicita uno nuevo",
    "SUCCESSFUL_REQUEST": "Solicitud exitosa",
    "CREATED_SUCCESSFULLY": "Creado ecitosamente",
    "THERE_IS_ALREADY_A_RECORD_WITH_THAT_NAME": "Ya existe un registro con ese nombre",
    "UPDATED_SUCCESSFULLY": "Actualizado exitosamente",
    "DELETED_SUCCESSFULLY": "Eliminado exitosamente",
    "THERE_HAS_BEEN_AN_ERROR": "Ha ocurrido un error",
    "INCOMPLETE_DATA_RECEIVED": "Datos incompletos recibidos",
    "NO_RECORDS": "No hay registros",
    "COULD_NOT_BE_CREATED": "No se pudo crear",
    "NOT_FOUND": "No encontrado",
    "COULD_NOT_BE_DELETED": "No pudo ser eliminado",
    "COULD_NOT_BE_UPDATED": "No pudo ser actualizado"
  },
  "login": {
    "USER_IS_NOT_REGISTERED": "Usuario no está registrado",
    "USER_BLOCKED": "Usuario bloqueado",
    "USER_UNAUTHORIZED": "Usuario no autorizado",
    "WRONG_USER_PASSWORD": "Contraseña de usuario errada",
    "TOO_MANY_FAILED_LOGIN_ATTEMPTS": "Demasiados intento de ingreso fallidos"
  },
  "profile": {
    "PROFILE_NOT_FOUND": "Perfil no encontrado",
    "PROFILE_UPDATED": "Perfil actualizado",
    "PROFILE_COULD_NOT_BE_UPDATED": "Perfil no pudo ser actualizado",
    "ANOTHER_USER_ALREADY_REGISTERED_WITH_THIS_USERNAME": "Otro usuario ya se encuentra registrado con este nombre de usuario"
  },
  "change-password": {
    "PASSWORD_COULD_NOT_BE_UPDATED": "Contraseña no pudo ser actualizada",
    "PASSWORD_SUCCESSFULLY_UPDATED": "Contraseña actualizada exitosamente",
    "WRONG_CURRENT_PASSWORD": "Contraseña actual errada"
  }
}

Deployment

You can make a deploy to staging or production servers. It will run a bash file with rsync command to sync your project directory to the servers project directory. Step into a terminal window and open your project folder, then type the following.

Deploy to staging server

deploy-staging.sh

Deploy to production server

deploy-production.sh

Do not forget to change variables to yours on each .sh file

PROJECT=myproject
USER=server_username
URL=my_staging_server_url

Excluding files on deploy

You can exclude files on each deployment environment (/exclude-production.txt and /exclude-staging.txt), add files you want to be excluded on the corresponding .txt file. Each excluded file or directory must be on a new line. Staging exclusion list example:

.git/
*.DS_Store
.phalcon/
.php/
cache/
.htaccess
exclude-staging.txt
exclude-production.txt
deploy-staging.sh
deploy-production.sh
config/server.development.php
config/server.production.php
public/.htaccess
schemas/

Bugs or improvements

Feel free to report any bugs or improvements. Pull requests are always welcome.

I love this! How can I help

It´s amazing you feel like that! Send me a tweet https://twitter.com/davellanedam, share this with others, make a pull request or if you feel really thankful you can always buy me a beer! Enjoy!

License

This project is open-sourced software licensed under the MIT License. See the LICENSE file for more information.