From 070f4d60bd2c1f267d7b65150282fec22ef1c328 Mon Sep 17 00:00:00 2001 From: laf Date: Wed, 16 Jul 2014 23:10:18 +0100 Subject: [PATCH] Added documentation and a function to tidy up json output --- html/api_v1.php | 14 +- html/includes/print-menubar.php | 9 +- html/pages/api-docs.inc.php | 408 ++++++++++++++++++++++++++++++++ includes/api_functions.inc.php | 151 +++++++++++- 4 files changed, 569 insertions(+), 13 deletions(-) create mode 100644 html/pages/api-docs.inc.php diff --git a/html/api_v1.php b/html/api_v1.php index 99972ef81..642465ab3 100644 --- a/html/api_v1.php +++ b/html/api_v1.php @@ -32,19 +32,19 @@ $app->group('/api', function() use ($app) { $app->group('/get', function() use ($app) { $app->group('/graph', function() use ($app) { $app->group('/port', function() use ($app) { - $app->get('/id/:id(/:type)(/:width)(/:height)(/:from)(/:to)(/)', 'authToken', 'get_graph_by_id');//api/v1/get/graph/port/id/$port_id/$key - $app->get('/device/:id/:port(/:type)(/:width)(/:height)(/:from)(/:to)(/)', 'authToken', 'get_graph_by_port');//api/v1/get/graph/port/device/$device_id/$ifName/$key - $app->get('/hostname/:hostname/:port(/:type)(/:width)(/:height)(/:from)(/:to)(/)', 'authToken', 'get_graph_by_port_hostname');//api/v1/get/graph/port/device/$hostname/$ifName/$key + $app->get('/id/:id(/:type)(/:width)(/:height)(/:from)(/:to)(/)', 'authToken', 'get_graph_by_id');//api/v1/get/graph/port/id/$port_id + $app->get('/device/:id/:port(/:type)(/:width)(/:height)(/:from)(/:to)(/)', 'authToken', 'get_graph_by_port');//api/v1/get/graph/port/device/$device_id/$ifName + $app->get('/hostname/:hostname/:port(/:type)(/:width)(/:height)(/:from)(/:to)(/)', 'authToken', 'get_graph_by_port_hostname');//api/v1/get/graph/port/device/$hostname/$ifName }); $app->group('/general', function() use ($app) { - $app->get('/device/:id/:type(/:width)(/:height)(/:from)(/:to)(/)', 'authToken', 'get_graph_generic_by_deviceid');//api/v1/get/graph/general/device/$device_id/$graph_type/$key - $app->get('/hostname/:hostname/:type(/:width)(/:height)(/:from)(/:to)(/)', 'authToken', 'get_graph_generic_by_hostname');//api/v1/get/graph/general/hostname/$hostname/$graph_type/$key + $app->get('/device/:id/:type(/:width)(/:height)(/:from)(/:to)(/)', 'authToken', 'get_graph_generic_by_deviceid');//api/v1/get/graph/general/device/$device_id/$graph_type + $app->get('/hostname/:hostname/:type(/:width)(/:height)(/:from)(/:to)(/)', 'authToken', 'get_graph_generic_by_hostname');//api/v1/get/graph/general/hostname/$hostname/$graph_type }); }); $app->group('/stats', function() use ($app) { $app->group('/port', function() use ($app) { - $app->get('/id/:id(/)', 'authToken', 'get_port_stats_by_id');//api/v1/get/stats/port/id/$port_id/$key - $app->get('/device/:id/:port(/)', 'authToken', 'get_port_stats_by_port');//api/v1/get/stats/port/device/$device_id/$ifName/$key + $app->get('/id/:id(/)', 'authToken', 'get_port_stats_by_id');//api/v1/get/stats/port/id/$port_id + $app->get('/device/:id/:port(/)', 'authToken', 'get_port_stats_by_port');//api/v1/get/stats/port/device/$device_id/$ifName }); }); }); diff --git a/html/includes/print-menubar.php b/html/includes/print-menubar.php index 42766775c..0fce47e8d 100644 --- a/html/includes/print-menubar.php +++ b/html/includes/print-menubar.php @@ -521,7 +521,14 @@ if ($_SESSION['userlevel'] >= '10') echo('
  • Edit User
  • Authlog
  • -
  • API Settings
  • '); + + '); } ?> + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. Please see LICENSE.txt at the top level of + * the source code distribution for details. + */ + +if ($_SESSION['userlevel'] == '10') +{ + +?> + +
    +
    + +

    Introduction

    +

    The API is designed to enable you to interact with your installtion from other systems, monitoring systems, apps or websites using any programming language that can make a web request and both send and receive json data. This documentation will provide you the methods, accepted parameters and responses from the API.

    + +

    Token authentication

    +

    Authentication against the API is done by tokens which are assigned to a user account. You can view and create tokens using the API access link within the System > API menu.


    +

    To send the token to the API you need to do this by using the X-Auth-Token within the header. As example if your API token was 91c60e737e342c205be5bba8e2954d27 then you would send the following X-Auth-Token: 91c60e737e342c205be5bba8e2954d27. As an example using curl within PHP you would do something like this:

    + curl_setopt($ch, CURLOPT_HTTPHEADER, array('X-Auth-Token: 91c60e737e342c205be5bba8e2954d27'));
    + +

    API Responses

    +

    The following responses are standard across each request type except for where an image would be returned directly, the response will be output in json format:

    + status
    +
      +
    • ok = The request was successful
    • +
    • error = The request failed
    • +
    + message
    +

    This will contain the reason for the success or failure of the request.


    +

    As an example to get you started quickly, here we use the API to request to list all devices:

    +
    curl -H "Content-Type: application/json" -H "X-Auth-Token: 91c60e737e342c205be5bba8e2954d27" "https://librenms.example.com/api/v1/list/devices"
    +{ 
    +  "status": "ok", 
    +  "devices": [  
    +  {
    +   "device_id": "4",
    +   "hostname": "example.co.uk",
    +   "sysName": "example.co.uk",
    +   "community": "public",
    +   "authlevel": null,
    +   "authname": null,
    +   "authpass": null,
    +   "authalgo": null,
    +   "cryptopass": null,
    +   "cryptoalgo": null,
    +   "snmpver": "v1",
    +   "port": "161",
    +   "transport": "udp",
    +   "timeout": null,
    +   "retries": null,
    +   "bgpLocalAs": null,
    +   "sysObjectID": null,
    +   "sysDescr": "Linux example.co.uk 2.6.18-238.19.1.el5 #1 SMP Fri Jul 15 07:31:24 EDT 2011 x86_64",
    +   "sysContact": "root@localhost",
    +   "version": "2.6.18-238.19.1.el5",
    +   "hardware": "Generic x86 64-bit",
    +   "features": null,
    +   "location": "Unknown",
    +   "os": "linux",
    +   "status": "1",
    +   "ignore": "0",
    +   "disabled": "0",
    +   "uptime": "90741309",
    +   "agent_uptime": "0",
    +   "last_polled": "2014-07-16 17:40:04",
    +   "last_polled_timetaken": "2.16",
    +   "last_discovered_timetaken": "3.15",
    +   "last_discovered": "2014-07-16 12:33:44",
    +   "purpose": "",
    +   "type": "server",
    +   "serial": null,
    +   "icon": null
    +  },
    +  {
    +   "device_id": "24",
    +   "hostname": "localhost",
    +   "sysName": "testing",
    +   "community": "public",
    +   "authlevel": "noAuthNoPriv",
    +   "authname": "",
    +   "authpass": "",
    +   "authalgo": "MD5",
    +   "cryptopass": "",
    +   "cryptoalgo": "AES",
    +   "snmpver": "v1",
    +   "port": "161",
    +   "transport": "udp",
    +   "timeout": null,
    +   "retries": null,
    +   "bgpLocalAs": null,
    +   "sysObjectID": null,
    +   "sysDescr": "Linux testing 2.6.32-431.el6.x86_64 #1 SMP Fri Nov 22 03:15:09 UTC 2013 x86_64",
    +   "sysContact": "root@localhost",
    +   "version": "2.6.32-431.el6.x86_64",
    +   "hardware": "Generic x86 64-bit",
    +   "features": null,
    +   "location": "Unknown",
    +   "os": "linux",
    +   "status": "1",
    +   "ignore": "0",
    +   "disabled": "0",
    +   "uptime": "19355163",
    +   "agent_uptime": "0",
    +   "last_polled": "2014-07-16 17:40:04",
    +   "last_polled_timetaken": "1.74",
    +   "last_discovered_timetaken": "1.28",
    +   "last_discovered": "2014-07-16 12:33:25",
    +   "purpose": null,
    +   "type": "server",
    +   "serial": null,
    +   "icon": null
    +  }
    + ]
    +}
    +    
    + +

    API request types

    +

    The following request types are currently used:

    +
      +
    • GET - This is used for the retrieval of information or images.
    • +
    • POST - This is used for adding new items such as devices.
    • +
    • PUT - This is used to update existing items.
    • +
    • DELETE - This is used to remove items.
    • +
    + +

    Available requests

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    VersionPath (required)Path (additional)Variables / JSON DataReturns
    Port Graphs
    /api/v1/get/graph/port/id/$id/$type/$width/$height/$from/$to +
      +
    • $id = the ID of the port
    • +
    • $type = the type of graph for the port (port_bits,port_upkts)
    • +
    • $width = the width of the graph to be returned
    • +
    • $height = the height of the graph to be returned
    • +
    • $from = the from date/time of the graph (unix timestamp)
    • +
    • $to = the to date/time of the graph (unix timestamp)
    • +
    +
    + PNG Image +
    curl -H "Content-Type: application/json" -H "X-Auth-Token: 91c60e737e342c205be5bba8e2954d27" \
    "https://librenms.example.com/api/v1/get/graph/port/id/1" > /tmp/graph.png
    curl -H "Content-Type: application/json" -H "X-Auth-Token: 91c60e737e342c205be5bba8e2954d27" \
    "https://librenms.example.com/api/v1/get/graph/port/id/1/port_bits/1024/768/1405457456/1405543856" > /tmp/graph.png
    /api/v1/get/graph/port/device/$device_id/$ifName/$type/$width/$height/$from/$to +
      +
    • $device_id = the ID of the device
    • +
    • $ifName = the ifName of an interface
    • +
    • $type = the type of graph for the port (port_bits,port_upkts)
    • +
    • $width = the width of the graph to be returned
    • +
    • $height = the height of the graph to be returned
    • +
    • $from = the from date/time of the graph (unix timestamp)
    • +
    • $to = the to date/time of the graph (unix timestamp)
    • +
    +
    + PNG Image +
    curl -H "Content-Type: application/json" -H "X-Auth-Token: 91c60e737e342c205be5bba8e2954d27" \
    "https://librenms.example.com/api/v1/get/graph/port/device/1/eth0" > /tmp/graph.png
    curl -H "Content-Type: application/json" -H "X-Auth-Token: 91c60e737e342c205be5bba8e2954d27" \
    "https://librenms.example.com/api/v1/get/graph/port/device/1/eth0/port_bits/1024/768/1405457456/1405543856" > /tmp/graph.png
    /api/v1/get/graph/port/hostname/$hostname/$ifName/$type/$width/$height/$from/$to +
      +
    • $hostname = the hostname of the device
    • +
    • $ifName = the ifName of an interface
    • +
    • $type = the type of graph for the port (port_bits,port_upkts)
    • +
    • $width = the width of the graph to be returned
    • +
    • $height = the height of the graph to be returned
    • +
    • $from = the from date/time of the graph (unix timestamp)
    • +
    • $to = the to date/time of the graph (unix timestamp)
    • +
    +
    + PNG Image +
    curl -H "Content-Type: application/json" -H "X-Auth-Token: 91c60e737e342c205be5bba8e2954d27" \
    "https://librenms.example.com/api/v1/get/graph/port/hostname/localhost/eth0" > /tmp/graph.png
    curl -H "Content-Type: application/json" -H "X-Auth-Token: 91c60e737e342c205be5bba8e2954d27" \
    "https://librenms.example.com/api/v1/get/graph/port/hostname/localhost/eth0/port_bits/1024/768/1405457456/1405543856" > /tmp/graph.png
    General Graphs
    /api/v1/get/graph/general/device/$device_id/$type/$width/$height/$from/$to +
      +
    • $device_id = the ID of the device
    • +
    • $type = the type of graph for the device (device_processor,device_storage)
    • +
    • $width = the width of the graph to be returned
    • +
    • $height = the height of the graph to be returned
    • +
    • $from = the from date/time of the graph (unix timestamp)
    • +
    • $to = the to date/time of the graph (unix timestamp)
    • +
    +
    + PNG Image +
    curl -H "Content-Type: application/json" -H "X-Auth-Token: 91c60e737e342c205be5bba8e2954d27" \
    "https://librenms.example.com/api/v1/get/graph/general/device/1/device_processor" > /tmp/graph.png
    curl -H "Content-Type: application/json" -H "X-Auth-Token: 91c60e737e342c205be5bba8e2954d27" \
    "https://librenms.example.com/api/v1/get/graph/general/device/1/device_processor/1024/768/1405457456/1405543856" > /tmp/graph.png
    /api/v1/get/graph/general/hostname/$hostname/$type/$width/$height/$from/$to +
      +
    • $hostname = the hostname of the device
    • +
    • $type = the type of graph for the device (device_processor,device_storage)
    • +
    • $width = the width of the graph to be returned
    • +
    • $height = the height of the graph to be returned
    • +
    • $from = the from date/time of the graph (unix timestamp)
    • +
    • $to = the to date/time of the graph (unix timestamp)
    • +
    +
    + PNG Image +
    curl -H "Content-Type: application/json" -H "X-Auth-Token: 91c60e737e342c205be5bba8e2954d27" \
    "https://librenms.example.com/api/v1/get/graph/general/hostname/localhost/device_processor" > /tmp/graph.png
    curl -H "Content-Type: application/json" -H "X-Auth-Token: 91c60e737e342c205be5bba8e2954d27" \
    "https://librenms.example.com/api/v1/get/graph/general/hostname/localhost/device_processor/1024/768/1405457456/1405543856" > /tmp/graph.png
    Port Stats
    /api/v1/get/stats/port/id/$port_id +
      +
    • $port_id = the ID of the port
    • +
    +
    + JSON +
    curl -H "Content-Type: application/json" -H "X-Auth-Token: 91c60e737e342c205be5bba8e2954d27" \
    "https://librenms.example.com/api/v1/get/stats/port/id/1"
    /api/v1/get/stats/port/device/$device_id/$ifName +
      +
    • $device_id = the ID of the device
    • +
    • $ifName = the ifName of the port
    • +
    +
    + JSON +
    curl -H "Content-Type: application/json" -H "X-Auth-Token: 91c60e737e342c205be5bba8e2954d27" \
    "https://librenms.example.com/api/v1/get/stats/port/device/1/eth0"
    List
    /api/v1/list/devices/$order/$type +
      +
    • $order = the name of the column to order by
    • +
    • $type = this is the device status (all, ignored, up, down, disabled)
    • +
    +
    + JSON +
    curl -H "Content-Type: application/json" -H "X-Auth-Token: 91c60e737e342c205be5bba8e2954d27" \
    "https://librenms.example.com/api/v1/list/devices"
    curl -H "Content-Type: application/json" -H "X-Auth-Token: 91c60e737e342c205be5bba8e2954d27" \
    "https://librenms.example.com/api/v1/list/devices/hostname/all"
    Add
    /api/v1/add/device +
      +
    • hostname = the hostname to be added
    • +
    • version = the version of snmp to use
    • +
    • community = the community to use
    • +
    • port = the port to use
    • +
    • transport = the transport to use
    • +
    • authlevel = the auth level to use for v3
    • +
    • authname = the auth name to use for v3
    • +
    • authpass = the auth pass to use for v3
    • +
    • authalog = the auth algorythm to use for v3
    • +
    • cryptopass = the crypto pass to use for v3
    • +
    • cryptoalgo = the crytpo algo to use for v3
    • +
    +
    + JSON +
    curl -X POST -d '{"hostname":"localhost.localdomain","version":"v1","community":"public"}' \
    -H "Content-Type: application/json" -H "X-Auth-Token: 91c60e737e342c205be5bba8e2954d27" \
    "https://librenms.example.com/api/v1/add/device"
    +
    +
    + +
    + + diff --git a/includes/api_functions.inc.php b/includes/api_functions.inc.php index 2b0549f32..787f9e317 100644 --- a/includes/api_functions.inc.php +++ b/includes/api_functions.inc.php @@ -12,6 +12,147 @@ * the source code distribution for details. */ +if (!defined('JSON_UNESCAPED_SLASHES')) + define('JSON_UNESCAPED_SLASHES', 64); +if (!defined('JSON_PRETTY_PRINT')) + define('JSON_PRETTY_PRINT', 128); +if (!defined('JSON_UNESCAPED_UNICODE')) + define('JSON_UNESCAPED_UNICODE', 256); + +function _json_encode($data, $options = 448) +{ + if (version_compare(PHP_VERSION, '5.4', '>=')) + { + return json_encode($data, $options); + } + + return _json_format(json_encode($data), $options); +} + +function _pretty_print_json($json) +{ + return _json_format($json, JSON_PRETTY_PRINT); +} + +function _json_format($json, $options = 448) +{ + $prettyPrint = (bool) ($options & JSON_PRETTY_PRINT); + $unescapeUnicode = (bool) ($options & JSON_UNESCAPED_UNICODE); + $unescapeSlashes = (bool) ($options & JSON_UNESCAPED_SLASHES); + + if (!$prettyPrint && !$unescapeUnicode && !$unescapeSlashes) + { + return $json; + } + + $result = ''; + $pos = 0; + $strLen = strlen($json); + $indentStr = ' '; + $newLine = "\n"; + $outOfQuotes = true; + $buffer = ''; + $noescape = true; + + for ($i = 0; $i < $strLen; $i++) + { + // Grab the next character in the string + $char = substr($json, $i, 1); + + // Are we inside a quoted string? + if ('"' === $char && $noescape) + { + $outOfQuotes = !$outOfQuotes; + } + + if (!$outOfQuotes) + { + $buffer .= $char; + $noescape = '\\' === $char ? !$noescape : true; + continue; + } + elseif ('' !== $buffer) + { + if ($unescapeSlashes) + { + $buffer = str_replace('\\/', '/', $buffer); + } + + if ($unescapeUnicode && function_exists('mb_convert_encoding')) + { + // http://stackoverflow.com/questions/2934563/how-to-decode-unicode-escape-sequences-like-u00ed-to-proper-utf-8-encoded-cha + $buffer = preg_replace_callback('/\\\\u([0-9a-f]{4})/i', + function ($match) + { + return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE'); + }, $buffer); + } + + $result .= $buffer . $char; + $buffer = ''; + continue; + } + elseif(false !== strpos(" \t\r\n", $char)) + { + continue; + } + + if (':' === $char) + { + // Add a space after the : character + $char .= ' '; + } + elseif (('}' === $char || ']' === $char)) + { + $pos--; + $prevChar = substr($json, $i - 1, 1); + + if ('{' !== $prevChar && '[' !== $prevChar) + { + // If this character is the end of an element, + // output a new line and indent the next line + $result .= $newLine; + for ($j = 0; $j < $pos; $j++) + { + $result .= $indentStr; + } + } + else + { + // Collapse empty {} and [] + $result = rtrim($result) . "\n\n" . $indentStr; + } + } + + $result .= $char; + + // If the last character was the beginning of an element, + // output a new line and indent the next line + if (',' === $char || '{' === $char || '[' === $char) + { + $result .= $newLine; + + if ('{' === $char || '[' === $char) + { + $pos++; + } + + for ($j = 0; $j < $pos; $j++) + { + $result .= $indentStr; + } + } + } + // If buffer not empty after formating we have an unclosed quote + if (strlen($buffer) > 0) + { + //json is incorrectly formatted + $result = false; + } + + return $result; +} + function authToken(\Slim\Route $route) { $app = \Slim\Slim::getInstance(); @@ -37,7 +178,7 @@ function authToken(\Slim\Route $route) { $app->response->setStatus(400); $output = array("status" => "error", "message" => "API Token is invalid"); - echo json_encode($output); + echo _json_encode($output); $app->stop(); } } @@ -125,7 +266,7 @@ function get_port_stats_by_id() $stats = dbFetchRow("SELECT * FROM `ports` WHERE `port_id`=?", array($port_id)); $output = array("status" => "ok", "port" => $stats); $app->response->headers->set('Content-Type', 'application/json'); - echo json_encode($output); + echo _json_encode($output); } function get_port_stats_by_port() @@ -139,7 +280,7 @@ function get_port_stats_by_port() $stats = dbFetchRow("SELECT * FROM `ports` WHERE `device_id`=? AND `ifName`=?", array($device_id,$if_name)); $output = array("status" => "ok", "port" => $stats); $app->response->headers->set('Content-Type', 'application/json'); - echo json_encode($output); + echo _json_encode($output); } function get_graph_generic_by_deviceid() @@ -231,7 +372,7 @@ function list_devices() } $output = array("status" => "ok", "devices" => $devices); $app->response->headers->set('Content-Type', 'application/json'); - echo json_encode($output); + echo _json_encode($output); } function add_device() @@ -296,5 +437,5 @@ function add_device() $output = array("status" => $status, "message" => $message); $app->response->headers->set('Content-Type', 'application/json'); - echo json_encode($output); + echo _json_encode($output); }