From 6974a0c2c1d0dd4df8f5805834eab26b2bf2f0e1 Mon Sep 17 00:00:00 2001 From: Alisa Frelia <1579593+exec-astraea@users.noreply.github.com> Date: Thu, 19 Jun 2025 15:13:28 +0200 Subject: [PATCH 01/13] Updated docs that mention mx.session.getConfig("csrftoken") to use getCSRFToken method instead --- .../howto/security/best-practices-security.md | 8 +++++- .../security/best-practices-security.md | 12 +++++++- .../published-odata-services/_index.md | 6 ++-- .../published-rest-service/_index.md | 6 ++-- .../published-odata-services/_index.md | 17 +++++++++-- .../published-rest-service/_index.md | 28 +++++++++++++------ 6 files changed, 61 insertions(+), 16 deletions(-) diff --git a/content/en/docs/howto/security/best-practices-security.md b/content/en/docs/howto/security/best-practices-security.md index 362002cf942..1ce4d83a4c7 100644 --- a/content/en/docs/howto/security/best-practices-security.md +++ b/content/en/docs/howto/security/best-practices-security.md @@ -139,7 +139,13 @@ This authentication option is not available for Published Web Services and can o If you choose this option, the API will expect a "X-Csrf-Token" HTTP request header to be set on each incoming request. This authentication option is particularly interesting for custom JavaScript and widget implementations. -The session token can be acquired by calling `mx.session.getConfig("csrftoken")` in JavaScript. This method call should be used before each API call to prevent cross-site request forgery (CSRF/XSRF). +The session token can be acquired by calling Mendix Client API method to get the current CSRF token. This method should be called before each API call in your widget or JavaScript action to prevent cross-site request forgery (CSRF/XSRF). + +```javascript +import getCSRFToken from "mx-api/session"; + +const token = getCSRFToken(); +``` #### Authentication Option 3, Custom {#custom} diff --git a/content/en/docs/howto10/security/best-practices-security.md b/content/en/docs/howto10/security/best-practices-security.md index d571863a071..6c5d192da5b 100644 --- a/content/en/docs/howto10/security/best-practices-security.md +++ b/content/en/docs/howto10/security/best-practices-security.md @@ -139,7 +139,17 @@ This authentication option is not available for Published Web Services and can o If you choose this option, the API will expect a "X-Csrf-Token" HTTP request header to be set on each incoming request. This authentication option is particularly interesting for custom JavaScript and widget implementations. -The session token can be acquired by calling `mx.session.getConfig("csrftoken")` in JavaScript. This method call should be used before each API call to prevent cross-site request forgery (CSRF/XSRF). +The session token can be acquired by calling Mendix Client API method to get the current CSRF token. This method should be called before each API call in your widget or JavaScript action to prevent cross-site request forgery (CSRF/XSRF). + +For Mendix versions below 10.23 you can call `mx.session.getConfig("csrftoken")` in your widget or JavaScript action. + +For Mendix versions 10.23 and higher: + +```javascript +import getCSRFToken from "mx-api/session"; + +const token = getCSRFToken(); +``` #### Authentication Option 3, Custom {#custom} diff --git a/content/en/docs/refguide/modeling/integration/odata-services/published-odata-services/_index.md b/content/en/docs/refguide/modeling/integration/odata-services/published-odata-services/_index.md index f5ec2ec3cee..b4b110feb7e 100644 --- a/content/en/docs/refguide/modeling/integration/odata-services/published-odata-services/_index.md +++ b/content/en/docs/refguide/modeling/integration/odata-services/published-odata-services/_index.md @@ -182,12 +182,14 @@ This result is a header which looks like `Authorization: Basic QWxhZGRpbjpvcGVuI When you check this authentication method, the JavaScript in your app can access the REST service using the current user's session. -To prevent cross-site request forgery, the `X-Csrf-Token` header needs to be set on each request, for example: +To prevent cross-site request forgery, the `X-Csrf-Token` header needs to be set on each request. If you're using a JS action, you need can use our API to retrieve the token. ```js +import getCSRFToken from "mx-api/session"; + var xmlHttp = new XMLHttpRequest(); xmlHttp.open("GET", "http://mysite/odata/myservice/myentity", false); -xmlHttp.setRequestHeader("X-Csrf-Token", mx.session.getConfig("csrftoken")); +xmlHttp.setRequestHeader("X-Csrf-Token", getCSRFToken()); xmlHttp.send(null); ``` diff --git a/content/en/docs/refguide/modeling/integration/rest-services/published-rest-services/published-rest-service/_index.md b/content/en/docs/refguide/modeling/integration/rest-services/published-rest-services/published-rest-service/_index.md index 30724514f19..a0bf6280f6c 100644 --- a/content/en/docs/refguide/modeling/integration/rest-services/published-rest-services/published-rest-service/_index.md +++ b/content/en/docs/refguide/modeling/integration/rest-services/published-rest-services/published-rest-service/_index.md @@ -69,12 +69,14 @@ If authentication is required, you can select which authentication methods to su * Select **Active session** to allow access from JavaScript inside your current application * Once a user has logged into the browser, the JavaScript in your app can access the REST service using the current user's session * [Offline-first](/refguide/offline-first/) apps cannot use active session authentication, because they do not have sessions that stay active while the app is running -* To prevent cross-site request forgery, the `X-Csrf-Token` header needs to be set on each request, for example: +* To prevent cross-site request forgery, the `X-Csrf-Token` header needs to be set on each request. If you're using a JS action, you need can use our API to retrieve the token. ```javascript + import getCSRFToken from "mx-api/session"; + var xmlHttp = new XMLHttpRequest(); xmlHttp.open("GET", "http://mysite/rest/myservice/myresource", false); - xmlHttp.setRequestHeader("X-Csrf-Token", mx.session.getConfig("csrftoken")); + xmlHttp.setRequestHeader("X-Csrf-Token", getCSRFToken()); xmlHttp.send(null); ``` diff --git a/content/en/docs/refguide10/modeling/integration/odata-services/published-odata-services/_index.md b/content/en/docs/refguide10/modeling/integration/odata-services/published-odata-services/_index.md index 203e766bac5..cbc26cb8cce 100644 --- a/content/en/docs/refguide10/modeling/integration/odata-services/published-odata-services/_index.md +++ b/content/en/docs/refguide10/modeling/integration/odata-services/published-odata-services/_index.md @@ -186,15 +186,28 @@ This result is a header which looks like `Authorization: Basic QWxhZGRpbjpvcGVuI When you check this authentication method, the JavaScript in your app can access the REST service using the current user's session. -To prevent cross-site request forgery, the `X-Csrf-Token` header needs to be set on each request, for example: +To prevent cross-site request forgery, the `X-Csrf-Token` header needs to be set on each request. If you're using a JS action, you need can use our API to retrieve the token. -```js +Example for Mendix versions below 10.23: + +```javascript var xmlHttp = new XMLHttpRequest(); xmlHttp.open("GET", "http://mysite/odata/myservice/myentity", false); xmlHttp.setRequestHeader("X-Csrf-Token", mx.session.getConfig("csrftoken")); xmlHttp.send(null); ``` +Example for Mendix versions 10.23 and newer: + +```javascript +import getCSRFToken from "mx-api/session"; + +var xmlHttp = new XMLHttpRequest(); +xmlHttp.open("GET", "http://mysite/odata/myservice/myentity", false); +xmlHttp.setRequestHeader("X-Csrf-Token", getCSRFToken()); +xmlHttp.send(null); +``` + ##### Custom {#authentication-microflow} {{% alert color="info" %}} diff --git a/content/en/docs/refguide10/modeling/integration/rest-services/published-rest-services/published-rest-service/_index.md b/content/en/docs/refguide10/modeling/integration/rest-services/published-rest-services/published-rest-service/_index.md index 8efb9f8c387..cc5cdacd87a 100644 --- a/content/en/docs/refguide10/modeling/integration/rest-services/published-rest-services/published-rest-service/_index.md +++ b/content/en/docs/refguide10/modeling/integration/rest-services/published-rest-services/published-rest-service/_index.md @@ -69,14 +69,26 @@ If authentication is required, you can select which authentication methods to su * Select **Active session** to allow access from JavaScript inside your current application * Once a user has logged into the browser, the JavaScript in your app can access the REST service using the current user's session * [Offline-first](/refguide10/offline-first/) apps cannot use active session authentication, because they do not have sessions that stay active while the app is running -* To prevent cross-site request forgery, the `X-Csrf-Token` header needs to be set on each request, for example: - - ```javascript - var xmlHttp = new XMLHttpRequest(); - xmlHttp.open("GET", "http://mysite/rest/myservice/myresource", false); - xmlHttp.setRequestHeader("X-Csrf-Token", mx.session.getConfig("csrftoken")); - xmlHttp.send(null); - ``` +* To prevent cross-site request forgery, the `X-Csrf-Token` header needs to be set on each request. If you're using a JS action, you need can use our API to retrieve the token. + +Example for Mendix versions below 10.23: + +```javascript +var xmlHttp = new XMLHttpRequest(); +xmlHttp.open("GET", "http://mysite/rest/myservice/myresource", false); +xmlHttp.setRequestHeader("X-Csrf-Token", mx.session.getConfig("csrftoken")); +xmlHttp.send(null); +``` +Example for Mendix versions 10.23 and newer: + +```javascript +import getCSRFToken from "mx-api/session"; + +var xmlHttp = new XMLHttpRequest(); +xmlHttp.open("GET", "http://mysite/rest/myservice/myresource", false); +xmlHttp.setRequestHeader("X-Csrf-Token", mx.session.getConfig("csrftoken")); +xmlHttp.send(null); +``` * Select **Custom** to authenticate using a microflow. This microflow is called every time a user wants to access a resource. From 002e67bb992bca1ae5db0bfceadb56e56631e802 Mon Sep 17 00:00:00 2001 From: Alisa Frelia <1579593+exec-astraea@users.noreply.github.com> Date: Thu, 19 Jun 2025 15:43:49 +0200 Subject: [PATCH 02/13] Updated docs that use mx.data.create to use the new APIs --- .../best-practices-javascript-actions.md | 19 ++- .../write-javascript-github.md | 109 ++++++++--------- .../best-practices-javascript-actions.md | 19 ++- .../write-javascript-github.md | 111 ++++++++---------- 4 files changed, 117 insertions(+), 141 deletions(-) diff --git a/content/en/docs/howto/extensibility/best-practices-javascript-actions.md b/content/en/docs/howto/extensibility/best-practices-javascript-actions.md index 64116e6f346..4e8597ea2ee 100644 --- a/content/en/docs/howto/extensibility/best-practices-javascript-actions.md +++ b/content/en/docs/howto/extensibility/best-practices-javascript-actions.md @@ -183,18 +183,17 @@ For information on how to use *Big.js*, consult the [big.js API](https://mikemcl Use the following code to create objects: ```javascript -mx.data.create({ - entity: "MyFirstModule.Cat", - callback: function(object) { - console.log("Object created on server"); - }, - error: function(error) { - console.error("Could not commit object:", error); - } -}); +import { create } from "mx-api/data" + +try { + const cat = await create({ entity: "MyFirstModule.Cat" }) + console.log("Object created on server:", cat); +} catch (err) { + console.error("Could not commit object:", err); +} ``` -For more information on creating objects, consult the [Create](https://apidocs.rnd.mendix.com/10/client/mx.data.html#.create) section of the *Mendix Client API*. +For more information on creating objects, consult the [Create](https://apidocs.rnd.mendix.com/11/client-mx-api/module-mx-api_data.html#.create) section of the *Mendix Client API*. #### Changing Objects diff --git a/content/en/docs/howto/extensibility/build-javascript-actions/write-javascript-github.md b/content/en/docs/howto/extensibility/build-javascript-actions/write-javascript-github.md index e3b03b14c9d..40624589ed8 100644 --- a/content/en/docs/howto/extensibility/build-javascript-actions/write-javascript-github.md +++ b/content/en/docs/howto/extensibility/build-javascript-actions/write-javascript-github.md @@ -91,7 +91,7 @@ To create a JavaScript action that can search for users on GitHub, follow the st const url = "https://api.github.com/search/users?q=" + query; const response = await fetch(url); // Fetch returns a promise, gets the url and wait for result const jsonData = await response.json(); // Transform to JSON - logger.debug("count results", jsonData.total_count); // log to the console a successful result + console.log("count results", jsonData.total_count); // log to the console a successful result return []; // return an empty list for now... // END USER CODE } @@ -104,6 +104,8 @@ To create a JavaScript action that can search for users on GitHub, follow the st 10. Finally, set a `Promise.all` return to wait for all promises to be resolved before the nanoflow can continue: ```javascript + import { create } from "mx-api/data" + export async function SearchGitHubUsers(query) { // BEGIN USER CODE if (!query) { @@ -112,24 +114,19 @@ To create a JavaScript action that can search for users on GitHub, follow the st const url = "https://api.github.com/search/users?q=" + query; const response = await fetch(url); const jsonData = await response.json(); - logger.debug("count", jsonData.total_count); + console.log("count", jsonData.total_count); const gitHubUsers = jsonData.items.map(createGitHubUser); return Promise.all(gitHubUsers); - function createGitHubUser(user) { - return new Promise(function (resolve, reject) { - mx.data.create({ - entity: "HowTo.GitHubUser", - callback: function(mxObject) { - mxObject.set("login", user.login); - mxObject.set("avatar_url", user.avatar_url); - resolve(mxObject); - }, - error: function(e) { - reject("Could not create object:" + error.message); - } - }); - }); + async function createGitHubUser(user) { + try { + const mxObject = await create({ entity: "HowTo.GitHubUser" }); + mxObject.set("login", user.login); + mxObject.set("avatar_url", user.avatar_url); + return mxObject; + } catch(err) { + throw new Error("Could not create object:" + err.message) + } } // END USER CODE } @@ -140,6 +137,8 @@ To create a JavaScript action that can search for users on GitHub, follow the st 11. The function will only set the `login` and `avatar_url` properties. To make it more flexible, you will make the function discover the available attributes and set them. Extend the domain model with more attributes from the API like so: ```javascript + import { create } from "mx-api/data" + export async function SearchGitHubUsers(query) { // BEGIN USER CODE if (!query) { @@ -148,30 +147,25 @@ To create a JavaScript action that can search for users on GitHub, follow the st const url = "https://api.github.com/search/users?q=" + query; const response = await fetch(url); const jsonData = await response.json(); - logger.debug("count", jsonData.total_count); + console.log("count", jsonData.total_count); const gitHubUsers = jsonData.items.map(createGitHubUser); return Promise.all(gitHubUsers); - function createGitHubUser(user) { - return new Promise(function (resolve, reject) { - mx.data.create({ - entity: "HowTo.GitHubUser", - callback: function(mxObject) { - // Dynamically set attributes - mxObject.getAttributes() - .forEach(function(attributeName) { - var attributeValue = user[attributeName]; - if (attributeValue) { - mxObject.set(attributeName, attributeValue); - } - }); - resolve(mxObject); - }, - error: function(error) { - reject("Could not create object:" + error.message); - } - }); - }); + async function createGitHubUser(user) { + try { + const mxObject = await create({ entity: "HowTo.GitHubUser" }); + // Dynamically set attributes + mxObject.getAttributes() + .forEach(function(attributeName) { + var attributeValue = user[attributeName]; + if (attributeValue) { + mxObject.set(attributeName, attributeValue); + } + }); + return mxObject; + } catch(err) { + throw new Error("Could not create object:" + err.message) + } } // END USER CODE } @@ -196,9 +190,11 @@ To create a JavaScript action that can search for users on GitHub, follow the st {{< figure src="/attachments/howto/extensibility/build-javascript-actions/write-javascript-github/select-user-entity.png" alt="select user entity" class="no-border" >}} -15. Your final step is updating the code. The new `userEntity` parameter has already been added. In the `mx.data.create` function, set `userEntity` as the `entity` to be created. Then, add some documentation for future reference: +15. Your final step is updating the code. The new `userEntity` parameter has already been added. In the `create` function, set `userEntity` as the `entity` to be created. Then, add some documentation for future reference: ```javascript + import { create } from "mx-api/data" + /* Searching users on GitHub.com, it could find users via various criteria. This action returns up to 100 results. @param {string} query - The query contains one or more search keywords and qualifiers. Qualifiers allow you to limit your search to specific areas of GitHub. @@ -225,31 +221,24 @@ To create a JavaScript action that can search for users on GitHub, follow the st const url = "https://api.github.com/search/users?q=" + query; const response = await fetch(url); const jsonData = await response.json(); - logger.debug("count", jsonData.total_count); const gitHubUsers = jsonData.items.map(createGitHubUser); return Promise.all(gitHubUsers); - function createGitHubUser(user) { - // Wrap the Mendix Client API in a promise - return new Promise(function (resolve, reject) { - mx.data.create({ - entity: userEntity, - callback: function(mxObject) { - // Dynamically set attributes - mxObject.getAttributes() - .forEach(function(attributeName) { - const attributeValue = user[attributeName]; - if (attributeValue) { - mxObject.set(attributeName, attributeValue); - } - }); - resolve(mxObject); - }, - error: function(error) { - reject("Could not create object:" + error.message); - } - }); - }); + async function createGitHubUser(user) { + try { + const mxObject = await create({ entity: userEntity }); + // Dynamically set attributes + mxObject.getAttributes() + .forEach(function(attributeName) { + const attributeValue = user[attributeName]; + if (attributeValue) { + mxObject.set(attributeName, attributeValue); + } + }); + return mxObject; + } catch(err) { + throw new Error("Could not create object:" + err.message) + } } // END USER CODE } diff --git a/content/en/docs/howto10/extensibility/best-practices-javascript-actions.md b/content/en/docs/howto10/extensibility/best-practices-javascript-actions.md index 4e75b149325..9a7032c707d 100644 --- a/content/en/docs/howto10/extensibility/best-practices-javascript-actions.md +++ b/content/en/docs/howto10/extensibility/best-practices-javascript-actions.md @@ -183,18 +183,17 @@ For information on how to use *Big.js*, consult the [big.js API](https://mikemcl Use the following code to create objects: ```javascript -mx.data.create({ - entity: "MyFirstModule.Cat", - callback: function(object) { - console.log("Object created on server"); - }, - error: function(error) { - console.error("Could not commit object:", error); - } -}); +import { create } from "mx-api/data" + +try { + const cat = await create({ entity: "MyFirstModule.Cat" }) + console.log("Object created on server:", cat); +} catch (err) { + console.error("Could not commit object:", err); +} ``` -For more information on creating objects, consult the [Create](https://apidocs.rnd.mendix.com/10/client/mx.data.html#.create) section of the *Mendix Client API*. +For more information on creating objects, consult the [Create](https://apidocs.rnd.mendix.com/10/client-mx-api/module-mx-api_data.html#.create) section of the *Mendix Client API*. #### Changing Objects diff --git a/content/en/docs/howto10/extensibility/build-javascript-actions/write-javascript-github.md b/content/en/docs/howto10/extensibility/build-javascript-actions/write-javascript-github.md index 6147a27d32f..039a5ce1bce 100644 --- a/content/en/docs/howto10/extensibility/build-javascript-actions/write-javascript-github.md +++ b/content/en/docs/howto10/extensibility/build-javascript-actions/write-javascript-github.md @@ -91,7 +91,7 @@ To create a JavaScript action that can search for users on GitHub, follow the st const url = "https://api.github.com/search/users?q=" + query; const response = await fetch(url); // Fetch returns a promise, gets the url and wait for result const jsonData = await response.json(); // Transform to JSON - logger.debug("count results", jsonData.total_count); // log to the console a successful result + console.log("count results", jsonData.total_count); // log to the console a successful result return []; // return an empty list for now... // END USER CODE } @@ -104,6 +104,8 @@ To create a JavaScript action that can search for users on GitHub, follow the st 10. Finally, set a `Promise.all` return to wait for all promises to be resolved before the nanoflow can continue: ```javascript + import { create } from "mx-api/data" + export async function SearchGitHubUsers(query) { // BEGIN USER CODE if (!query) { @@ -112,24 +114,19 @@ To create a JavaScript action that can search for users on GitHub, follow the st const url = "https://api.github.com/search/users?q=" + query; const response = await fetch(url); const jsonData = await response.json(); - logger.debug("count", jsonData.total_count); + console.log("count", jsonData.total_count); const gitHubUsers = jsonData.items.map(createGitHubUser); return Promise.all(gitHubUsers); - function createGitHubUser(user) { - return new Promise(function (resolve, reject) { - mx.data.create({ - entity: "HowTo.GitHubUser", - callback: function(mxObject) { - mxObject.set("login", user.login); - mxObject.set("avatar_url", user.avatar_url); - resolve(mxObject); - }, - error: function(e) { - reject("Could not create object:" + error.message); - } - }); - }); + async function createGitHubUser(user) { + try { + const mxObject = await create({ entity: "HowTo.GitHubUser" }); + mxObject.set("login", user.login); + mxObject.set("avatar_url", user.avatar_url); + return mxObject; + } catch(err) { + throw new Error("Could not create object:" + err.message) + } } // END USER CODE } @@ -139,7 +136,9 @@ To create a JavaScript action that can search for users on GitHub, follow the st 11. The function will only set the `login` and `avatar_url` properties. To make it more flexible, you will make the function discover the available attributes and set them. Extend the domain model with more attributes from the API like so: - ```javascript + ```javascript + import { create } from "mx-api/data" + export async function SearchGitHubUsers(query) { // BEGIN USER CODE if (!query) { @@ -148,30 +147,25 @@ To create a JavaScript action that can search for users on GitHub, follow the st const url = "https://api.github.com/search/users?q=" + query; const response = await fetch(url); const jsonData = await response.json(); - logger.debug("count", jsonData.total_count); + console.log("count", jsonData.total_count); const gitHubUsers = jsonData.items.map(createGitHubUser); return Promise.all(gitHubUsers); - function createGitHubUser(user) { - return new Promise(function (resolve, reject) { - mx.data.create({ - entity: "HowTo.GitHubUser", - callback: function(mxObject) { - // Dynamically set attributes - mxObject.getAttributes() - .forEach(function(attributeName) { - var attributeValue = user[attributeName]; - if (attributeValue) { - mxObject.set(attributeName, attributeValue); - } - }); - resolve(mxObject); - }, - error: function(error) { - reject("Could not create object:" + error.message); - } - }); - }); + async function createGitHubUser(user) { + try { + const mxObject = await create({ entity: "HowTo.GitHubUser" }); + // Dynamically set attributes + mxObject.getAttributes() + .forEach(function(attributeName) { + var attributeValue = user[attributeName]; + if (attributeValue) { + mxObject.set(attributeName, attributeValue); + } + }); + return mxObject; + } catch(err) { + throw new Error("Could not create object:" + err.message) + } } // END USER CODE } @@ -196,9 +190,11 @@ To create a JavaScript action that can search for users on GitHub, follow the st {{< figure src="/attachments/howto10/extensibility/build-javascript-actions/write-javascript-github/select-user-entity.png" alt="select user entity" class="no-border" >}} -15. Your final step is updating the code. The new `userEntity` parameter has already been added. In the `mx.data.create` function, set `userEntity` as the `entity` to be created. Then, add some documentation for future reference: +15. Your final step is updating the code. The new `userEntity` parameter has already been added. In the `create` function, set `userEntity` as the `entity` to be created. Then, add some documentation for future reference: ```javascript + import { create } from "mx-api/data" + /* Searching users on GitHub.com, it could find users via various criteria. This action returns up to 100 results. @param {string} query - The query contains one or more search keywords and qualifiers. Qualifiers allow you to limit your search to specific areas of GitHub. @@ -225,31 +221,24 @@ To create a JavaScript action that can search for users on GitHub, follow the st const url = "https://api.github.com/search/users?q=" + query; const response = await fetch(url); const jsonData = await response.json(); - logger.debug("count", jsonData.total_count); const gitHubUsers = jsonData.items.map(createGitHubUser); return Promise.all(gitHubUsers); - function createGitHubUser(user) { - // Wrap the Mendix Client API in a promise - return new Promise(function (resolve, reject) { - mx.data.create({ - entity: userEntity, - callback: function(mxObject) { - // Dynamically set attributes - mxObject.getAttributes() - .forEach(function(attributeName) { - const attributeValue = user[attributeName]; - if (attributeValue) { - mxObject.set(attributeName, attributeValue); - } - }); - resolve(mxObject); - }, - error: function(error) { - reject("Could not create object:" + error.message); - } - }); - }); + async function createGitHubUser(user) { + try { + const mxObject = await create({ entity: userEntity }); + // Dynamically set attributes + mxObject.getAttributes() + .forEach(function(attributeName) { + const attributeValue = user[attributeName]; + if (attributeValue) { + mxObject.set(attributeName, attributeValue); + } + }); + return mxObject; + } catch(err) { + throw new Error("Could not create object:" + err.message) + } } // END USER CODE } From 2de1bd51ee3a7e134a0b8afa16a78d82332a0946 Mon Sep 17 00:00:00 2001 From: Alisa Frelia <1579593+exec-astraea@users.noreply.github.com> Date: Thu, 19 Jun 2025 16:03:19 +0200 Subject: [PATCH 03/13] Removed obsolete section on wrapping old APIs in promises --- .../best-practices-javascript-actions.md | 30 ------------------- .../best-practices-javascript-actions.md | 24 --------------- 2 files changed, 54 deletions(-) diff --git a/content/en/docs/howto/extensibility/best-practices-javascript-actions.md b/content/en/docs/howto/extensibility/best-practices-javascript-actions.md index 4e8597ea2ee..0bae9764b38 100644 --- a/content/en/docs/howto/extensibility/best-practices-javascript-actions.md +++ b/content/en/docs/howto/extensibility/best-practices-javascript-actions.md @@ -289,36 +289,6 @@ Use the following code to employ an asynchronous return for when your nanoflow n Many APIs and functions are designed in an asynchronous way, and use callback functions or promises. A JavaScript action expects a promise to be returned. The promise should be resolved with the return value as expected in the action. -#### Understanding Promises - -A `Promise` object represents the eventual completion (or failure) of an asynchronous operation and its resulting value. - -Use the following code to wrap a callback API in a promise: - -```javascript -function AskConfirmation(question) { - // BEGIN USER CODE - return new Promise(function (resolve) { - mx.ui.confirmation({ - content: question, - handler: function() { - resolve(true); - }, - onCancel: function() { - resolve(false); - } - }); - }); - // END USER CODE -} -``` - -Explaining the callback code: - -* Use the standard Mendix Client to show a confirmation dialog box with an **OK** and a **Cancel** button (the execution of the nanoflow halts until the user clicks one of the buttons) -* The resolve will return a Boolean value, which is used as the return value of the action -* In the nanoflow, the return variable can be used for an alternative flow for confirmation and cancel - #### Understanding Promise API This function uses the Fetch API: diff --git a/content/en/docs/howto10/extensibility/best-practices-javascript-actions.md b/content/en/docs/howto10/extensibility/best-practices-javascript-actions.md index 9a7032c707d..bf0a8e50161 100644 --- a/content/en/docs/howto10/extensibility/best-practices-javascript-actions.md +++ b/content/en/docs/howto10/extensibility/best-practices-javascript-actions.md @@ -289,30 +289,6 @@ Use the following code to employ an asynchronous return for when your nanoflow n Many APIs and functions are designed in an asynchronous way, and use callback functions or promises. A JavaScript action expects a promise to be returned. The promise should be resolved with the return value as expected in the action. -#### Understanding Promises - -A `Promise` object represents the eventual completion (or failure) of an asynchronous operation and its resulting value. - -Use the following code to wrap a callback API in a promise: - -```javascript -function AskConfirmation(question) { - // BEGIN USER CODE - return new Promise(function (resolve) { - mx.ui.confirmation({ - content: question, - handler: function() { - resolve(true); - }, - onCancel: function() { - resolve(false); - } - }); - }); - // END USER CODE -} -``` - Explaining the callback code: * Use the standard Mendix Client to show a confirmation dialog box with an **OK** and a **Cancel** button (the execution of the nanoflow halts until the user clicks one of the buttons) From 5aee559496301be5787517e6e28356e07777fcc3 Mon Sep 17 00:00:00 2001 From: Alisa Frelia <1579593+exec-astraea@users.noreply.github.com> Date: Thu, 19 Jun 2025 16:09:19 +0200 Subject: [PATCH 04/13] Use window.reload() instead of mx.reloadWithState() --- .../docs/refguide/modeling/menus/translatable-texts/_index.md | 2 +- .../docs/refguide10/modeling/menus/translatable-texts/_index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/content/en/docs/refguide/modeling/menus/translatable-texts/_index.md b/content/en/docs/refguide/modeling/menus/translatable-texts/_index.md index 556a97e8381..b1c38e6ecf9 100644 --- a/content/en/docs/refguide/modeling/menus/translatable-texts/_index.md +++ b/content/en/docs/refguide/modeling/menus/translatable-texts/_index.md @@ -88,7 +88,7 @@ There are two options to ensure that the language is changed: 1. Add the platform supported widget [HTML / JavaScript Snippet](https://marketplace.mendix.com/link/component/56/) to your app. 2. Create a pop-up page. 3. Place the HTMLSnippet widget on the pop-up page. - 4. Add the **JavaScript** content `mx.reloadWithState();` to the widget. + 4. Add the **JavaScript** content `window.reload();` to the widget. 5. Open your new pop-up page from a microflow when you want to switch the user's language. {{< figure src="/attachments/refguide/modeling/menus/translatable-texts/reload-with-state.png" alt="System Domain Model for User and Language" class="no-border" width="600" >}} diff --git a/content/en/docs/refguide10/modeling/menus/translatable-texts/_index.md b/content/en/docs/refguide10/modeling/menus/translatable-texts/_index.md index 864881ebcde..360c66c516a 100644 --- a/content/en/docs/refguide10/modeling/menus/translatable-texts/_index.md +++ b/content/en/docs/refguide10/modeling/menus/translatable-texts/_index.md @@ -88,7 +88,7 @@ There are two options to ensure that the language is changed: 1. Add the platform supported widget [HTML / JavaScript Snippet](https://marketplace.mendix.com/link/component/56/) to your app. 2. Create a pop-up page. 3. Place the HTMLSnippet widget on the pop-up page. - 4. Add the **JavaScript** content `mx.reloadWithState();` to the widget. + 4. Add the **JavaScript** content `window.reload();` to the widget. 5. Open your new pop-up page from a microflow when you want to switch the user's language. {{< figure src="/attachments/refguide10/modeling/menus/translatable-texts/reload-with-state.png" alt="System Domain Model for User and Language" class="no-border" width="600" >}} From edc993b90b7e64ac1f25e6632ab97a624c68a6e3 Mon Sep 17 00:00:00 2001 From: Alisa Frelia <1579593+exec-astraea@users.noreply.github.com> Date: Mon, 23 Jun 2025 13:47:12 +0200 Subject: [PATCH 05/13] Modernized JS syntax in the examples --- .../build-javascript-actions/write-javascript-github.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/en/docs/howto/extensibility/build-javascript-actions/write-javascript-github.md b/content/en/docs/howto/extensibility/build-javascript-actions/write-javascript-github.md index 40624589ed8..d250dea8696 100644 --- a/content/en/docs/howto/extensibility/build-javascript-actions/write-javascript-github.md +++ b/content/en/docs/howto/extensibility/build-javascript-actions/write-javascript-github.md @@ -156,8 +156,8 @@ To create a JavaScript action that can search for users on GitHub, follow the st const mxObject = await create({ entity: "HowTo.GitHubUser" }); // Dynamically set attributes mxObject.getAttributes() - .forEach(function(attributeName) { - var attributeValue = user[attributeName]; + .forEach(attributeName => { + const attributeValue = user[attributeName]; if (attributeValue) { mxObject.set(attributeName, attributeValue); } @@ -229,7 +229,7 @@ To create a JavaScript action that can search for users on GitHub, follow the st const mxObject = await create({ entity: userEntity }); // Dynamically set attributes mxObject.getAttributes() - .forEach(function(attributeName) { + .forEach(attributeName => { const attributeValue = user[attributeName]; if (attributeValue) { mxObject.set(attributeName, attributeValue); From 591337ede4a749fd5ffeb7cc4e58eb2bc210715d Mon Sep 17 00:00:00 2001 From: Quinn Tracy <142489060+quinntracy@users.noreply.github.com> Date: Mon, 23 Jun 2025 15:24:45 +0200 Subject: [PATCH 06/13] Revise --- .../odata-services/published-odata-services/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/refguide/modeling/integration/odata-services/published-odata-services/_index.md b/content/en/docs/refguide/modeling/integration/odata-services/published-odata-services/_index.md index b4b110feb7e..5e00180323f 100644 --- a/content/en/docs/refguide/modeling/integration/odata-services/published-odata-services/_index.md +++ b/content/en/docs/refguide/modeling/integration/odata-services/published-odata-services/_index.md @@ -182,7 +182,7 @@ This result is a header which looks like `Authorization: Basic QWxhZGRpbjpvcGVuI When you check this authentication method, the JavaScript in your app can access the REST service using the current user's session. -To prevent cross-site request forgery, the `X-Csrf-Token` header needs to be set on each request. If you're using a JS action, you need can use our API to retrieve the token. +To prevent cross-site request forgery, the `X-Csrf-Token` header needs to be set on each request. If you are using a JavaScript action, you can use an API to retrieve the token. ```js import getCSRFToken from "mx-api/session"; From 457d1ebc9c5b440bba937cd7a3498b8a1a2e71e2 Mon Sep 17 00:00:00 2001 From: Quinn Tracy <142489060+quinntracy@users.noreply.github.com> Date: Mon, 23 Jun 2025 15:26:29 +0200 Subject: [PATCH 07/13] Revise --- .../published-rest-services/published-rest-service/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/refguide/modeling/integration/rest-services/published-rest-services/published-rest-service/_index.md b/content/en/docs/refguide/modeling/integration/rest-services/published-rest-services/published-rest-service/_index.md index a0bf6280f6c..af024ca3aec 100644 --- a/content/en/docs/refguide/modeling/integration/rest-services/published-rest-services/published-rest-service/_index.md +++ b/content/en/docs/refguide/modeling/integration/rest-services/published-rest-services/published-rest-service/_index.md @@ -69,7 +69,7 @@ If authentication is required, you can select which authentication methods to su * Select **Active session** to allow access from JavaScript inside your current application * Once a user has logged into the browser, the JavaScript in your app can access the REST service using the current user's session * [Offline-first](/refguide/offline-first/) apps cannot use active session authentication, because they do not have sessions that stay active while the app is running -* To prevent cross-site request forgery, the `X-Csrf-Token` header needs to be set on each request. If you're using a JS action, you need can use our API to retrieve the token. +* To prevent cross-site request forgery, the `X-Csrf-Token` header needs to be set on each request; if you are using a JavaScript action, you can use an API to retrieve the token ```javascript import getCSRFToken from "mx-api/session"; From 47cd100bfbf0f4d4b6ac0e424178498c5ff37914 Mon Sep 17 00:00:00 2001 From: Quinn Tracy <142489060+quinntracy@users.noreply.github.com> Date: Mon, 23 Jun 2025 15:29:07 +0200 Subject: [PATCH 08/13] Revise --- .../odata-services/published-odata-services/_index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/en/docs/refguide10/modeling/integration/odata-services/published-odata-services/_index.md b/content/en/docs/refguide10/modeling/integration/odata-services/published-odata-services/_index.md index cbc26cb8cce..fecb4bd09f4 100644 --- a/content/en/docs/refguide10/modeling/integration/odata-services/published-odata-services/_index.md +++ b/content/en/docs/refguide10/modeling/integration/odata-services/published-odata-services/_index.md @@ -186,9 +186,9 @@ This result is a header which looks like `Authorization: Basic QWxhZGRpbjpvcGVuI When you check this authentication method, the JavaScript in your app can access the REST service using the current user's session. -To prevent cross-site request forgery, the `X-Csrf-Token` header needs to be set on each request. If you're using a JS action, you need can use our API to retrieve the token. +To prevent cross-site request forgery, the `X-Csrf-Token` header needs to be set on each request. If you are using a JavaScript action, you can use an API to retrieve the token. -Example for Mendix versions below 10.23: +For Studio Pro versions 10.22 and below, see the example below: ```javascript var xmlHttp = new XMLHttpRequest(); @@ -197,7 +197,7 @@ xmlHttp.setRequestHeader("X-Csrf-Token", mx.session.getConfig("csrftoken")); xmlHttp.send(null); ``` -Example for Mendix versions 10.23 and newer: +For Studio Pro versions 10.23 and above, see the example below: ```javascript import getCSRFToken from "mx-api/session"; From 4165acc1ac040191170e0108df6f2587893b971f Mon Sep 17 00:00:00 2001 From: Quinn Tracy <142489060+quinntracy@users.noreply.github.com> Date: Mon, 23 Jun 2025 15:33:06 +0200 Subject: [PATCH 09/13] Change version wording --- .../published-rest-service/_index.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/content/en/docs/refguide10/modeling/integration/rest-services/published-rest-services/published-rest-service/_index.md b/content/en/docs/refguide10/modeling/integration/rest-services/published-rest-services/published-rest-service/_index.md index cc5cdacd87a..bd4de90c43a 100644 --- a/content/en/docs/refguide10/modeling/integration/rest-services/published-rest-services/published-rest-service/_index.md +++ b/content/en/docs/refguide10/modeling/integration/rest-services/published-rest-services/published-rest-service/_index.md @@ -69,9 +69,9 @@ If authentication is required, you can select which authentication methods to su * Select **Active session** to allow access from JavaScript inside your current application * Once a user has logged into the browser, the JavaScript in your app can access the REST service using the current user's session * [Offline-first](/refguide10/offline-first/) apps cannot use active session authentication, because they do not have sessions that stay active while the app is running -* To prevent cross-site request forgery, the `X-Csrf-Token` header needs to be set on each request. If you're using a JS action, you need can use our API to retrieve the token. +* To prevent cross-site request forgery, the `X-Csrf-Token` header needs to be set on each request. If you are using a JavaScript action, you can use an API to retrieve the token. -Example for Mendix versions below 10.23: +For Studio Pro versions 10.22 and below, see the following example: ```javascript var xmlHttp = new XMLHttpRequest(); @@ -79,7 +79,8 @@ xmlHttp.open("GET", "http://mysite/rest/myservice/myresource", false); xmlHttp.setRequestHeader("X-Csrf-Token", mx.session.getConfig("csrftoken")); xmlHttp.send(null); ``` -Example for Mendix versions 10.23 and newer: + +For Studio Pro versions 10.23 and above, see the following example: ```javascript import getCSRFToken from "mx-api/session"; From ccd7a3a911cf4c8ea3bc444f93657a850e1cfd1a Mon Sep 17 00:00:00 2001 From: Mark van Ments Date: Tue, 24 Jun 2025 10:23:48 +0200 Subject: [PATCH 10/13] Minor proofreading changes --- content/en/docs/howto/security/best-practices-security.md | 2 +- content/en/docs/howto10/security/best-practices-security.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/content/en/docs/howto/security/best-practices-security.md b/content/en/docs/howto/security/best-practices-security.md index 1ce4d83a4c7..209d779f9f5 100644 --- a/content/en/docs/howto/security/best-practices-security.md +++ b/content/en/docs/howto/security/best-practices-security.md @@ -139,7 +139,7 @@ This authentication option is not available for Published Web Services and can o If you choose this option, the API will expect a "X-Csrf-Token" HTTP request header to be set on each incoming request. This authentication option is particularly interesting for custom JavaScript and widget implementations. -The session token can be acquired by calling Mendix Client API method to get the current CSRF token. This method should be called before each API call in your widget or JavaScript action to prevent cross-site request forgery (CSRF/XSRF). +The session token can be acquired by calling a Mendix Client API method to get the current CSRF token. This method should be called before each API call in your widget or JavaScript action to prevent cross-site request forgery (CSRF/XSRF). ```javascript import getCSRFToken from "mx-api/session"; diff --git a/content/en/docs/howto10/security/best-practices-security.md b/content/en/docs/howto10/security/best-practices-security.md index 6c5d192da5b..e229444d2da 100644 --- a/content/en/docs/howto10/security/best-practices-security.md +++ b/content/en/docs/howto10/security/best-practices-security.md @@ -141,9 +141,9 @@ If you choose this option, the API will expect a "X-Csrf-Token" HTTP request hea The session token can be acquired by calling Mendix Client API method to get the current CSRF token. This method should be called before each API call in your widget or JavaScript action to prevent cross-site request forgery (CSRF/XSRF). -For Mendix versions below 10.23 you can call `mx.session.getConfig("csrftoken")` in your widget or JavaScript action. +In Mendix versions below 10.23 you can call `mx.session.getConfig("csrftoken")` in your widget or JavaScript action. -For Mendix versions 10.23 and higher: +In Mendix versions 10.23 and above: ```javascript import getCSRFToken from "mx-api/session"; From c41eab41128ccf13fb6f0a8b0d5ccb9054b58ba2 Mon Sep 17 00:00:00 2001 From: Mark van Ments Date: Tue, 24 Jun 2025 10:24:59 +0200 Subject: [PATCH 11/13] Proofread --- content/en/docs/howto10/security/best-practices-security.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/howto10/security/best-practices-security.md b/content/en/docs/howto10/security/best-practices-security.md index e229444d2da..935364c367c 100644 --- a/content/en/docs/howto10/security/best-practices-security.md +++ b/content/en/docs/howto10/security/best-practices-security.md @@ -139,7 +139,7 @@ This authentication option is not available for Published Web Services and can o If you choose this option, the API will expect a "X-Csrf-Token" HTTP request header to be set on each incoming request. This authentication option is particularly interesting for custom JavaScript and widget implementations. -The session token can be acquired by calling Mendix Client API method to get the current CSRF token. This method should be called before each API call in your widget or JavaScript action to prevent cross-site request forgery (CSRF/XSRF). +The session token can be acquired by calling a Mendix Client API method to get the current CSRF token. This method should be called before each API call in your widget or JavaScript action to prevent cross-site request forgery (CSRF/XSRF). In Mendix versions below 10.23 you can call `mx.session.getConfig("csrftoken")` in your widget or JavaScript action. From 3a3598dd145d8e9b95c4b6b5ea9a9a402c33bc53 Mon Sep 17 00:00:00 2001 From: Mark van Ments Date: Wed, 2 Jul 2025 16:59:55 +0200 Subject: [PATCH 12/13] Clarify which code to use in Mx10.22 and below --- .../best-practices-javascript-actions.md | 2 +- .../best-practices-javascript-actions.md | 28 ++++++++++++++++++- .../write-javascript-github.md | 4 +++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/content/en/docs/howto/extensibility/best-practices-javascript-actions.md b/content/en/docs/howto/extensibility/best-practices-javascript-actions.md index 0bae9764b38..de3f20178d6 100644 --- a/content/en/docs/howto/extensibility/best-practices-javascript-actions.md +++ b/content/en/docs/howto/extensibility/best-practices-javascript-actions.md @@ -287,7 +287,7 @@ Use the following code to employ an asynchronous return for when your nanoflow n } ``` -Many APIs and functions are designed in an asynchronous way, and use callback functions or promises. A JavaScript action expects a promise to be returned. The promise should be resolved with the return value as expected in the action. +Many APIs and functions are designed in an asynchronous way, and use callback functions or [promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). A JavaScript action expects a promise to be returned. The promise should be resolved with the return value as expected in the action. #### Understanding Promise API diff --git a/content/en/docs/howto10/extensibility/best-practices-javascript-actions.md b/content/en/docs/howto10/extensibility/best-practices-javascript-actions.md index bf0a8e50161..a0775347fe8 100644 --- a/content/en/docs/howto10/extensibility/best-practices-javascript-actions.md +++ b/content/en/docs/howto10/extensibility/best-practices-javascript-actions.md @@ -180,7 +180,7 @@ For information on how to use *Big.js*, consult the [big.js API](https://mikemcl #### Creating Objects -Use the following code to create objects: +Use the following code to create objects in Mendix version 10.23 and above: ```javascript import { create } from "mx-api/data" @@ -195,6 +195,8 @@ try { For more information on creating objects, consult the [Create](https://apidocs.rnd.mendix.com/10/client-mx-api/module-mx-api_data.html#.create) section of the *Mendix Client API*. +If you are using Mendix version 10.22 or below, you will need to use [`mx.data.create`](https://apidocs.rnd.mendix.com/10/client/mx.data.html#.create). + #### Changing Objects Use the following code to change objects: @@ -295,6 +297,30 @@ Explaining the callback code: * The resolve will return a Boolean value, which is used as the return value of the action * In the nanoflow, the return variable can be used for an alternative flow for confirmation and cancel +#### Understanding Promises + +If you are using Mendix version 10.23 or below, you will need to use promises. A `Promise` object represents the eventual completion (or failure) of an asynchronous operation and its resulting value. + +Use the following code in Mendix versions 10.23 or below to wrap a callback API in a promise: + +```javascript +function AskConfirmation(question) { + // BEGIN USER CODE + return new Promise(function (resolve) { + mx.ui.confirmation({ + content: question, + handler: function() { + resolve(true); + }, + onCancel: function() { + resolve(false); + } + }); + }); + // END USER CODE +} +``` + #### Understanding Promise API This function uses the Fetch API: diff --git a/content/en/docs/howto10/extensibility/build-javascript-actions/write-javascript-github.md b/content/en/docs/howto10/extensibility/build-javascript-actions/write-javascript-github.md index 039a5ce1bce..c4fcd0667b0 100644 --- a/content/en/docs/howto10/extensibility/build-javascript-actions/write-javascript-github.md +++ b/content/en/docs/howto10/extensibility/build-javascript-actions/write-javascript-github.md @@ -10,6 +10,10 @@ description: "This advanced how-to teaches you to make a JavaScript action which Nanoflows are even more powerful with pluggable nanoflow actions — called JavaScript actions. [How to Build JavaScript Actions: Part 1 (Basic)](/howto10/extensibility/write-javascript-actions/) shows you how to create a JavaScript TextToSpeech action, expose it as a nanoflow action, and then use it in a demo. In this advanced how-to you will learn to call a REST service, use a generic return type, and make an API to enhance the power of your JavaScript actions. +{{% alert color="warning" %}} +The code on this page assumes you are using Mendix version 10.23.0 or above, the LTS version of Mendix 10. If you are using a previous version, you can refer to the code in the Mendix 9 version of [Build JavaScript Actions: Part 2 (Advanced)](/howto9/extensibility/write-javascript-github/). +{{% /alert %}} + This how-to teaches you how to do the following: * Create a JavaScript action From 000194bd1629bb4ec0adce830959713ae73ef556 Mon Sep 17 00:00:00 2001 From: Mark van Ments Date: Wed, 2 Jul 2025 17:04:28 +0200 Subject: [PATCH 13/13] Correct version number error. --- .../howto10/extensibility/best-practices-javascript-actions.md | 2 +- .../build-javascript-actions/write-javascript-github.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/content/en/docs/howto10/extensibility/best-practices-javascript-actions.md b/content/en/docs/howto10/extensibility/best-practices-javascript-actions.md index a0775347fe8..c037ad0e8bf 100644 --- a/content/en/docs/howto10/extensibility/best-practices-javascript-actions.md +++ b/content/en/docs/howto10/extensibility/best-practices-javascript-actions.md @@ -299,7 +299,7 @@ Explaining the callback code: #### Understanding Promises -If you are using Mendix version 10.23 or below, you will need to use promises. A `Promise` object represents the eventual completion (or failure) of an asynchronous operation and its resulting value. +If you are using Mendix version 10.22 or below, you will need to use promises. A `Promise` object represents the eventual completion (or failure) of an asynchronous operation and its resulting value. Use the following code in Mendix versions 10.23 or below to wrap a callback API in a promise: diff --git a/content/en/docs/howto10/extensibility/build-javascript-actions/write-javascript-github.md b/content/en/docs/howto10/extensibility/build-javascript-actions/write-javascript-github.md index c4fcd0667b0..f529f69ff0d 100644 --- a/content/en/docs/howto10/extensibility/build-javascript-actions/write-javascript-github.md +++ b/content/en/docs/howto10/extensibility/build-javascript-actions/write-javascript-github.md @@ -11,7 +11,7 @@ description: "This advanced how-to teaches you to make a JavaScript action which Nanoflows are even more powerful with pluggable nanoflow actions — called JavaScript actions. [How to Build JavaScript Actions: Part 1 (Basic)](/howto10/extensibility/write-javascript-actions/) shows you how to create a JavaScript TextToSpeech action, expose it as a nanoflow action, and then use it in a demo. In this advanced how-to you will learn to call a REST service, use a generic return type, and make an API to enhance the power of your JavaScript actions. {{% alert color="warning" %}} -The code on this page assumes you are using Mendix version 10.23.0 or above, the LTS version of Mendix 10. If you are using a previous version, you can refer to the code in the Mendix 9 version of [Build JavaScript Actions: Part 2 (Advanced)](/howto9/extensibility/write-javascript-github/). +The code on this page assumes you are using Mendix version 10.23.0 or above. If you are using a previous version, you can refer to the code in the Mendix 9 version of [Build JavaScript Actions: Part 2 (Advanced)](/howto9/extensibility/write-javascript-github/). {{% /alert %}} This how-to teaches you how to do the following: