-
Notifications
You must be signed in to change notification settings - Fork 7
Core Documentation
Controllers are classes that serve two functions.
- To provide endpoints.
- To route to other controllers.
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
.
- The
[verb]
is an HTTP verb or method. For exampleget
andpost
are valid verbs. These are written in lower case. - 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. - 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.
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
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
.
- 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. - 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.
public function fooBarController() {
returns new FooBar();
}
This example will allow access to the FooBar Controllers endpoints and sub controllers via the url /foo-bar
.
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.
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.
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.
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.
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"
]
}
}
}
}
}
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.
// 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
);
}