Managing Endpoints
Endpoints are custom REST services that are accessible from custom widgets or external systems. Through endpoints, custom widgets can access external services via HTTP.
In this case, endpoints act as a kind of HTTP proxy, so custom widgets can make Ajax requests to external services without having cross-domain issues. Also, endpoints can expose Application Builder's data sources, such as oneWEX collections, to external systems.
Endpoints are defined based on data source definitions. Therefore, all you need to do to enable endpoints is to create data sources.
The enableEndpoint property in the data source definition controls whether to enable endpoints for the data source. If you create a new data source, the enableEndpoint property is true by default.
https://your.server.com/builder/api/endpoint/<datasource-id>
Below is an example of a data source definition.
{
"key": "my_ds",
"name": "Book Search API",
"enableEndpoint": true,
"options": {
"protocol": "https:",
"method": "GET",
"host": "external.server.com",
"path": "/books/v1/search?start=${start}&max=${count}&q=${query}"
},
"map": {
...
}
}
Abstract Proxy mode
https://your.server.com/builder/api/endpoint/my_ds?start=0&count=10&query=cat
In this mode, a destination URL is constructed in the same way as the search API. That is, options.path in the data source definition is used to construct the URL and parameters are converted to actual ones based on the pattern in options.path.
In the abstract proxy mode, the result is normalized based on the field mapping in the data source definition, just like the search API. The result should look like this:
{
"items": [ ... ],
"itemsRaw": [ ... ],
"totalCount": 489
}
Direct Proxy Mode
https://your.server.com/builder/api/endpoint/my_ds/books/v1/search?max=10&q=cat
In this mode, a destination URL is constructed by appending the additional path to options.host in the data source definition. In this case, options.path is not used. The given parameters (?max=10&q=cat) are passed to the destination as they are.
The resulting data is never processed. The original data is returned with the original content-type. Any resources including images, XML etc. can be accessed in direct proxy mode.
Making Requests
The client can make a request with any of the following methods:
- GET request with query parameters.
- POST request with x-www-form-urlencoded parameters.
- POST request with JSON parameters.
Data source supports the same three types of REST services. All types of services can be called with any method. For example, a REST service that accepts POST requests with JSON parameters can be accessed using the GET request with query parameters.
CORS Support
When you wish to access an endpoint from an external web application, you may want to make Ajax requests to the endpoint. In general, the browser does not allow this since Application Builder and your external web application are in different domains. To overcome the browser's same origin policy, the Application Builder's endpoint feature supports Cross Origin Resource Sharing (CORS). It is enabled by default, and no special setup is required. The code below is an example of making Ajax requests to an endpoint using jQuery.
var url = "https://your.server.com/builder/api/endpoint/voc?start=0&count=10&query=juice";
$.ajax({
url: url,
type: 'GET',
})
.done(function(data) {
data.items.forEach(function(item) {
console.log(item.title);
});
});
=>
apple juice
orange juice
...
Server-side scripts
You may want to customize payload at the server-side rather than client-side. For example,
converting an XML response from backend to JSON, merging two response data into one, filter out
unnecessary data to slim down the payload size, etc. In such cases, you can write custom JavaScript
code that is executed by Node.js at the server-side. To do so, you can implement the
applyEndpointFilter
method in a data source adapter.
applyEndpointFilter
method- Method
-
applyEndpointFilter: function(response: any, req: Request): any
- Parameters
-
Table 1. Summary Name Type Description response
any A response from the corresponding data source. It contains body
andheaders
.req
Request A request object for the endpoint call. - Returns
- Customized response.
- Example (Manipulating JSON object)
-
You can customize body and headers and return the customized response. When the content type is application/json, for example, body would be a JSON string. You may want to use JSON.parse() to handle it as JavaScript object as shown in the example code below. You do not need to care about content-length as it will automatically be filled before sending the response to the client.
applyEndpointFilter: function(response, req) { var body = JSON.parse(response.body); // ... customize the body object as you like ... response.body = JSON.stringify(body); response.headers['x-custom-header'] = 'something'; return response; }
- Example (Convert XML to JSON)
-
The example below is a case where data source response is an XML and you want to convert it to JSON. If you would like, you can utilize XML to JSON converter called
xml-js
. (https://www.npmjs.com/package/xml-js)The variable convert, which holds a reference toxml-js
, is accessible from theapplyEndpointFilter
method. Therefore, you can callconvert.xml2js()
to convert XML to a JavaScript object, as shown in the example below.applyEndpointFilter: function(response, req) { try { var obj = convert.xml2js(response.body, {compact:true, spaces:4}); // ... customize the json object as you like ... response.body = JSON.stringify(obj); response.headers['content-type'] = 'application/json; charset=UTF-8'; } catch (e) { console.log(e); } return response; }
- Example (Asynchronous Operation)
-
If you want to perform asynchronous operation in the method, you can return a promise that resolves when the new response data is ready.
applyEndpointFilter: function(response, req) { var url = 'http://...'; return new Promise((resolve, reject) => { fetch(url).then(function(response) { return response.text(); }).then(function(text) { // your code goes here response.body = ...; resolve(response); }); }); }