PHPMaker supports REST API that enables you to perform CRUD (Create, Read, Update and Delete) for the tables in the generated web application. You can issue the request to the API (e.g. via JavaScript codes), get the response as JSON (Javascript Object Notation), interpret and present the result as you like it. The default address for the API request is the api subfolder of the generated application (i.e. <mysite>/api).
The REST API is implemented on the basis of the list, view, add, edit and delete pages supported for each table selected for generation. The basic supported API actions are add (Create), list / view (Read), edit (Update), delete (Delete), login (Authenticate User, if Security is enabled) and file (Get file content).
The standard exchange of information with the API is shown in the following examples (using the "cars" table of the demo database for demonstration):
Example 1 - Get a record by key (view action)
- Javascript (Assuming "input-id" is an input for key value)
$("#input-id").change(function() {
var url = "api/", object = "<Table>", action = "view", key = encodeURIComponent($(this).val());
//$.get(url + "/" + action + "/" + object + "/" + key, function(res) { // URL format if URL Rewrite enabled
$.get(url + "?action=" + action + "&object=" + object + "&key=" + key, function(res) { // Get response from View page API
if (res && res.success) {
var row = res[object];
alert(JSON.stringify(row)); // Show output JSON
} else {
alert(res.failureMessage);
}
});
});
- HTTP Request
GET /api/?action=view&object=cars&key=1 (or /api/view/cars/1, if URL Rewrite is enabled. See the URL Rewrite section for more details)
Accept: application/json
- HTTP Response
200 OK
{
"success": true,
"version": "15.0.0",
"cars": {
"ID": 1,
"Trademark": 1,
...
}
}
Example 2 - Create a record (add action)
- Javascript (Assuming "btn-id" is the submit button for the add form)
$("#btn-id").click(function() {
var url = "api/", object = "<Table>", action = "add", data = $(this.form).serialize();
data += "&action=" + encodeURIComponent(action) + "&object=" + encodeURIComponent(object);
//$.post(url + "/" + action + "/" + object, data, function(res) { // URL format if URL Rewrite enabled
$.post(url, data, function(res) { // Get response from Add page API
if (res && res.success) {
var row = res[object];
alert(JSON.stringify(row)); // Show output JSON
} else {
alert(res.failureMessage);
}
});
});
- HTTP Request
POST /api/
action=add&object=cars&Trademark=1&...
Accept: application/json
If your data is JSON, the HTTP request should be:
POST /api/
{ "action": "add", "object": "cars", "Trademark": 1, ... }
Content-Type: application/json
Accept: application/json
Notes
- HTTP Response (success)
200 OK
{
"success": true,
"version": "15.0.0",
"cars": {
"ID": 16,
"Trademark": 1,
...
}
}
- HTTP Response (failure)
200 OK
{
"success": false,
"version": "15.0.0",
"failureMessage": "<failed reason>"
}
The following actions are supported. For list/view/file actions, the request is expected as HTTP GET, for other actions the request is expected as HTTP POST.
Action | Parameters | Request | Response |
list (Get list of records) | action=list object=<Table> start=<StartRecordNumber> (Optional, start record number, default = 1) recperpage=<RecordsPerPage> (Optional, record per page, default = [Records per page] setting, requires activating the [Selectable page sizes] setting) order=<Field> (Optional, sort by the specified field, requires activating the [Sort] setting in list page) orderby=ASC|DESC (Optional, sort ascending (ASC) or descending (DESC), requires activating the [Sort] setting in list page) <Field>=<FieldValue> (Optional, search field by value, requires activating the [Advanced/Extended Search] setting in list page) |
Without URL Rewrite GET /api/?action=list&object=cars With URL Rewrite GET /api/list/cars |
Successful response { "success": true,"version": "15.0.0", "cars": [ { "ID": 1, "Trademark": 1, ... }, { "ID": 2, "Trademark": 1, ... } ] } Failed response { "success": false,"version": "15.0.0", "failureMessage": "<failed reason>" } |
view (Get single record by key) | action=view object=<Table> <KeyField>=<KeyFieldValue> (key field value) |
Without URL Rewrite GET /api/?action=view&object=cars&ID=1 With URL Rewrite GET /api/view/cars/1 |
Successful response { "success": true, "version": "15.0.0", "cars": { "ID": 1, "Trademark": 1, ... } } Failed response See failed response for list |
add (Insert a new record) | action=add object=<Table> <Field>=<FieldValue> (field to be inserted) |
Without URL Rewrite POST /api/ action=add&object=cars&Trademark=1&... With URL Rewrite POST /api/add/cars Trademark=1&... |
Successful response { "success": true, "version": "15.0.0", "cars": { "ID": 16, "Trademark": 1, ... } } Failed response See failed response for list |
edit (Update an existing record by key) | action=edit object=<Table> <KeyField>=<KeyFieldValue> (key field value) <Field>=<FieldValue> (field to be updated) |
Without URL Rewrite POST /api/ action=edit&object=cars&ID=1&Trademark=2&... With URL Rewrite POST /api/edit/cars/1 Trademark=2&... |
Successful response { "success": true, "version": "15.0.0", "cars": { "Trademark": 2, ... } } Failed response See failed response for list |
delete (Delete an existing record by key) | action=delete object=<Table> <KeyField>=<KeyFieldValue> (key field value) |
Without URL Rewrite POST /api/ action=delete&object=cars&ID=1 With URL Rewrite POST /api/delete/cars/1 |
Successful response { "success": true, "version": "15.0.0", "cars": { "ID": 1, "Trademark": 1, ... } } Failed response See failed response for list |
login (Authenticate an user, see Authenticate user with JWT) | action=login username=<UserName> (user name value) password=<Password> (password value) |
Without URL Rewrite POST /api/ action=login&username=admin&password=master With URL Rewrite POST /api/login username=admin&password=master |
Successful response { "JWT": "<JsonWebToken>" } Failed response 401 Unauthorized |
file (Get file content) | action=file object=<Table> field=<Field> <KeyField>=<KeyFieldValue> (key field value) |
Without URL Rewrite GET /api/?action=file&object=cars&field=Picture&key=1 With URL Rewrite GET /api/file/cars/Picture/1 |
Successful response For blob field (e.g. Picture field in cars table), binary content of file field with the correct content type For string field (e.g. Photo field in employees table), JSON response of file locations: { "Photo": { "EmpID1.jpg": "http://<my-site>/upload/EmpID1.jpg" }, "version": "15.0.0" } Failed response Empty response |
To improve the usability and search friendliness of the API URL, it is recommended that you setup URL Rewrite for your site so that the URL is much cleaner and easier to read and remember. Compare:
/api/?action=view&object=cars&ID=1, and
/api/view/cars/1
you will see the difference.
To use the URL Rewrite feature, all you need to do is to map all URL beyond the API path to the index.php page of the API path (i.e. /api/* => /api/index.php).
For Apache, you need to enabled the mod_rewrite module by creating an .htaccess file in the API folder
with the following rewrite rules:
RewriteEngine On # Turn on the rewriting engine
RewriteRule ^.*$ /index.php [L,QSA]
To understand more about the Apache mod_rewrite module, please refer to Apache web site:
https://httpd.apache.org/docs/current/mod/mod_rewrite.html
For Internet Information Services (IIS), the URL Rewrite module is not built-in, so you need to download and install
the IIS URL Rewrite module from the microsoft web site below first:
https://www.iis.net/downloads/microsoft/url-rewrite
After installing, you should be able to see URL Rewrite module in IIS for your web site. To perform the mapping:
- Select your site
- Double click the URL Rewrite module
- Click Add Rule(s) and select Blank rule under Inbound rules
- Enter a Name (e.g. api) and set other settings as follows: (assume the api is under <mysite>/api)
Click the Apply button to save the rule.
To understand more about the IIS URL Rewrite, please refer to the Microsoft article:
https://docs.microsoft.com/en-us/iis/extensions/url-rewrite-module/using-the-url-rewrite-module
REST API is stateless. Each API request is independent of each other and no session data is stored in the server to record the current state of the API requests. To access protected resources from the API, you need to authenticate the user first by getting a JSON Web Token (JWT) using the login action, then pass the JWT as an authentication header in subsequent API requests. Note that each JWT has a limited timespan, so you may need to re-authenticate the user again once the token has expired.
You can customize the following JWT parameters via Tools -> Advanced Settings.
Settings | Description | Value |
API JWT signing secret key | The secret key used to sign the JWT. | Non-optional, make sure you use different values for different projects and keep it in a secret place |
API JWT signing algorithm | The algorithm used to sign the JWT. | Default is HS512. For more possible values refer to JWT web site below. |
API JWT authorization header | The name of the header storing the JWT. | Default is X-Authorization |
API access time after login (seconds) | Time you can access the protected resources after login | Default is 10. If you want immediate access, you can change it to 0. |
API expire time after login (seconds) | The JWT expiry time | Default is 600 (10 minutes). You will need to authenticate again once the JWT expires. |
To understand more about JWT, please visit:
https://jwt.io/introduction/
The following Javascript shows how to get a protected resource from the API by JWT. Authenticate the user first by
clicking the login button. Then click the Get order record button to get the order record
which is a protected resource.
$(function() {
var store = store || {};
/*
* Store JWT
*/
store.setJWT = function(data) {
this.JWT = data;
}
/*
* Login
*/
$("#frm-login").submit(function(e) {
e.preventDefault();
var data = $("#frm-login").serialize();
data += '&action=login';
//$.post("api/login", data, function(data) { // URL Rewrite
$.post("api/", data, function(data) {
$("button").removeAttr("disabled");
store.setJWT(data.JWT);
}).fail(function(xhr, status, error) {
alert("login failed. status: " + status + ", error: " + error);
});
});
/*
* Get protected resource
*/
var getProtectedResource = function(e) {
e.preventDefault();
$.ajax({
//url: "api/view/orders/10248", // URL Rewrite
url: "api/?action=view&object=orders&OrderID=10248",
type: "GET",
success: function(data, status, xhr) {
var out = (data && typeof data === 'object') ? JSON.stringify(data) : data;
alert(out);
},
error: function (xhr, ajaxOptions, thrownError) {
alert("status: " + xhr.status + ", error: " + thrownError);
},
beforeSend: function(request) { // Set JWT header
request.setRequestHeader('X-Authorization', 'Bearer ' + store.JWT);
}
});
}
$("#btn-with-token").click(getProtectedResource);
});
<form id="frm-login" method="post">
User name: <input type="text" name="username" value="admin">
Password: <input type="text" name="password" value="master">
<input type="submit" value="Login">
</form>
<button id="btn-with-token" type="button" disabled>Get order record</button>
Beside the built-in API actions, you can add new API actions by writing your custom API handler and put the codes in server side Global Code (see Server Events and Client Scripts).
Example 1 - Hello world
$API_ACTIONS["hello"] = function(Request $request, Response &$response) {
Write("Hello " . Param("user", Route(1))); // Get parameter from $_GET or $_POST
};
The user can now access the URL /api/?action=hello?user=John (or /api/hello/John for URL Rewrite) to get the response text
"Hello John".
Example 2 - Get product by product name
$API_ACTIONS["getProductByName"] = function(Request $request, Response &$response) {
$name = Param("name", Route(1)); // Get parameter from $_GET or $_POST
if ($name !== NULL)
WriteJson(ExecuteRow("SELECT * FROM products WHERE ProductName = '" . AdjustSql($name) . "'"));
};
The product data can now be accessed using the following JavaScript:
//$.get("api/getProductByName/Chai", function(res) { // URL format if URL Rewrite enabled
$.get("api/?action=getProductByName&name=Chai", function(res) { // Get response from API
console.log(res); // Show the result in console
});