A service controller consists of actual actions responding to requests.
To create a service controller, the developer must extend wlRestController class and define some actions that will process the requests and provide data to be served back to the requester. The actions are implemented by class methods (declared as protected or public) following the convention: actionNameRequestMethod. Request method must be Get, Post, Put or Delete.
Let's create a basic service controller that will return 'Hello World' string in response to GET requests.
class sampleHelloRestControllerV1 extends wlRestController { protected function helloGet() { //define the action hello that will respond only to GET requests return "Hello World"; } }
Please note the convention when defining actions: the action name (hello) is followed by the accepted request method (Get), resulting the method name helloGet. This convention must be embraced when defining methods for service actions.
A service controller must registered in within a service with an unique name. In order to accomplish that define the wlRestController::getDefaultName method in the controller class
class sampleHelloRestControllerV1 extends wlRestController { public function getDefaultName() { //give a default name to the controller return 'hello'; } protected function helloGet() { //define the action hello that will respond only to GET requests return "Hello World"; } }
or/and when calling the controller constructor have a string parameter as name.
$helloController = sampleHelloRestControllerV1('hi');
Use wlRestController::registerController method to register a service controller in within a service:
$service = new wlRestService(); //create a service $service->registerController(new sampleHelloRestControllerV1()); //register the service controller with the default name $service->run(); //run the service
or to register it using a custom name:
$service = new wlRestService(); //create a service $service->registerController(new sampleHelloRestControllerV1('hi')); //register the service controller with 'the default name'hi' as name $service->run(); //run the service
The custom name given in the constructor have higher priority when registering a service. In example above the controller will be registered under the 'hi' name and URL for calling its hello action should look like: http ://rest-service-endpoint-url/hi/v1/hello.
You may have noticed the v1 part in the request URL. It represents the controller service version; so, when requesting by GET http ://rest-service-endpoint-url/hi/v1/hello, will call the helloGet method of the controller idetified under hi name and having version v1.
By default, all service controllers have v1 string set as version. To specify other version just define wlRestController::getVersion method:
class sampleHelloRestControllerV1 extends wlRestController { //... public function getVersion() { //give a different version instead of 'v1' return 'ver1'; } //... }
Now, the URL should be: http ://rest-service-endpoint-url/hi/ver1/hello.
To offer different action results for different controller versions, a good technique is to extend the class implementing the first version and just redefine the actions to be changed.
Of course, new methods for new actions can be added also.
class sampleHelloRestControllerV2 extends sampleHelloRestControllerV1 { //... public function getVersion() { //specify the new version return 'v2'; } protected function helloGet() { //redefine the action hello that will respond only to GET requests return "Hello World from version 2"; } protected function greetingsGet() { //ad a new action that will respond only to GET requests return "Greetings World"; } //... }
Both versions can be registered:
$service = new wlRestService(); //create a service $service->registerController(new sampleHelloRestControllerV1()); //register the service controller version 1 with the default name (hello) $service->registerController(new sampleHelloRestControllerV2()); //register the service controller version 2 with the default name (hello) $service->run(); //run the service
Let's extend out Hello World service controller to make it available for the other request types:
class sampleHelloRestControllerV1 extends wlRestController { public function getDefaultName() { //give a default name to the controller return 'hello'; } protected function helloGet() { //define the action hello that will respond only to GET requests return "Hello World"; } protected function helloPut() { //define the action hello that will respond only to PUT requests file_put_contents('hello.txt', 'Hello World from PUT'); } protected function helloPost() { //define the action hello that will respond only to POST requests file_put_contents('hello.txt', 'Hello World from POST'); } protected function helloDelete() { //define the action hello that will respond only to DELETE requests unlink('hello.txt'); } }
The code above is a very simple example that manipulates the file system as response to different request types.
Let's build now a more realistic example that will also use data sent by the requester. The example will simulate a CRUD functionality still using the file system.
class sampleDbSimulatorRestController extends wlRestController { //set a default name for the service controller public function getDefaultName() { return 'db'; } //retrieves a person by the id parameter, or an array of all persons if no parameters are sent with the GET request protected function personGet() { $params = $this->getService()->getRequest()->getQueryParams(); //get the query (GET) parameters (as given in the URL) if(count($params)) { //if parameters are found $id = $params[0]; //we assume that the first parameters is the id return $this->readPerson($id); //call helper that reads a person }else { //if no parameters are found, will return an array with all persons $ret = array(); $files = scandir(__DIR__); foreach($files as $id) { $person = $this->readPerson($id); if($person !== null) { $ret[$id] = $person; } } return $ret; } } //updates or creates a person using the parameters sent with PUT request protected function personPut() { $params = $this->getService()->getRequest()->getActionParams(); //get the action parameters (as sent with PUT) $this->writePerson($params); //call helper that writes the person } //deletes a person file identified by id parameter sent along with the DELETE request protected function personDelete() { $params = $this->getService()->getRequest()->getQueryParams(); //get the query parameters (as given in the URL) $id = $params[0]; //we assume that the first parameters is the id $this->deletePerson($id); //call helper that deletes the person } //helper method that parses a file identified by $id and returns an array representing the person private function readPerson($id) { //... } //helper method that deletes the file identified by $id private function deletePerson($id) { //... } //helper method that updates the file identified by $personArray['id'] //if $personArray['id'] is not set, it means that we have a new person an a new file should be created private function writePerson($personArray) { //... } }
In this sample, the helpers were skipped in order to keep focus on the main functionality. The whole sample is included in the commercial package as a full featured demonstration.
Building a RESTful web service for your PHP web application has never been so easy!
WiseLoop PHP REST Services is a powerful API framework that allows easy development of any kind of API through RESTful web services.