6. UI for our math service¶
Our goal in this chapter is to create a simple webpage which can execute our “add_numbers” service and return the results on screen.
When the input isn’t legal, we should display the error on screen.
Create an API controller¶
The directory for our service should already exists, since we’ve created it in the “Hello world” chapter.
Like the “HelloWorld” controller, this one should contain two files as well.
1<?php
2
3namespace ValueA\Samples\Api;
4
5use ValueA\Base\ApiQueueControllerBase;
6
7class MathController extends ApiQueueControllerBase
8{
9}
The classname is the only thing that’s different here compared to the one in “Hello world”, the controller lives in the same place (namespace) as the other service.
The routing (xml) beneath the controller is different, since our request accepts parameters.
1<route>
2 <add>
3 <bind>valuea.samples.add_numbers</bind>
4 <type>POST</type>
5 <guess_types>1</guess_types>
6 </add>
7</route>
Although not very complicated, we notice two things here. At line 4 we tell the controller we should only respond to “POST” type requests, next at line 5 we tell the controller it should guess the variable types depending on its input.
Note
json schema expects parameters to be type safe, which means that a string 1 (‘1’) isn’t the same as the number 1. Using guess_types you can ask our controller to guess the proper type. Normally we only use this approach when the types aren’t guaranteed to be correctly passed by the client.
Tip
The routing xml also supports parameters as part of the url, to map situations like /api/samples/math/add/1/2, which requires a definition like this for our example:
<parameters>
<parameter>
<a>id</name>
<default/>
</parameter>
<parameter>
<b>id</name>
<default/>
</parameter>
</parameters>
Which maps a to the first parameter and b to the second, containing no default when a value is omitted.
Create the controller for the UI¶
The controller for our Math example is similar to the one created in “Hello world” and contains the path to our template (which is created next) and the name to use in the controller.
1<?php
2namespace ValueA\Samples;
3
4class MathController extends \ValueA\Base\IndexController
5{
6 public function indexAction()
7 {
8 $this->view->title = 'Math';
9 $this->view->pick('ValueA/Samples/math');
10 }
11}
Add the template (view)¶
Our api is automatically published on /api/samples/math/add with the steps taken so far,
now we should be able to create a page using a bootstrap grid layout containing all required input and
output fields.
The html part in the code below contains a bootstrap grid layout with input fields and a single button.
Note
The id tags should be unique with the page and is used to reference the items, within jQuery you can
easily address an object by id using the hash #. e.g. $("#value_a") is the element with id value_a.
1<script type="text/javascript">
2 $( document ).ready(function() {
3 $("#add_numbers").click(function(){
4 var params = {'a': $("#value_a").val(), 'b': $("#value_b").val()};
5 ajaxCall(url="/api/samples/math/add", sendData=params, callback=function(data,status) {
6 if (data.error != undefined) {
7 BootstrapDialog.alert('Please input valid parameters');
8 } else {
9 $("#result").val(data.result);
10 }
11 });
12 });
13 });
14</script>
15
16<!-- Bootstrap grid layout -->
17<div class="row">
18 <div class=" col-md-4 col-xs-12">
19 <div class="input-group">
20 <label for="value_a"><strong>Input A</strong></label>
21 <input type="text" id="value_a" class="form-control">
22 </div>
23 </div>
24 <div class=" col-md-4 col-xs-12">
25 <div class="input-group">
26 <label for="value_b"><strong>Input B</strong></label>
27 <input type="text" id="value_b" class="form-control">
28 </div>
29 </div>
30 <div class=" col-md-4 col-xs-12">
31 <div class="input-group">
32 <label for="result"><strong>Result</strong></label>
33 <input type="text" id="result" class="form-control">
34 </div>
35 </div>
36</div>
37<div class="row">
38 <div class=" col-md-12 col-xs-12">
39 <hr/>
40 <button type="button" class="btn btn-default" id="add_numbers">
41 Go!
42 </button>
43 <br/><br/>
44 </div>
45</div>
The script part on top of the code block is where it all comes together, it binds the onclick event of the add_numbers button with the rest/service action.
Let’s step into the code block for some further explaining.
It all starts with $( document ).ready(function() { telling this code should be execute when the page is fully loaded, more details
on how this works can be found at jQuery.
Next we define an onlick event which then executes the call to the service,
we’ve created our own wrapper for this operation ajaxCall() which kind of explains itself (endpoint, parameters and a callback for the response).
When the call returns, it will execute the callback code which checks data.error != undefined to identify errors.
Finally we either throw an error using BootstrapDialog.alert (part of bootstrap3-dialog)
or fill the result input with the response.
Note
Go to https://yourip/ui/samples/math/ and try to input some different values including floating point values (e.g. 10.1). Note that only integer values are accepted and because guess_types is set we don’t have to convert the types in the call to math/add.
Tip
Most browsers support a development mode where you can see the actual request send to the server, in this case our requests looks like
{"a":"1","b":"2"}
If types were proper on input, it would have been {"a":1,"b":2}
Change the existing ACL¶
With our root user we automatically skip the ACL, thus allowing us access to our newly designed service.
In the previous example we have created an ACL which allows access to the hello world app, now we’re going to change the ACL to allow access to all pages within the samples scope:
1<acl>
2 <page-valuea-samples>
3 <name>ValueA Samples</name>
4 <patterns>
5 <pattern>ui/samples/*</pattern>
6 <pattern>api/samples/*</pattern>
7 </patterns>
8 </page-valuea-samples>
9</acl>
Lines 5 and 6 define the patterns to match for this ACL, in which we allow access to all underneath samples.
Tip
The pattern tags can easily be extended, if you only want to allow the additional services to be available, just
add the ui/samples/math/* and api/samples/math/* patterns.