A starter kit for building a restful API in PHP, with server-side and client-side sample code
These days, if you want a scalable web application, at some point you?re going to have to consider building cloud-based API services, micro or otherwise, that allow your distributed applications the ability to share common functions.
This article is going to show you how to build a simple restful API in PHP. We?re going to build a server-side API that receives an API key from the client, connects to a MySQL database for the API Secret Key, and then returns a JSON Web Token (JWT) that?s secured with the Secret Key.
The client-side application is a simple PHP page that makes a call to the API to retrieve a token and then stores it in a cookie before writing out the page. The page itself includes some simple jQuery that allows you to delete the cookie and then retrieve a new token using the same API interface through JavaScript. The goal is to provide you a single page where you can see PHP and JavaScript code calling the same API.
I?ve also included some MySQL scripts to build our sample database.
When we?re done, you?ll have some solid foundational code you can extend to create your own applications. In fact, future articles I write will come back and refine and build upon this API project to provide other types of real-world services.
Let?s get started!
The Sample Code
All of the sample code is available in the following three GitHub repositories. Feel free to download and use this code any way you want, without attribution:
- Back-end API: medium-php-api-starter
- Client-side front end: medium-php-api-starter-client
- Database scripts: medium-php-api-starter-dbscripts
I obviously built this project on my localhost with the back-end API in one project and the client-side front end in a separate project. To make this simple demonstration work, there are some hardcoded references (e.g., database connection details, API host URL, etc). I?ll come back in a later article, and we?ll refine our project by moving these things into INI files and database tables so we don?t have those things in our code. But for now, the idea is to just keep it simple.
I decided on separate repositories for everything because I do intend to come back and build on this project in later articles. The master branch in each repository will always be the most current version of the code, but I?ll leave each feature branch in the repository so you can roll back at any time and work with the application at any stage. That being said, each of these repositories contain a branch called original which will be the code we work with here as a starting point.
As a side note, my development environment is set up entirely in Docker containers using the instructions you can find in my recent article, ?How to Run Your Entire Development Environment in Docker Containers on macOS.?
Database Scripts
Let?s start by running the MySQL database scripts. There are only two. One creates the api_starter database and the second one creates an app_api_key table that?ll be indexed by the API Key and provide the API back end with an associated Secret Key to use for encoding the JWT.
To clone this repository to your machine, open a terminal window and navigate to the location you want to use for your projects (I personally have a Sites folder in my root user folder). Use the following command to pull down the original branch for this repository:
Note: The following Git commands are a single line that has wrapped. Make sure to copy and paste the whole thing.
git clone -b original https://github.com/crmcmullen/medium-php-api-starter-dbscripts.git phpapistarter_dbscripts
Open your favorite MySQL tool of choice (I use MySQL Workbench) and run apistarter.sql. This will build the database and the database user that?ll be used in this project.
Next run apistarter_app_api_key.sql. This will build the app_api_key table, insert a single record into it that we?ll use in our example, and then build a view over the table.
That?s it for the database. Pretty simple.
Server-Side API Back End
Next, pull down the back-end code for the API. Once again, I open terminal and navigate into my Sites folder. In my project, I use a folder called phpapistarter for the API server code, and you?ll see that referenced as the API host in the code. If you use a different folder, make sure to update that in the code.
git clone -b original https://github.com/crmcmullen/medium-php-api-starter.git phpapistarter
The API service has the following files:
index.php
A straightforward page that allows cross-origin requests. It prerequires all the necessary classes, validates the incoming API request, and hands the function request to the API handler.
/src/api_handler.php
This is the heart of the API service. The loadFunctionMap function preloads all of the public facing end points and the classes to which they belong into an array. The array allows you to alias the function names internally if you want. For example, if the public facing end point was getToken but internally in your code you referred to the function_name as fnGetToken, you could do that. In this first version, the only valid end point will be getToken.
Future end points will need to be added to this array. If the end point doesn?t exist in the array, an invalid method call error will be raise to the client.
The validateRequest function evaluates the request to make sure it includes an API Key and Token, retrieves the caller?s app_api_key record and uses the API Secret Key to decode the JWT. It then makes sure all the things match and that the token isn?t expired.
The getCommand function retrieves the class and internal function name from the function map, and execCommand converts it into a function call with associated parameters.
Of course the getToken command is one of the core API end-point commands in the API Handler and the focus of this demo.
/src/app_autoloader.php
This file preregisters all of the classes that?ll be referenced by the API and will speed up class loading.
/src/app_jwt.php
This class is built on the JSON Web Token encoder/decoder code provided by Neuman Vong and Anant Narayanan here.
/src/app_response.php
A simple class library that provides standard HTML response codes and descriptions.
/src/db_classes/data_access.php
This abstract class is extended by other database classes and provides connectivity to the MySQL database via the db_connect function, as well as an abstract function for retrieving a ResultSet array with getResultSetArray.
Note that db_connect has the connection variables hardcoded in. These will be replaced in a later project, where we?ll move these to an INI file.
/src/db_classes/app_api_key.php
This is the database class for the app_api_key database table. At the moment, it simply has one method and that?s to retrieve the caller?s API record for the API Secret Key in order to encode/decode a token.
And that?s it for the API service. Granted, it only has one end point of its own. But the framework is now in place to add other API end points in the future.
Client-Side Application
For the client-side application I used a folder called phpapistarter_client. You can pull the code by navigating into your Sites folder and using the following command:
git clone -b original https://github.com/crmcmullen/medium-php-api-starter-client.git phpapistarter_client
If you use the same project folders as me (e.g., phpapistarter and phpapistarter_client), you can immediately open this project in your browser at http://localhost/phpapistarter_client and start playing with it.
This client app really isn?t rocket science. It?s a single page with two JavaScript files.
index.php
If no cookie exists, this page makes an API call to the getToken endpoint to retrieve a token. It then packages that token up in a cookie.
You?ll notice the API Key and API Host are hardcoded. A later article will move these values into an INI file and database table so they?re not in the source code. I was just trying to simplify things here.
From a process standpoint, however, this would be how you?d want to retrieve the token in production, since the entire transaction would happen on the server side prior to writing the page.
The HTML portion of the page itself is pretty basic. It displays the token that was created and provides a button to delete it and a second button to retrieve a new token with a JavaScript call to the exact same API. This provides you with code that shows you how to make the same API call both in PHP and JavaScript.
I?ve also used Bootstrap just to add some basic CSS.
/js/api_handler.js
This Javascript file is a generic jQuery API handler. Pass it some variables, and it makes the call for you and then performs a callback.
Normally, you wouldn?t pass the API Key or API Host as variables. Instead this JavaScript would retrieve the cookie and get those variables along with the token and pass them in the API call. However, since this demo is potentially making an API call when there?s no cookie, we need to do things a little differently.
Once again, a later article will fix this. The PHP code will always create the cookie, and this JavaScript will pull what it needs from it for subsequent calls.
/js/cookie_handler.js
A JavaScript file with very basic and generic cookie-handling functions.
Summary
That?s it for this article. With this little bit of demo code you?ve got a great start to a PHP restful-API service. I?ll write some future articles that?ll build on this project and show you how you can set up the API Handler on the server to make calls to additional real-world type classes and even connect with other services like SendGrid e-mail or Google reCAPTCHA validations.
I hope this article and supporting code helps you with your projects.