Hello CrossUI Community,
I've been leveraging CrossUI for a week - it's incredibly versatile. I'm currently trying to send JSON data through the API Caller's body instead of the URL query. Is there a way to achieve this directly in CrossUI, or must I resort to crafting a custom JS function for AJAX requests?
I'd like to pass in body this JSON :
{
"intitule_el" : { "Value" : "asdvsvsbcd" } ,
"truc_el" : { "Value" : "asdvsvsbcd" }
}
instead of having it in querystring in url :
.../api/elements?_rand_=ertl7wxb&intitule_el=asdvscscbcd&truc_el=asdvsvsbcd
Looking forward to your guidance. Thanks!
[ADDED in 2.52]Sending JSON Data in API Caller Body with CrossUI
Re: Sending JSON Data in API Caller Body with CrossUI
If you want to set query data, use queryData ( not in the "Web API Caller" dialog), which you can find it in the right "Component Config" area.
And set queryMethod to "POST".
requestType should be "FORM" or "JSON".
Will enhance "Web API Caller" dialog later.
And set queryMethod to "POST".
requestType should be "FORM" or "JSON".
Will enhance "Web API Caller" dialog later.
Re: Sending JSON Data in API Caller Body with CrossUI
Thank you for providing this helpful code snippet. At the moment, I've developed my method using PUT and POST to interact with the API, and it's working exceptionally well for my current needs. I'll definitely keep your technique in mind for future forms that I'll be working on. It seems like a valuable approach to explore further. Thanks again for sharing!
Best regards,
Romain
Best regards,
Romain
// -----------------------------------------------------------------------------------------------
// JSON_query: Allows SQL-like operations on a JSON object of type SELECT
// -----------------------------------------------------------------------------------------------
function JSON_query(data, action, key_id) {
// If the action starts with SELECT, we launch the SQL emulation function to
// manage JSON data like SQL tables with SELECT, WHERE, IN, AND, OR, LIKE, NULL, %, GROUP, ORDER....
if (action.substr(0, 7) == "SELECT ") {
var a = SQL_query(action, data);
return a;
}
// If the action starts with RENAME {id_el: 'id', intitule_el: 'caption'}, we can rename fields of the JSON object
if (action.substr(0, 7) == "RENAME ") {
return fields_json_rename(action, data);
}
// ------------------------------------------------------------------------------------------------------------------------------------------------
// Handling PUT and POST actions
// ------------------------------------------------------------------------------------------------------------------------------------------------
// For example: received from the global CrossUI function named: JSON_query()
// -> a1) val (object): {page.XXXXXXXXXXX_form.getFormValues(true,null,true,true,true)} // Only modified fields in the form using PUT method
// -> a2) val (object): {page.XXXXXXXXXXX_form.getFormValues(false,null,true,false,false)}// All fields in the form using POST method
// -> b) action (string): "PUT XXXXXXXXXXXX" // Indicating here that we will use PUT method with the API on the endpoint "XXXXXXX"
// -> c) key_id (string): {page.id_el.getValue()} // Primary key of the record to update (here: example with id_el for the elements table represented by XXXXX)
// ------------------------------------------------------------------------------------------------------------------------------------------------
if (action.startsWith("PUT ") || action.startsWith("POST ")) {
// If the data object is empty, then nothing has been modified in the form, so we do nothing
if (Object.keys(data).length == 0) {
return null;
}
// Headers to be sent
const headers = {
"accept": "application/json_v1",
"authorization": "Token " + Token,
"Accept-Language": "fr",
"content-type": "application/json"
};
// For example: elements that we'll call XXXXXXXXX here
const endPoint = action.substring(action.indexOf(" ")).trim();
// Method used by the API request: PUT or POST
var method = action.substring(0, action.indexOf(" ")).trim();
// URL to call for the API, composed of the endPoint (XXXXXXXXX), followed by / and the ID of the record to update if provided
const url_endPoint = url_API_REST + endPoint + (key_id != null ? "/" + key_id : "");
// Depending on the PUT method: transformation of modified fields received
// from the form by a format accepted by the API (with fieldname: {Value: "aaaaa"}....)
if (method == "PUT") {
var JSON_form = JSON.stringify(JSON_API_format_form(data));
}
// For POST method: the original provided JSON format { name: value} by CrossUI is fine
else if (method == "POST") {
var JSON_form = JSON.stringify(data);
}
// Performs the AJAX request and returns the promise directly
return ajax_request_api(method, url_endPoint, JSON_form, headers)
.then(response => {
// Sending a global message (Global broadcast to the CrossUI interface):
// - {arg1}: the action to close the form: "close_form_XXXXXXXXXXXXX"
// - {arg2}: the JSON returned by the API (before, after with the fields of the record before and after update)
// - {arg3}: the object of modified fields in the form (argument "a)" received at the beginning of the JSON_query function in the variable "data")
// - and on the CrossUI interface, 2 components listen to the message sent by broadcast -
// => The "XXXXXXX_form" page which will close the form window
// => The "XXXXXXX_window" page which will update the Treegrid row with the object of argument 3 (above)
var object_response = JSON.parse(response);
xui.broadcast("action", "close_form_" + endPoint, object_response, data, method);
})
.catch(error => {
// Displaying an alert with the error
xui.broadcast("action", "error_form_" + endPoint, error);
});
}
// Returns a rejected promise if the action is not recognized to keep the function asynchronous
return Promise.reject(new Error('Action not recognized.'));
}
Re: Sending JSON Data in API Caller Body with CrossUI
in CrossUI, I go in Actions Editor
and for PUT API, I call Function : functions.JSON_query with :
val : {page.element_form.getFormValues(true, null , true, true ,true)}
action : PUT elements
key_id : {page.id_el.getValue()}
my script call API and then broadcast a global message for the next operations in crossUI to update Grid and more
and for PUT API, I call Function : functions.JSON_query with :
val : {page.element_form.getFormValues(true, null , true, true ,true)}
action : PUT elements
key_id : {page.id_el.getValue()}
my script call API and then broadcast a global message for the next operations in crossUI to update Grid and more
Re: Sending JSON Data in API Caller Body with CrossUI
Currently, I have been utilizing the API Caller for the GET method to retrieve a JSON with dozens of rows from a database, and it has been functioning admirably. I had configured my headers in the Web API caller interface as follows:
However, I now find myself needing to replace the hardcoded value for Authorization with a global variable (global.ARR.TOKEN), which will be an actual user token obtained from a cookie. The global variable is functioning correctly, and I am able to observe its value by using console.log in the Firefox Console.
Subsequently, I attempted to add the following into the Query Header:
My issue arises from the fact that the variable is not being replaced by its real value when I invoke the API. In the Firefox Console, I can see the headers appearing like this:
Is there a solution to rectify this? Or do I need to utilize my own AJAX function to call the API and then send the JSON result to CrossUI?
Code: Select all
Authorization: Bearer Token xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (hardcoded token for testing)
Accept: application/json
Content-Type: application/json; charset=utf-8
Subsequently, I attempted to add the following into the Query Header:
Code: Select all
Authorization: Bearer Token {global.ARR.TOKEN}
Code: Select all
Authorization: Bearer Token {global.ARR.TOKEN}
Accept: application/json_v1
Content-Type: application/json; charset=utf-8
Re: Sending JSON Data in API Caller Body with CrossUI
For now, I have found a temporary solution.
My PHP login page for the application creates a cookie with a token once the user authentication is successful.
Then, in the interface created by CrossUI, before making an API invoke call, I call a global function with the following code:
This allows me to dynamically modify the `queryHeader` with the correct token retrieved from the cookie created at the beginning of the application launch during the PHP login page.
I understand that I will need to add all the different APICallers created in CrossUI to my global function. If you have a better approach to accomplish this, I would greatly appreciate it.
My PHP login page for the application creates a cookie with a token once the user authentication is successful.
Then, in the interface created by CrossUI, before making an API invoke call, I call a global function with the following code:
Code: Select all
// setToken
// [this]: global
function(token/*String*/) {
xui.APICaller._cache[0].getProperties().queryHeader.Authorization = "Bearer " + getCookie("token");
}
I understand that I will need to add all the different APICallers created in CrossUI to my global function. If you have a better approach to accomplish this, I would greatly appreciate it.
Re: Sending JSON Data in API Caller Body with CrossUI
There are 3 global hooks for APICaller:
The code will be in xuiconf.js:
The code will be in xuiconf.js:
Code: Select all
// [[Global Functions
xui.$cache.functions = {
"$APICaller:beforeInvoke" : {
"desc" : "set authToken or header for each APICaller",
"params" : [
{
"id" : "callerPrf",
"type" : "Object",
"desc" : "the caller profile"
}
],
"actions" : [
function(callerPrf){
if( xui.debugMode && window.console ){
console.log( ">> [[API calling]]", callerPrf );
}
var ins = callerPrf.boxing( ),
token = "",
custom_header = null;//{};
if(token)ins.setOAuth2Token( token );
if(custom_header)ins.setQueryHeader( custom_header );
}
]
},
"$APICaller:beforeData" : {
"desc" : "before data returns",
"params" : [
{
"id" : "rspData",
"type" : "Hash",
"desc" : ""
},
{
"id" : "req",
"type" : "String",
"desc" : ""
},
{
"id" : "callerPrf",
"type" : "Object",
"desc" : ""
}
],
"actions" : [
function(rspData, req, callerPrf){
//console.log(rspData);
}
]
},
"$APICaller:onError" : {
"desc" : "error handler",
"params" : [
{
"id" : "errMsg",
"type" : "Hash",
"desc" : ""
},
{
"id" : "req",
"type" : "String",
"desc" : ""
},
{
"id" : "callerPrf",
"type" : "Object",
"desc" : ""
},
{
"id" : "status",
"type" : "Number",
"desc" : ""
},
{
"id" : "statusText",
"type" : "String",
"desc" : ""
},
{
"id" : "rspData",
"type" : "Object",
"desc" : ""
}
],
"actions" : [
function(errMsg, req, callerPrf, status, statusText, rspData){
//console.log(errMsg);
}
]
}
};
// ]]Global Functions