Skip to content

Core Documentation

Daniel Mason edited this page Sep 8, 2015 · 8 revisions

Core Documentation

  1. Controllers
  2. Endpoints
  3. Formatting
  4. Self Documentation
  5. Exceptions

Controllers

Controllers are classes that serve two functions.

  1. To provide endpoints.
  2. To route to other controllers.

Endpoint methods

Endpoints are the bread an butter of an api, they provide the functionality. In Aye Aye, endpoints are specially named methods inside controllers. The naming convention works like this [verb][Name]Endpoint.

  1. The [verb] is an HTTP verb or method. For example get and post are valid verbs. These are written in lower case.
  2. The [Name] is the name of your endpoint as it will appear in the url. The is must start with a capital letter and if the endpoint is multiple words that you'd like to separate, then each new word should be capitalised.
  3. The word Endpoint is added to the end to tell Aye Aye that this is an endpoint, and not some other type of method, you do not want visible and accessible to the outside world.

Endpoint methods should return the data you want the user to receive.

Example
public function getHelloWorldEndpoint(...) {
   ...
}

In the example above, we have created an endpoint called HelloWorld. It uses the get verb, so you can access it by sending a get request to /hello-world. Notice the casing of the name caused the url to break into a more readable structure. Endpoints are discussed further below

Controller methods

Aye Aye uses a single controller as a starting point, all other controllers must be accessible via that controller. We do this by adding methods that using the following naming convention [name]Controller.

  1. The [name] is the name of your controller as it will appear in the url. The is must start with a capital letter and if the endpoint is multiple words that you'd like to separate, then each new word should be capitalised.
  2. The word Controller is added to the end to tell Aye Aye that this method provides access to another controller. It will be listed separately from the current controllers endpoints.

Controller methods must return an instance of another controller.

Example
public function fooBarController() {
    returns new FooBar();
}

This example will allow access to the FooBar Controllers endpoints and sub controllers via the url /foo-bar.

Endpoints

When writing an API, endpoints are where you should be spending most of your time. As discussed [above] (#endpoint-methods), endpoints in Aye Aye are specially named methods inside Controller classes, however Aye Aye also recognises the parameters you declare the endpoint to take, and will do it's best to populate them.

When you want to give an API information, how do you do that? This can depend a lot on the type of request. For example a POST request from a form will be sent as a query string in the body of the request. If you make an ajax call however, you could send a json encoded body. GET requests conversely, are not supposed to contain bodies at all, so information might arrive as a query string after the url, or it might be part of the url itself. And sometimes, depending on the standard you're abiding by, it might be more appropriate to send data in the HTTP Header. So already we have data in 3 or 4 different locations, in multiple formats. Luckily, with Aye Aye, you don't have to worry about that.

Aye Aye takes the following philosophy: "If I can see a parameter called "user_id" does it matter if it's in the url, body or header?". Probably not. Does it matter if it's user_id, user-id or userId. Again, probably not. Finally, in the case of the body, does it matter if it's a query string, and xml document or a json encoded object... You get the idea.

So Aye Aye abstracts all of that for you. When you create an endpoint, simply tell Aye Aye what data you expect want to receive by giving the method a list of parameters.

Example
public function getHelloWorldEndpoint($name = 'World') {
    return "Hello $name";
}

In the example above we've created an endpoint called /hello-world which we can give a parameter name. If we don't provide name in the request, it will be default to 'World'. The parameter can be passed in a query string at the end of the url, a header, or the body. It doesn't matter.

As with method names above, Aye Aye will also accept a wide range of variations in parameter names to make it as easy as possible for you to get the information you need. Note: if a default parameter isn't provided, null is used rather than allowing the method to fail entirely.

Formatting

Aye Aye likes to return information to end users as an object, the format of which is decided on primarily by the consumer. To facilitate this, there is always a response object that contains a data property. In our previous example, we might expect to see something like this:

{
    "data" : "Hello World"
}

or, if the consumer prefers XML:

<?xml version="1.0" encoding="UTF-8" ?>
<response>
    <data>Hellow World</data>
</response>

Formatting is not handled by the controller itself, but is managed through the Formatters and FormatFactory provided by the Formatters Library, however it is important to have a basic understanding of how they opperate on the data you return.

Simply, they will try to turn non-scalar values into arrays before returning the data. They do this in part to help provide more control over what gets returned. The best way to work with this is by implementing either the \AyeAye\Formatter\Serializable interface, or PHP's own \JsonSerializable, which Aye Aye will handle automatically. Alternatively, you can return a pre-constructed array. Failing that Aye Aye will still try to create an array from publicly accessible parameters, but results may vary.

Self Documentation

Let's be honest, as developers, one of the worst parts of our job is writing documentation, but explaining how an API works is also incredibly important. Luckily Aye Aye will even help you out with this, using a Documenter class.

Assuming you document your code using PhpDoc / PSR-5 anyway, the default Documenter can read what you've written about an endpoint method and display it to the consumer. When a consumer hit's any controller (for example, your initial controller that they will see if they visit the root of your API), Aye Aye will tell them the Controllers and Endpoints available from there. Endpoints will additionally be documented with a Summary, Description, the names, types and explainations of each variable, and the return type.

Example
class InitialController extends Controller
{
    /**
     * Returns a reference to this class
     */
     public function recursiveController()
     {
         return $this;
     }
     
     /**
      * Introduce yourself to the Api.
      * This method will greet new users.
      * @param string $iAm Tell the Api who you are
      * @return string
      */
     public function getIAmEndpoint($iAm = 'Captain')
     {
         return "Hello $iAm";
     }
}

Aye Aye will automatically respond with the following documentation (assuming Json is requested or the default)

{
  "data": {
    "controllers": [
      "recursive"
    ],
    "endpoints": {
      "get": {
        "iam": {
          "summary": "Introduce yourself to the Api.",
          "description": "This method will greet new users.",
          "parameters": {
            "iAm": {
              "type": "string",
              "description": "Tell the Api who you are"
            }
          },
          "returnType": [
            "string"
          ]
        }
      }
    }
  }
}

Exceptions

Aye Aye includes a special Exception designed to provide more useful information to your end users. Simply, they can be given two messages, one for you which should be logged, and one to send the user. Furthermore, the exceptions code will be carried forward as an HTTP status. Here's the constructor:

public function __construct($publicMessage = '', $code = 500, $systemMessage = '', \Exception $previous = null)

The important thing to note here is that the first message is now public. This message can be used to inform the user of what went wrong. The code defaults to 500, which will be translated to an Internal Server Error.

Example
// use \AyeAye\Api\Exception;

public function getExceptionEndpoint() {
    throw new Exception(
        'Hello Exception',    // Data returned to user
        500,                  // The HTTP status code
        'User hit Exception', // Message for your logs
        null                  // Any exception can be added here
    );
}