
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 code), get the response as JSON (JavaScript Object Notation), interpret and present the result as you like it. The default path for the API request is "api" under the generated application (i.e. <mysite>/api).
API Actions
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 object = "<Table>", key = encodeURIComponent($(this).val()); $.get("/api/view/" + object + "/" + 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); } }); });
{ "success": true, "version": "18.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 object = "<Table>", data = $(this.form).serialize(); $.post("/api/add/" + object, 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
If your data is JSON, the HTTP request should be:
POST /api/add/cars
{ "Trademark": 1, ... }
Content-Type: application/json
Accept: application/json
{ "success": true, "version": "18.0.0", "cars": { "ID": 16, "Trademark": 1, ... } }HTTP Response (failure)
{ "success": false, "version": "18.0.0", "failureMessage": "<failed reason>" }
The following actions are supported:
| Action | Parameters | Response |
GET /api/list/{table} Get list of records, e.g. /api/list/cars |
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) ordertype=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) |
Successful response { "success": true,"version": "18.0.0", "cars": [ { "ID": 1, "Trademark": 1, ... }, { "ID": 2, "Trademark": 1, ... } ] } Failed response { "success": false,"version": "18.0.0", "failureMessage": "<failed reason>" } |
GET /api/view/{table}/{key} Get single record by key, e.g. /api/view/cars/1 |
Successful response { "success": true, "version": "18.0.0", "cars": { "ID": 1, "Trademark": 1, ... } } Failed response See failed response for list |
|
POST /api/add/{table} Insert a new record, e.g. /api/add/cars |
<Field>=<FieldValue> (field to be inserted) |
Successful response { "success": true, "version": "18.0.0", "cars": { "ID": 16, "Trademark": 1, ... } } Failed response See failed response for list |
POST /api/register Register a new user in the user table, e.g. /api/register |
<Field>=<FieldValue> (field to be inserted) |
Successful response { "success": true, "version": "18.0.0", "employees": { "EmployeeID": 10, "Username": "newuser", ... } } Failed response See failed response for list |
POST /api/edit/{table}/{key} Update an existing record by key, eg. /api/edit/cars/1 |
<Field>=<FieldValue> (field to be updated) |
Successful response { "success": true, "version": "18.0.0", "cars": { "Trademark": 2, ... } } Failed response See failed response for list |
GET /api/delete/{table}/{key} Delete an existing record by key, e.g. /api/delete/cars/1 POST /api/delete/{table} Delete multiple records by keys, e.g. /api/delete/cars |
key_m[]=<FieldValue> Note If composite key, <FieldValue> is comma separated values.
|
Successful response { "success": true, "version": "18.0.0", "cars": { "ID": 1, "Trademark": 1, ... } } Failed response See failed response for list |
POST /api/login Authenticate an user, see Authenticate user with JWT, e.g. /api/login GET /api/login Accepted if the advanced setting Allow login by URL is enabled, e.g. /api/login?username=admin&password=master |
username=<UserName> (user name value) password=<Password> (password value) securitycode=<SecurityCode> (Google Authenticator security code, required if Two factor authentication is enabled.) |
Successful response Note When testing in Swagger UI, after loggiing in, you need to click the Authorize button and enter "Bearer <JsonWebToken>" to authorize yourself before testing other actions.
|
|
GET /api/file/{table}/{field}/{key} Get file info by primary, e.g. /api/file/employees/Photo/1 GET /api/file/{table}/{path} Get file data by encrypted file path, e.g. /api/file/employees/xxx |
Note If composite key, when testing in Swagger UI, enter {key} as comma separated values. |
Successful response
|
POST /api/upload Upload files, e.g. /api/upload |
Successful response JSON response of file token and file info: { "success": true, "version": "18.0.0", "token": "<FileToken>", "files": [ ...file info...] } Failed response { "success": false, "version": "18.0.0", "files": [] } |
|
GET /api/permissions/{userLevelID} Get permissions, e.g. /api/permissions/1 POST /api/permissions/{userLevelID} Update permissions, e.g. /api/permissions/1
|
{ "<Table1>": <Permission1>, "<Table2>": <Permission2>, ... } |
Get permissions JSON response: { "userlevel": 1, "permissions": { "cars": 8 , ... } } Update permission Successful response { "success": true, "userlevel": 1, "permissions": { "cars": 264 } } Failed response { "success": false, "userlevel": 1 } |
Authenticate User with JWT (JSON Web Token)
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.
Notes
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. Upload Files To upload files, you can use upload action (see above). You can upload file(s) by HTML 5, e.g. <input type="file" id="id" name="name" onchange="uploadFiles(this);"> If you want to let the user select multiple files, simply use the multiple attribute on the input element and add [] to the name: <input type="file" id="id" name="name[]" multiple onchange="uploadFiles(this);"> Notes Beside the built-in API actions, you can add your own API actions by Api_Action server event (see Server Events and Client Scripts). Example 1 - Hello world
$(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();
$.post("/api/login", 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",
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">
<input type="text" name="username" value="admin">
<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>
<script>
// Upload files
function uploadFiles(el) {
var files = el.files, // Get FileList object
name = el.name,
url = "/api/upload",
xhr = new XMLHttpRequest(),
fd = new FormData();
xhr.responseType = "json";
xhr.open("POST", url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200 && xhr.response) { // Files uploaded
if (xhr.response.filetoken) // Check file token
console.log(xhr.response.filetoken);
}
};
for (var i = 0; i < files.length - 1; i++)
fd.append(name, files[i]); // Append File object to form data
xhr.send(fd);
}
</script>
function Api_Action($app)
{
$app->get('/hello/{name}', function ($request, $response, $args) {
$name = $args["name"] ?? null; // Get the input value
if ($name !== null) {
$response = $response->write("Hello, " . $name); // Write to response
}
return $response; // Return Psr\Http\Message\ResponseInterface object
});
}
The user can now access the URL /api/hello/John to get the response text
"Hello John".
Notes
Example 2 - Get product by name
function Api_Action($app) { $app->get('/getProductByName/{name}', function ($request, $response, $args) { $name = $args["name"] ?? null; // Get the input value if ($name !== null) { $response = $response->withJson(ExecuteRow("SELECT * FROM products WHERE ProductName = '" . AdjustSql($name) . "'")); // Select the record by name and return as JSON } return $response; // Return Psr\Http\Message\ResponseInterface object }); }
The product data can now be accessed using the following JavaScript:
$.get("/api/getProductByName/Chai", function(res) { console.log(res); // Show the result in console });
Note See Returning JSON for more details about returning JSON data from callback function.