Building API Endpoints

Building API Endpoints

Learn how to build a simple API using CMS Pages.

View the routing article if you prefer to define API routes using PHP instead.

When working with client-side frameworks such as Vue.js or React, it will be necessary to consume server-side APIs. These can be defined using your theme where each page represents an API endpoint.

The page represents a transformation layer that sits between your CMS Components and the JSON responses that are returned to your application. Most objects, such as models and collections, support JSON serialization and can be returned directly as a response.

# Sending a Response

In the simplest form, an API resource can be composed by returning a Twig variable using the response() Twig function. This function overrides the page contents and returns a custom response to the browser.

url = "/api/foobar"
___TWIG0___

The above call will return a response with a application/json content type.

{ "foo": "bar" }

In most cases you will be converting component variables to a response.

___TWIG0___

# Collections

The collect()Twig function builds a collection for a response. The push method is used to push items on to the collection and it can be used to customize each result.

___TWIG0___

___TWIG1___
    ___TWIG2___
___TWIG3___

___TWIG4___

# Conditions

All Twig conditions can be used in the markup to affect the response and the last response call is the one that will be sent to the browser.

# Checking the HTTP Method

Use the this.request.method Twig property to check the request method.

___TWIG0___
    <!-- Do GET Logic -->
___TWIG1___
    <!-- Method Unsupported -->
___TWIG2___

# Aborting the Request

The abort() Twig function can be used to abort the request with a 404 response.

___TWIG0___
    ___TWIG1___
___TWIG2___
    ___TWIG3___
___TWIG4___

# Working with Pages and Layouts

Since the API is defined in the Markup section of the page or layout, all components and life-cycle events are available.

# Using Layouts as Middleware

Middleware allows you to apply common logic to multiple endpoints, such as checking authentication or throttling requests. A CMS layout with priority mode can be used to apply logic to multiple pages and the layout logic executes before the page logic.

Remember to include the {% page %} Twig tag so the page logic is included. For example, a layout named api.htm can have any conditional logic.

description = "API Authentication"
is_priority = 1
___TWIG0___
    ___TWIG1___
___TWIG2___
    ___TWIG3___
___TWIG4___

Every page that uses the layout will have the conditions of the layout applied.

layout = "api"
___TWIG0___

Always use priority mode in the layout to ensure the layout contents run first.

# Calling AJAX Handlers

In some cases you may wish to call an AJAX handler of a component or inside the page. This is possible using the ajaxHandler() Twig function.

url = "/api/signin

[account]
___TWIG0___

___TWIG1___
    ___TWIG2___
___TWIG3___
    ___TWIG4___
___TWIG5___

You may also call a handler and pass it directly as a response. The response includes variables set on the page and array values returned by the function.

___TWIG0___

It will also handle redirects automatically. See the Twig function article for more details.

# Working with Resources

When working with models and collections, it is recommended to return data wrapped in the data attribute. Wrapping the response provides a consistent interface.

# Models & Collections

Returning a model resource.

url = "/api/blog/post/:slug"

[section post]
handle = "Blog\Post"
identifier = "slug"
___TWIG0___
    ___TWIG1___
___TWIG2___
    ___TWIG3___
___TWIG4___

Returning a collection resource.

url = "/api/blog/posts"

[collection posts]
handle = "Blog\Post"
___TWIG0___

# Pagination

When responding with a paginated collection, it is recommended to use the pager() Twig function to construct the response using the links and meta attributes.

___TWIG0___

___TWIG1___

___TWIG2___

The above will output the following JSON format.

{
    "data": {},
    "links": {
        "first": "https://yoursite.tld/api/blog/posts?page=1",
        "last": "https://yoursite.tld/api/blog/posts?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "path": "https://yoursite.tld/api/blog/posts",
        "per_page": 3,
        "total": 2,
        "current_page": 1,
        "last_page": 1,
        "from": 1,
        "to": 2
    }
}

# Usage Examples

These are some practical examples of how snippets can be used.

# Returning Users with Avatar Thumbnails

The following example sets the users variable to all the users found in the User plugin (opens new window). The avatar relationship is eager loaded after the fact and then the avatar_thumb attribute is set as a thumb URL for each user if an avatar is found.

## pages/api/users.htm
url = "/api/users"
function onStart()
{
    $this['users'] = \RainLab\User\Models\User::all();
}
___TWIG0___
___TWIG1___

___TWIG2___
___TWIG3___
    ___TWIG4___
___TWIG5___

___TWIG6___
___TWIG7___

# See Also