3 namespace Friendica\Module\Api;
5 use Friendica\App\Arguments;
6 use Friendica\Core\L10n;
7 use Friendica\Core\Logger;
8 use Friendica\Core\System;
10 use Friendica\Object\Api\Mastodon\Error;
11 use Friendica\Util\Arrays;
12 use Friendica\Util\HTTPInputData;
13 use Friendica\Util\XML;
16 * This class is used to format and return API responses
27 * @param Arguments $args
29 public function __construct(L10n $l10n, Arguments $args)
36 * Creates the XML from a JSON style array
38 * @param array $data JSON style array
39 * @param string $root_element Name of the root element
41 * @return string The XML data
43 public static function createXML(array $data, string $root_element): string
45 $childname = key($data);
46 $data2 = array_pop($data);
48 $namespaces = ['' => 'http://api.twitter.com',
49 'statusnet' => 'http://status.net/schema/api/1/',
50 'friendica' => 'http://friendi.ca/schema/api/1/',
51 'georss' => 'http://www.georss.org/georss'];
53 /// @todo Auto detection of needed namespaces
54 if (in_array($root_element, ['ok', 'hash', 'config', 'version', 'ids', 'notes', 'photos'])) {
58 if (is_array($data2)) {
60 Arrays::walkRecursive($data2, ['Friendica\Module\Api\ApiResponse', 'reformatXML']);
66 foreach ($data2 as $item) {
67 $data4[$i++ . ':' . $childname] = $item;
74 $data3 = [$root_element => $data2];
76 return XML::fromArray($data3, $xml, false, $namespaces);
80 * Formats the data according to the data type
82 * @param string $root_element Name of the root element
83 * @param string $type Return type (atom, rss, xml, json)
84 * @param array $data JSON style array
86 * @return array|string (string|array) XML data or JSON data
88 public static function formatData(string $root_element, string $type, array $data)
94 $ret = static::createXML($data, $root_element);
105 * Callback function to transform the array in an array that can be transformed in a XML file
107 * @param mixed $item Array item value
108 * @param string $key Array key
112 public static function reformatXML(&$item, string &$key): bool
114 if (is_bool($item)) {
115 $item = ($item ? 'true' : 'false');
118 if (substr($key, 0, 10) == 'statusnet_') {
119 $key = 'statusnet:' . substr($key, 10);
120 } elseif (substr($key, 0, 10) == 'friendica_') {
121 $key = 'friendica:' . substr($key, 10);
127 * Exit with error code
130 * @param string $description
131 * @param string $message
132 * @param string|null $format
136 public static function error(int $code, string $description, string $message, string $format = null)
139 'error' => $message ?: $description,
140 'code' => $code . ' ' . $description,
141 'request' => DI::args()->getQueryString()
144 header(($_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.1') . ' ' . $code . ' ' . $description);
146 self::exit('status', ['status' => $error], $format);
150 * Outputs formatted data according to the data type and then exits the execution.
152 * @param string $root_element
153 * @param array $data An array with a single element containing the returned result
154 * @param string|null $format Output format (xml, json, rss, atom)
158 public static function exit(string $root_element, array $data, string $format = null)
160 $format = $format ?? 'json';
162 $return = static::formatData($root_element, $format, $data);
166 header('Content-Type: text/xml');
169 header('Content-Type: application/json');
170 if (!empty($return)) {
171 $json = json_encode(end($return));
172 if (!empty($_GET['callback'])) {
173 $json = $_GET['callback'] . '(' . $json . ')';
179 header('Content-Type: application/rss+xml');
180 $return = '<?xml version="1.0" encoding="UTF-8"?>' . "\n" . $return;
183 header('Content-Type: application/atom+xml');
184 $return = '<?xml version="1.0" encoding="UTF-8"?>' . "\n" . $return;
193 * Quit execution with the message that the endpoint isn't implemented
195 * @param string $method
200 public static function unsupported(string $method = 'all')
202 $path = DI::args()->getQueryString();
203 Logger::info('Unimplemented API call',
207 'agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
208 'request' => HTTPInputData::process()
210 $error = DI::l10n()->t('API endpoint %s %s is not implemented', strtoupper($method), $path);
211 $error_description = DI::l10n()->t('The API endpoint is currently not implemented but might be in the future.');
212 $errorobj = new Error($error, $error_description);
213 System::jsonError(501, $errorobj->toArray());