# API Construction

Quickly build out an API using the cloud.api module by assiging functions to HTTP methods.

You trigger these processes and return the resulting data to the client in various formats.

These function/HTTP method combos are generally referred to as Routing Methods.


Starting an API

Your API will reside in the api.lua file found in the project directory you want to work with.

Inside this file, you will want to start with the following structure, which follows the same structure of many Lua modules:

--apps/myapp/api.lua

--=========================================================--
--== Get an instance of the Cloud API Object
--=========================================================--
local api = cloud.api()

-- Routing Methods will be added here.

--=========================================================--
--== Return the API Object to the core
--=========================================================--
return api

Routing Methods

Routing methods come in two formats, both based on the incoming HTTP method, specifically GET and POST.

POST Methods

When using the Corona SDK client module, your requests are sent as POST by default. You can build endpoints for your API calls like so:

--apps/myapp/api.lua
local api = cloud.api()

--=========================================================--
--== Create an "echo" routing method
--=========================================================--
function api.post.echo( input )
  return input
end

return api

Endpoint Schema

The code above generates an endpoint at https://your.coronium.instance/myapp/echo

By default this function will only run when the project key is passed in the X-Project-Key header, and requested with an HTTP POST method. This process happens automatically if you're using the Corona SDK module.


Returning Data

In the above function we don't return anything to the client, which is required to complete the client lifecycle.

The Circle of Life

You must always return data from the Routing Methods.

Note: Without returning data to the client, you risk creating a "dangling" connection, which only uses resourses, for no purpose.

In the case of our "echo" function, it's very simple:

--apps/myapp/api.lua
local api = cloud.api()

function api.post.echo( input )
  return input --echo data back to client
end

return api

GET Methods

If you're using the Corona SDK module exclusivly, you won't need to set up any GET methods. If you plan on having user-facing pages or functionality, then you will use the GET methods.

Heads Up!

A 'GET' method is inheritly "public" unless set otherwise.

A GET Routing Method is nearly identical to a POST:

--apps/myapp/api.lua
local api = cloud.api()

function api.get.echo(input)
  return input --echo data back to client
end

return api

Can you spot the difference?


Incoming Data

A number of parameters are passed to a Routing Method when it's called. One of the more used, is the input data.

Input data is always a Lua table and generated slightly different depending on the HTTP method request type.

For GET requests, the input data is gathered from the query string as name=val pairs and converted to a table.

A POST requests data is built from the "body" posted. Coronium 2 expects JSON data in the POST body, and will convert it into a Lua table upon entry to the Routing Method.


Method Parameters

A Routing Method has a number of passed in parameters that you can access for various use cases. The full signature of a Routing Method is as follows:

api.METHOD.ACTION(input, isAjax, headers, method)

Parameters

Name Description Type
input A table with any incoming data from the client. table
isAjax A flag to check whether request is Ajax. boolean
headers A table of the HTTP request headers. table
method The HTTP request method. string

Example

...

function api.post.stats(input, isAjax)
  if isAjax then
    return cloud.error('no ajax!')
  end

  return input
end

...

Returning Data II

Much like the incoming parameters, the return has some additonal options as well.

The full signature for the data return is as follows:

return output[, contentType[, headers]]

Parameters

Name Description Type
output A string, number, boolean, or table to send to the client. mixed
contentType A content type constant, default: cloud.JSON constant
headers A table of the HTTP request headers. table

Example

...

function api.get.story()
  --just some plain text
  local t = "Once upon a time"
  return t, cloud.TEXT
end

...

The output above will be render as plain text, with no decorations or JSON encoding.

cloud.JSON

The cloud.JSON content type is the default output, so is not required to be specified. With this content type, any data return-ed will attempt to be converted to JSON before being sent down the wire.

For end clients like the Corona SDK module, this data is converted to a Lua table for client consumption.

The result key

All JSON data is returned in an enclosing object with a result key. This result may hold a string, number, boolean, or object.

When processed by the Corona SDK module, this data is converted to a Lua table. You can access this data with the regular Corona event.response from the network event returned.

String Example

In the Cloud...

--apps/users/api.lua
...

function api.post.getUserName()
  return "Mr. Jones" --a string
end

...

This will send {"result":"Mr. Jones"} down the wire.

In Corona SDK...

local function listener(event)
  if event.phase == "ended" then
    print(event.response.result)
    -- "Mr. Jones"
  end
end

local req = cloud:request('/users/getUserName', {}, listener)

This would be the same results expected when passed a single number, or boolean value.

Table Example

When passing a table object, the data will be JSON encoded before being sent down the wire. As above, the data will reside in the event.response key in Corona SDK.

In the Cloud...

--apps/store/api.lua
...

function api.post.product()
  local product =
  {
    sku = 001,
    desc = "widget",
    inStock = false
  }

  return product
end

...

In Corona SDK...

local function listener(event)
  if event.phase == "ended" then
    print(event.response.inStock)
    -- false
  end
end

local req = cloud:request('/store/product', {}, listener)

cloud.HTML

You can generate and display dynamic and static web pages using data from your Coronium 2 instance. The content is not wrapped by any result object.

Content Generation

See the cloud.template module and Generating Pages for more information.

cloud.TEXT

If you'd like just plain text with no decorations or wrappers, then use this content type.

...

function api.get.stats()
  local cpu = '100%'
  return cpu, cloud.TEXT
end

...