It is pretty standard in REST API design that 400 codes are valid responses (e.g. not found). Not being able to handle these responses properly is a pretty significant design flaw in the API Connector.
As a workaround I wrote a simple Azure Function (node.js) to wrap API calls and always return 200 with the actual code in the response body. Seems to solve the issue. Bubble could easily implement something like this this.
Here is the Azure function code in case anyone else is blocked by this as well. Just call the Azure function http endpoint with the path /bubble/your_api_path.
index.js:
const BASE_URL = '<YOUR API BASE URL>';
module.exports = async (context) => {
//create a response conforming to JSend format - https://github.com/omniti-labs/jsend
const respond = (code, message, data) => {
context.res = {
headers: { 'Content-Type': 'application/json' },
status: 200,
body: {
code: code,
status: (code < 400) ? 'success' : (code < 500) ? 'fail' : 'error',
message: message,
data: data
}
};
}
const options = {
method: context.req.method,
uri: BASE_URL + context.req.params.segments,
headers: {
'content-type': 'application/json',
'x-authapi-client': context.req.headers['x-authapi-client'] <--THIS IS SPECIFIC TO MY API
},
qs: context.req.query,
body: context.req.body,
json: true,
resolveWithFullResponse: true,
simple: false
}
const request = require('request-promise-native');
try {
const response = await request(options);
//NOTE: change the respond params based on your API response format
respond(response.statusCode, response.body.message, response.body.data);
} catch (e) {
let msg = ('message' in e) ? e.message : ('cause' in e) ? e.cause : 'unknown';
respond(500, msg, null);
}
}
function.json:
{
"bindings": [{
"authLevel" : "anonymous",
"type" : "httpTrigger",
"direction" : "in",
"name" : "req",
"route" : "bubble/{*segments}"
}, {
"type" : "http",
"direction" : "out",
"name" : "res"
}]
}
host.json:
{
"version": "2.0",
"extensions": {
"http": {
"routePrefix": ""
}
}
}