Skip to content

Client API updates #9709

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: development
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -290,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.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see there are lots of mentions of Promise still in this document. Do we still need this explanation of what a Promise is, even if you don't need to use it on callback APIs?

I see the next section is also about Promises,


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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading the section below this, I'm not sure why it is titled "Promise API" but the whole text is about "Fetch API"?


This function uses the Fetch API:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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) {
Expand All @@ -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
}
Expand All @@ -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) {
Expand All @@ -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(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
}
Expand All @@ -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.
Expand All @@ -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(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
}
Expand Down
8 changes: 7 additions & 1 deletion content/en/docs/howto/security/best-practices-security.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 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";

const token = getCSRFToken();
```

#### Authentication Option 3, Custom {#custom}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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*.
Comment on lines +186 to +196
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to keep the old information as well for those who are still using MTS versions of Mendix 10.


#### Changing Objects

Expand Down Expand Up @@ -290,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
}
```

Comment on lines -293 to -316
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is still needed for customers who are using an MTS version of Mendix 10?

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)
Expand Down
Loading