Skip to content

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)