Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Good PHP Rest Api library [closed]

I am developing a cross-platform system and I need to make a rest API to tie them together. I have long experience in PHP and I want to use this for this service.

I could develop a API 100% manually, but I am hoping there is some great libraries out there that could ease my development.

Does anyone have any experience with libraries like this? Anything you could recommend?

like image 816
OptimusCrime Avatar asked Mar 10 '13 21:03

OptimusCrime


People also ask

Is PHP good for API?

PHP is a powerful language, with a wide range of offerings that make utilizing it for anything from basic websites to complex APIs a very strong proposition.

Which PHP Framework is specifically created for building REST web services?

PHP REST API: Lumen Lumen is a micro-API framework made out of Laravel. Specially designed for building REST APIs, this framework cuts off all Laravel features that restrict stateless APIs. Instead, it focuses on what is useful to REST APIs. This is why Lumen is such a lightweight framework.

What is PHP REST API?

REST (Representational State Transfer) is an API that defines a set of functions that programmers can use to send requests and receive responses using the HTTP protocol methods such as GET and POST.


1 Answers

I got the badge Popular question for this question, so I feel it's about time I elaborate how I did my REST-soluton.

I did look at both Laravel, Sympfony2 and Codeigniter for this REST Api. They all had some elements I liked and some I disliked. My main concern was how to do the authentication because I had a rather complex algorithm where my users can log in with the apps' access_token or access_tokens served by Google or Facebook. I also perfer being in complete control of my framework and the frameworks mentioned above had some elements I felt unnecessary and hard to work around. Because of this I decided to make my own REST-solution. It is not as hard as one might expect, and it can be done in several ways. The way I did it requires some knowledge about OOP-programming.

Okey, so starting out a made a base-class called REST. This class takes care of all the stuff that is in common for every call. Like authentication, parsing the requested path to a method, checking access_token etc.

One of the central things in this class is the requested path and how this is translated into a method. I did this inspired by Laravel. I have a array with key => value where the key is the url it should match and the value is the actual method to call. I also included the way Lavavel parses variables in the URL like so:

'/user/(:id)' => 'user_id',

This would match any /user/[number]. It also checks what type of request this is, so if this is a simple get-method it would try to call get_user_id. Anything parsed with (:id) would be used as an argument when calling that method (so it is actually calling get_user_id($id)).

After authentication the actual method-call gets evaluated. I did not want all the methods (like get_user_id) in the REST-class itself, so I broke these up in different controllers that extends the REST-class. This is done by looking at the url being requested. If it is /user/(:id) the script will check if there is a controller named userController.php. If it exists, check if the method we are going to call exists. If it does, check if the number of arguments matches what we have. If everything is good, execute the method, if not return an error message. Structure and error-messages are very important when making a API like this.

In the different controllers I call the constructor for the REST-class to get the authentication, parsing of the url etc resolved. The tricky part here is that I did not want to do:

$controller = new MyController();
$controller->printResponse();

In the bottom of every controller. So I made a little hack and a script called run.php that does this dynamically for every controller-class. Before I include the run.php I save the path for the controller by simply doing $path = explode('/',__FILE__);. This is used in the run-script. The run-script looks like this:

// Splitting the file-name, removing the extension
$name = explode('.',$path[count($path)-1]);

// Uppercasing the first letter to be nice and OOP-ish
$classToCall = ucfirst($name[0]);

// Creating a new instance
$controller = new $classToCall();

// Logging
$controller->doLog();

// Printing the final response
$controller->printResponse();

I found this to be a perfect solution for how I wanted to build my API. I can easily add new methods by supplying it in the array that parses urls to methods, and I can add new methods in the nicely broken apart controllers for maximum cleanness.

Some people might think this is too much work, but it actually took me only a few hours to get it up and running. I'd also call this highly dynamic as I can just add new controllers and the system will recognize them if they are valid url-patterns.


A few friendly advices.

If you decide to go with something resembling this solution, these can be some good tips. In each controller, do something like this:

public function __construct() {
    // Loading the class-name, setting it in the REST-class, so we can check if it holds the method being called
    $this->className = get_class($this);

    // Calling RESTs constructor
    parent::__construct();
}

We will need to store what class we are currently working from. This would be UserController or something like that.

In the REST-class I can then use this variable to check if the actual method getting called does exist in this controller. I've done that this way:

// Checking if the method exists
if (method_exists($this->className,$method_name)) {
    // Check to see if we have the required number of arguments represented
    $ReflectionClass = new ReflectionClass($this->className);

    if ($ReflectionClass->getMethod($method_name)->getNumberOfParameters() == count($this->methodUrl['args'])) {
        $this->response['response'] = call_user_func_array(array($this, $method_name), $this->methodUrl['args']);

I hope that can get you all going.

Happy codin'

like image 79
OptimusCrime Avatar answered Oct 06 '22 02:10

OptimusCrime