API server
Result object
All responses processed by the addin must be embedded in a Result object serialized as a JSON string.
Here is a lightweight python implementation (full implementation on gitlab):
class Result:
def __init__(self, subkind=None, ok=None, success_msg=None, error_msg=None, data=None, misc=None):
self.kind = 'Result'
self.subkind = subkind
self.ok = ok
self.success_msg = success_msg
self.error_msg = error_msg
self.data = data
self.misc = misc
self.msg = None
@property
def json(self):
if self.ok is None:
self.ok = 1 if (self.data or self.success_msg) else 0
self.msg = self.success_msg if self.ok == 1 else self.error_msg
return json.dumps(self.__dict__)
Custom API server
Python
Here is a quick example how to implement 2 functions as API in Python, HTTP server included:
from bottle import route, run
@www.route('/test/styles/<STYLE>', method='get')
def test_style(STYLE):
result = Result()
if STYLE == 'SCALAR':
result.data = "vA1"
result.success_msg = "1 scalar"
elif STYLE == 'DICT':
result.data = {"A1": "vA1", "B1": "vB1", "A2": "vA2", "B2": "vB2", "A3": "vA3", "B3": "vB3"}
result.success_msg = "1 object with 6 keys/values"
elif STYLE == 'MATRIX_BY_COLS':
result.misc['cols'] = ["A", "B", "C"]
result.data = [[11, 12, 13], [21, 22, 23], [31, 32, 33]]
result.success_msg = "3 cols x 3 rows, int"
elif STYLE == 'MATRIX_BY_ROWS':
result.misc['cols'] = ["A", "B"]
result.data = [[11, 21], [12, 22], [13, 23]]
result.success_msg = "2 cols x 3 rows, int"
elif STYLE == 'DICT_LIST':
result.data = [{"A": "vA1", "B": "vB1"}, {"A": "vA2", "B": "vB2"}, {"A": "vA3", "B": "vB3"}]
result.success_msg = '2 cols x 3 rows, text'
elif STYLE == 'COL':
result.data = ['row1', 'row2', 'row3']
result.success_msg = '1 col with 3 rows'
elif STYLE == 'ROW':
result.data = [['col1', 'col2', 'col3']]
result.success_msg = '1 row with 3 cols'
else:
result.error_msg = "Wrong params"
return result.json
@www.route('/test/my_function', method='post')
def test_my_function():
result = Result()
a = request.params.get('a')
b = request.params.get('b')
if a and b:
result.data = int(a) * 10 + int(b)
result.success_msg = 'f(a,b) = 10a + b'
else:
result.error_msg = 'Params are a:int, b:int'
return result.json
print("Starting API server on localhost:8080...")
run(host='localhost', port=8080)
with calls from Excel:
=xlbc_get('http://localhost:8080/test/styles/MATRIX_BY_COLS)
=xlbc_get('http://localhost:8080/test/my_function?a=30&b=100)
R
Another example, using rplumber.io
#* @get /normaldistribution
normaldistribution <- function(n=10) {
rnorm(n)
}
library(plumber)
api <- plumb("api.R")
api$run(port=8080)
call from Excel:
=xlbc_get('http://localhost:8080)/normaldisbution?n=5)