• /
  • EnglishEspañolFrançais日本語한국어Português
  • Se connecterDémarrer

Cette traduction automatique est fournie pour votre commodité.

En cas d'incohérence entre la version anglaise et la version traduite, la version anglaise prévaudra. Veuillez visiter cette page pour plus d'informations.

Créer un problème

Accédez à NerdStorageVault depuis votre Nerdlet

Conseil

Cette leçon fait partie d’un cours qui vous apprend à créer une application New Relic à partir de zéro. Si vous ne l’avez pas déjà fait, consultez la présentation.

Chaque leçon du cours s'appuie sur la précédente, alors assurez-vous d'avoir terminé la dernière leçon, Accéder à NerdStorage depuis votre nerdlet, avant de commencer celle-ci.

Tout au long de ce cours, vous créez une application New Relic qui collecte des données télémétriques à partir d'un service Web de démonstration qui exécute un test A/B sur un formulaire d'inscription à une newsletter. L'objectif de votre application New Relic est de vous aider à comprendre comment les changements de conception impactent le nombre d'abonnements à des newsletters de haute qualité que votre service reçoit. L'objectif commercial, augmenter le nombre d'abonnements à la newsletter de qualité de votre service, repose principalement sur trois informations clés :

  • Nombre de pages vues par version
  • Nombre d'abonnement par version
  • Nombre d'annulations

Les annulations sont importantes car si une version de conception de votre formulaire d'inscription à la newsletter génère un nombre élevé d'abonnements mais également un nombre élevé d'annulations, alors ces abonnements n'ont pas autant de valeur.

Dans les leçons précédentes, vous avez collecté des données sur les pages vues et les abonnements à partir de la base de données de New Relic (NRDB), mais vous avez toujours besoin de données d'annulation. Votre application de démonstration ne signale pas les données d'annulation à New Relic. Vous devez donc récupérer ces données à partir d'une source externe. Nous avons fourni un service sur https://api.nerdsletter.net/cancellations pour renvoyer de fausses données d'annulation aux fins de ce cours. Si vous visitez cette URL dans votre navigateur, vous verrez un bref message : « Non autorisé ». C'est parce que nous avons créé ce service avec l'exigence que quiconque requests ses données doit passer un en-tête d'autorisation avec le jeton porteur ABC123.

Donc, avant de pouvoir demander des données d'annulation à api.nerdsletter.net, vous devez implémenter quelques nouveaux comportements dans votre application :

  • Fournir un mécanisme pour saisir un jeton d'autorisation
  • Conserver le jeton d'autorisation dans un datastore sécurisé

Pour saisir votre jeton d'autorisation, vous utiliserez un Modal avec un TextField. Le datastore sécurisé que vous utiliserez s'appelle NerdStorageVault. Il est différent de NerdStorage, que vous avez utilisé dans la dernière leçon, car il prend uniquement en charge le stockage utilisateur et crypte ses données.

Stockez votre jeton API

Accédez au répertoire add-nerdstoragevault/ab-test du référentiel de cours:

bash
$
cd nru-programmability-course/add-nerdstoragevault/ab-test

Ce répertoire contient le code que nous attendons de votre application à ce stade du cours. En naviguant vers le bon répertoire au début de chaque leçon, vous laissez votre code personnalisé derrière vous, vous protégeant ainsi du transport de code incorrect d'une leçon à l'autre.

Dans le fichier index.js de votre Nerdlet, initialisez state dans AbTestNerdletNerdlet avec un jeton par défaut null :

import React from 'react';
import { ChartGroup, Grid, GridItem } from 'nr1';
import EndTestSection from './end-test';
import NewsletterSignups from './newsletter-signups';
import PastTests from './past-tests';
import TotalCancellations from './total-cancellations';
import TotalSubscriptions from './total-subscriptions';
import VersionDescription from './description';
import VersionPageViews from './page-views';
import VersionTotals from './totals';
const ACCOUNT_ID = 123456 // <YOUR NEW RELIC ACCOUNT ID>
const VERSION_A_DESCRIPTION = 'The newsletter signup message says, "Sign up for our newsletter"'
const VERSION_B_DESCRIPTION = 'The newsletter signup message says, "Sign up for our newsletter and get a free shirt!"'
export default class AbTestNerdletNerdlet extends React.Component {
constructor() {
super(...arguments);
this.state = {
token: null,
}
}
render() {
return <div>
<Grid className="wrapper">
<GridItem columnSpan={6}>
<VersionDescription
description={VERSION_A_DESCRIPTION}
version="A"
/>
</GridItem>
<GridItem columnSpan={6}>
<VersionDescription
description={VERSION_B_DESCRIPTION}
version="B"
/>
</GridItem>
<GridItem columnSpan={12}><hr /></GridItem>
<GridItem columnSpan={12}><NewsletterSignups /></GridItem>
<GridItem columnSpan={6}><TotalSubscriptions /></GridItem>
<GridItem columnSpan={6}><TotalCancellations /></GridItem>
<GridItem columnSpan={6}>
<VersionTotals version='a' accountId={ACCOUNT_ID} />
</GridItem>
<GridItem columnSpan={6}>
<VersionTotals version='b' accountId={ACCOUNT_ID} />
</GridItem>
<ChartGroup>
<GridItem columnSpan={6}>
<VersionPageViews version='a' />
</GridItem>
<GridItem columnSpan={6}>
<VersionPageViews version='b' />
</GridItem>
</ChartGroup>
<GridItem columnSpan={12}>
<EndTestSection
accountId={ACCOUNT_ID}
versionADescription={VERSION_A_DESCRIPTION}
versionBDescription={VERSION_B_DESCRIPTION}
/>
</GridItem>
<GridItem columnSpan={12}>
<PastTests accountId={ACCOUNT_ID} />
</GridItem>
</Grid>
</div>
}
}

Votre Nerdlet utilise cet état token pour gérer le jeton d'autorisation que vous transmettrez ultérieurement au service tiers. Cependant, state d’un composant ne constitue pas une solution à long terme pour la gestion des données. Pour cela, vous avez besoin NerdStorageVault.

Implémentez une méthode, appelée storeToken(), qui mute les données NerdStorageVault et liez cette méthode à l'instance AbTestNerdletNerdlet :

import React from 'react';
import {
ChartGroup,
Grid,
GridItem,
NerdGraphMutation,
} from 'nr1';
import EndTestSection from './end-test';
import NewsletterSignups from './newsletter-signups';
import PastTests from './past-tests';
import TotalCancellations from './total-cancellations';
import TotalSubscriptions from './total-subscriptions';
import VersionDescription from './description';
import VersionPageViews from './page-views';
import VersionTotals from './totals';
const ACCOUNT_ID = 123456 // <YOUR NEW RELIC ACCOUNT ID>
const VERSION_A_DESCRIPTION = 'The newsletter signup message says, "Sign up for our newsletter"'
const VERSION_B_DESCRIPTION = 'The newsletter signup message says, "Sign up for our newsletter and get a free shirt!"'
export default class AbTestNerdletNerdlet extends React.Component {
constructor() {
super(...arguments);
this.state = {
token: null,
}
this.storeToken = this.storeToken.bind(this);
}
storeToken(newToken) {
if (newToken != this.state.token) {
const mutation = `
mutation($key: String!, $token: SecureValue!) {
nerdStorageVaultWriteSecret(
scope: { actor: CURRENT_USER }
secret: { key: $key, value: $token }
) {
status
errors {
message
type
}
}
}
`;
const variables = {
key: "api_token",
token: newToken,
};
NerdGraphMutation.mutate({ mutation: mutation, variables: variables }).then(
(data) => {
if (data.data.nerdStorageVaultWriteSecret.status === "SUCCESS") {
this.setState({token: newToken})
}
}
);
}
}
render() {
return <div>
<Grid className="wrapper">
<GridItem columnSpan={6}>
<VersionDescription
description={VERSION_A_DESCRIPTION}
version="A"
/>
</GridItem>
<GridItem columnSpan={6}>
<VersionDescription
description={VERSION_B_DESCRIPTION}
version="B"
/>
</GridItem>
<GridItem columnSpan={12}><hr /></GridItem>
<GridItem columnSpan={12}><NewsletterSignups /></GridItem>
<GridItem columnSpan={6}><TotalSubscriptions /></GridItem>
<GridItem columnSpan={6}><TotalCancellations /></GridItem>
<GridItem columnSpan={6}>
<VersionTotals version='a' accountId={ACCOUNT_ID} />
</GridItem>
<GridItem columnSpan={6}>
<VersionTotals version='b' accountId={ACCOUNT_ID} />
</GridItem>
<ChartGroup>
<GridItem columnSpan={6}>
<VersionPageViews version='a' />
</GridItem>
<GridItem columnSpan={6}>
<VersionPageViews version='b' />
</GridItem>
</ChartGroup>
<GridItem columnSpan={12}>
<EndTestSection
accountId={ACCOUNT_ID}
versionADescription={VERSION_A_DESCRIPTION}
versionBDescription={VERSION_B_DESCRIPTION}
/>
</GridItem>
<GridItem columnSpan={12}>
<PastTests accountId={ACCOUNT_ID} />
</GridItem>
</Grid>
</div>
}
}

Lorsque vous appelez storeToken() avec une nouvelle valeur de jeton, votre Nerdlet utilise les API NerdGraph pour muter les données NerdStorageVault pour la clé api_token . Si la demande à NerdGraph réussit, storeToken() met à jour state.token afin que le nouveau jeton soit accessible localement.

Contrairement à NerdStorage, qui dispose de composants de requête et de mutation pour votre commodité, NerdStorageVault n'a aucun composant dans le SDK. Au lieu de cela, vous devez utiliser NerdGraphQuery et NerdGraphMutation pour interagir avec lui

Important

Il est important de se rappeler que NerdStorageVault est limité à la portée de l’utilisateur. Tout autre utilisateur de votre application New Relic aura ses propres données NerdStorageVault . Cela signifie que même les autres utilisateurs de votre compte devront saisir leur jeton séparément.

interrogez votre jeton API

Tout d’abord, créez des méthodes et state pour afficher et masquer votre prompt de jeton API :

import React from 'react';
import {
ChartGroup,
Grid,
GridItem,
NerdGraphMutation,
} from 'nr1';
import EndTestSection from './end-test';
import NewsletterSignups from './newsletter-signups';
import PastTests from './past-tests';
import TotalCancellations from './total-cancellations';
import TotalSubscriptions from './total-subscriptions';
import VersionDescription from './description';
import VersionPageViews from './page-views';
import VersionTotals from './totals';
const ACCOUNT_ID = 123456 // <YOUR NEW RELIC ACCOUNT ID>
const VERSION_A_DESCRIPTION = 'The newsletter signup message says, "Sign up for our newsletter"'
const VERSION_B_DESCRIPTION = 'The newsletter signup message says, "Sign up for our newsletter and get a free shirt!"'
export default class AbTestNerdletNerdlet extends React.Component {
constructor() {
super(...arguments);
this.state = {
hideTokenPrompt: true,
token: null,
}
this.storeToken = this.storeToken.bind(this);
this.showPrompt = this.showPrompt.bind(this);
this.hidePrompt = this.hidePrompt.bind(this);
}
storeToken(newToken) {
if (newToken != this.state.token) {
const mutation = `
mutation($key: String!, $token: SecureValue!) {
nerdStorageVaultWriteSecret(
scope: { actor: CURRENT_USER }
secret: { key: $key, value: $token }
) {
status
errors {
message
type
}
}
}
`;
const variables = {
key: "api_token",
token: newToken,
};
NerdGraphMutation.mutate({ mutation: mutation, variables: variables }).then(
(data) => {
if (data.data.nerdStorageVaultWriteSecret.status === "SUCCESS") {
this.setState({token: newToken})
}
}
);
}
}
showPrompt() {
this.setState({ hideTokenPrompt: false });
}
hidePrompt() {
this.setState({ hideTokenPrompt: true });
}
render() {
return <div>
<Grid className="wrapper">
<GridItem columnSpan={6}>
<VersionDescription
description={VERSION_A_DESCRIPTION}
version="A"
/>
</GridItem>
<GridItem columnSpan={6}>
<VersionDescription
description={VERSION_B_DESCRIPTION}
version="B"
/>
</GridItem>
<GridItem columnSpan={12}><hr /></GridItem>
<GridItem columnSpan={12}><NewsletterSignups /></GridItem>
<GridItem columnSpan={6}><TotalSubscriptions /></GridItem>
<GridItem columnSpan={6}><TotalCancellations /></GridItem>
<GridItem columnSpan={6}>
<VersionTotals version='a' accountId={ACCOUNT_ID} />
</GridItem>
<GridItem columnSpan={6}>
<VersionTotals version='b' accountId={ACCOUNT_ID} />
</GridItem>
<ChartGroup>
<GridItem columnSpan={6}>
<VersionPageViews version='a' />
</GridItem>
<GridItem columnSpan={6}>
<VersionPageViews version='b' />
</GridItem>
</ChartGroup>
<GridItem columnSpan={12}>
<EndTestSection
accountId={ACCOUNT_ID}
versionADescription={VERSION_A_DESCRIPTION}
versionBDescription={VERSION_B_DESCRIPTION}
/>
</GridItem>
<GridItem columnSpan={12}>
<PastTests accountId={ACCOUNT_ID} />
</GridItem>
</Grid>
</div>
}
}

state.hideTokenPrompt détermine si le prompt est visible ou non. Maintenant, vous avez besoin d’un mécanisme pour révéler le prompt, qui est masqué par défaut.

requête NerdStorageVault pour votre api_token:

import React from 'react';
import {
ChartGroup,
Grid,
GridItem,
NerdGraphMutation,
NerdGraphQuery,
} from 'nr1';
import EndTestSection from './end-test';
import NewsletterSignups from './newsletter-signups';
import PastTests from './past-tests';
import TotalCancellations from './total-cancellations';
import TotalSubscriptions from './total-subscriptions';
import VersionDescription from './description';
import VersionPageViews from './page-views';
import VersionTotals from './totals';
const ACCOUNT_ID = 123456 // <YOUR NEW RELIC ACCOUNT ID>
const VERSION_A_DESCRIPTION = 'The newsletter signup message says, "Sign up for our newsletter"'
const VERSION_B_DESCRIPTION = 'The newsletter signup message says, "Sign up for our newsletter and get a free shirt!"'
export default class AbTestNerdletNerdlet extends React.Component {
constructor() {
super(...arguments);
this.state = {
hideTokenPrompt: true,
token: null,
}
this.storeToken = this.storeToken.bind(this);
this.showPrompt = this.showPrompt.bind(this);
this.hidePrompt = this.hidePrompt.bind(this);
}
storeToken(newToken) {
if (newToken != this.state.token) {
const mutation = `
mutation($key: String!, $token: SecureValue!) {
nerdStorageVaultWriteSecret(
scope: { actor: CURRENT_USER }
secret: { key: $key, value: $token }
) {
status
errors {
message
type
}
}
}
`;
const variables = {
key: "api_token",
token: newToken,
};
NerdGraphMutation.mutate({ mutation: mutation, variables: variables }).then(
(data) => {
if (data.data.nerdStorageVaultWriteSecret.status === "SUCCESS") {
this.setState({token: newToken})
}
}
);
}
}
showPrompt() {
this.setState({ hideTokenPrompt: false });
}
hidePrompt() {
this.setState({ hideTokenPrompt: true });
}
componentDidMount() {
const query = `
query($key: String!) {
actor {
nerdStorageVault {
secret(key: $key) {
value
}
}
}
}
`;
const variables = {
key: "api_token",
};
NerdGraphQuery.query(
{
query: query,
variables: variables,
}
).then(
({ loading, error, data }) => {
if (error) {
console.error(error);
this.showPrompt();
}
if (data && data.actor.nerdStorageVault.secret) {
this.setState({ token: data.actor.nerdStorageVault.secret.value })
} else {
this.showPrompt();
}
}
)
}
render() {
return <div>
<Grid className="wrapper">
<GridItem columnSpan={6}>
<VersionDescription
description={VERSION_A_DESCRIPTION}
version="A"
/>
</GridItem>
<GridItem columnSpan={6}>
<VersionDescription
description={VERSION_B_DESCRIPTION}
version="B"
/>
</GridItem>
<GridItem columnSpan={12}><hr /></GridItem>
<GridItem columnSpan={12}><NewsletterSignups /></GridItem>
<GridItem columnSpan={6}><TotalSubscriptions /></GridItem>
<GridItem columnSpan={6}><TotalCancellations /></GridItem>
<GridItem columnSpan={6}>
<VersionTotals version='a' accountId={ACCOUNT_ID} />
</GridItem>
<GridItem columnSpan={6}>
<VersionTotals version='b' accountId={ACCOUNT_ID} />
</GridItem>
<ChartGroup>
<GridItem columnSpan={6}>
<VersionPageViews version='a' />
</GridItem>
<GridItem columnSpan={6}>
<VersionPageViews version='b' />
</GridItem>
</ChartGroup>
<GridItem columnSpan={12}>
<EndTestSection
accountId={ACCOUNT_ID}
versionADescription={VERSION_A_DESCRIPTION}
versionBDescription={VERSION_B_DESCRIPTION}
/>
</GridItem>
<GridItem columnSpan={12}>
<PastTests accountId={ACCOUNT_ID} />
</GridItem>
</Grid>
</div>
}
}

Ici, dans componentDidMount(), vous avez demandé à NerdGraph vos données api_token . componentDidMount() est une méthode de cycle de vie React qui est appelée lorsque votre composant est monté dans l'arborescence des composants. Cela signifie qu'au début de son processus de configuration, votre application demandera votre api_token.

Si la requête NerdGraph répond avec succès avec votre jeton de NerdStorageVault, elle définit le jeton dans state. Sinon, il affiche le prompt pour que vous puissiez saisir un jeton.

C'est idéal pour stocker un jeton initial, mais que se passe-t-il si vous entrez le mauvais jeton ou si l'API change ? Vous avez besoin d’un moyen de révéler l’ prompt à la demande. Ensuite, vous créerez l’ prompt jeton réelle et un bouton pour appeler manuellement l’ prompt.

Créez votre prompt

Dans nerdlets/ab-test-nerdlet, ajoutez un nouveau fichier Javascript nommé token-prompt.js:

bash
$
touch token-prompt.js

Dans ce nouveau fichier, créez un bouton qui vous permet de saisir un nouveau jeton à la demande :

import React from 'react';
import { Button } from 'nr1';
class ApiTokenButton extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<Button onClick={this.props.showPrompt}>Update API token</Button>
)
}
}

ApiTokenButton reçoit showPrompt() dans ses accessoires et appelle cette méthode lorsque son Button est cliqué.

Créez une prompt de jeton en utilisant un Modal avec un TextField:

import React from 'react';
import {
Button,
Modal,
TextField,
} from 'nr1';
class ApiTokenButton extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<Button onClick={this.props.showPrompt}>Update API token</Button>
)
}
}
class ApiTokenPrompt extends React.Component {
constructor() {
super(...arguments);
this.state = {
token: null,
tokenError: false,
};
this.submitToken = this.submitToken.bind(this);
this.hideTokenError = this.hideTokenError.bind(this);
this.changeToken = this.changeToken.bind(this);
this.keyPress = this.keyPress.bind(this);
}
showTokenError() {
this.setState({ tokenError: true });
}
hideTokenError() {
this.setState({ tokenError: false });
}
changeToken(event) {
this.setState({ token: event.target.value });
}
submitToken(event) {
event.preventDefault();
if (this.state.token) {
this.props.storeToken(this.state.token)
this.hideTokenError()
this.props.hidePrompt()
} else {
this.showTokenError()
}
}
keyPress(event) {
if(event.keyCode == 13) {
event.preventDefault();
this.submitToken(event);
}
}
render() {
return <Modal hidden={this.props.hideTokenPrompt} onClose={this.props.hidePrompt}>
To see cancellation data, you need to enter an API token for your backend service:
<form>
<TextField label="API token" onChange={this.changeToken} onKeyDown={this.keyPress} invalid={this.state.tokenError ? "Token required" : false} />
<Button type={Button.TYPE.PRIMARY} onClick={this.submitToken}>Submit</Button>
</form>
</Modal>
}
}

ApiTokenPrompt rend un Modal avec un TextField, un Button et une prompt explicative. Vous utilisez le Modal pour saisir votre jeton API. Il fournit également une gestion des erreurs de base si vous essayez de soumettre le formulaire sans valeur de jeton.

Il est important de distinguer le token dans AbTestNerdletNerdlet.state et le token dans ApiTokenPrompt.state. Le token dans state de votre Nerdlet est le jeton actuel que votre Nerdlet connaît. C'est ce jeton qui correspond à ce qui est dans NerdStorageVault. Le token dans ApiTokenPrompt.state est une valeur fluide qui change lorsque vous mettez à jour le texte dans TextField. Lorsque vous appuyez sur Submit dans la fenêtre modale, ApiTokenPrompt soumet son token à la méthode storeToken() de votre Nerdlet. Ensuite, storeToken() mute NerdStorageVault avec le nouveau jeton.

Vous avez également mis en œuvre quelques méthodes pour améliorer l'expérience utilisateur :

  • keyPress() soumet le jeton lorsque la touche RETURN est enfoncée
  • showTokenError() et hideTokenError() rappelle à l'utilisateur qu'il doit saisir un jeton avant de soumettre le formulaire

Exportez vos composants pour pouvoir les utiliser dans votre Nerdlet :

import React from 'react';
import {
Button,
Modal,
TextField,
} from 'nr1';
class ApiTokenButton extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<Button onClick={this.props.showPrompt}>Update API token</Button>
)
}
}
class ApiTokenPrompt extends React.Component {
constructor() {
super(...arguments);
this.state = {
token: null,
tokenError: false,
};
this.submitToken = this.submitToken.bind(this);
this.hideTokenError = this.hideTokenError.bind(this);
this.changeToken = this.changeToken.bind(this);
this.keyPress = this.keyPress.bind(this);
}
showTokenError() {
this.setState({ tokenError: true });
}
hideTokenError() {
this.setState({ tokenError: false });
}
changeToken(event) {
this.setState({ token: event.target.value });
}
submitToken(event) {
event.preventDefault();
if (this.state.token) {
this.props.storeToken(this.state.token)
this.hideTokenError()
this.props.hidePrompt()
} else {
this.showTokenError()
}
}
keyPress(event) {
if(event.keyCode == 13) {
event.preventDefault();
this.submitToken(event);
}
}
render() {
return <Modal hidden={this.props.hideTokenPrompt} onClose={this.props.hidePrompt}>
To see cancellation data, you need to enter an API token for your backend service:
<form>
<TextField label="API token" onChange={this.changeToken} onKeyDown={this.keyPress} invalid={this.state.tokenError ? "Token required" : false} />
<Button type={Button.TYPE.PRIMARY} onClick={this.submitToken}>Submit</Button>
</form>
</Modal>
}
}
export { ApiTokenButton, ApiTokenPrompt }

Dans le fichier index.js de votre Nerdlet, importez ApiTokenButton et ApiTokenPrompt et ajoutez-les à render():

import React from 'react';
import {
ChartGroup,
Grid,
GridItem,
NerdGraphMutation,
NerdGraphQuery,
} from 'nr1';
import EndTestSection from './end-test';
import NewsletterSignups from './newsletter-signups';
import PastTests from './past-tests';
import TotalCancellations from './total-cancellations';
import TotalSubscriptions from './total-subscriptions';
import VersionDescription from './description';
import VersionPageViews from './page-views';
import VersionTotals from './totals';
import { ApiTokenButton, ApiTokenPrompt } from './token-prompt';
const ACCOUNT_ID = 123456 // <YOUR NEW RELIC ACCOUNT ID>
const VERSION_A_DESCRIPTION = 'The newsletter signup message says, "Sign up for our newsletter"'
const VERSION_B_DESCRIPTION = 'The newsletter signup message says, "Sign up for our newsletter and get a free shirt!"'
export default class AbTestNerdletNerdlet extends React.Component {
constructor() {
super(...arguments);
this.state = {
hideTokenPrompt: true,
token: null,
}
this.storeToken = this.storeToken.bind(this);
this.showPrompt = this.showPrompt.bind(this);
this.hidePrompt = this.hidePrompt.bind(this);
}
storeToken(newToken) {
if (newToken != this.state.token) {
const mutation = `
mutation($key: String!, $token: SecureValue!) {
nerdStorageVaultWriteSecret(
scope: { actor: CURRENT_USER }
secret: { key: $key, value: $token }
) {
status
errors {
message
type
}
}
}
`;
const variables = {
key: "api_token",
token: newToken,
};
NerdGraphMutation.mutate({ mutation: mutation, variables: variables }).then(
(data) => {
if (data.data.nerdStorageVaultWriteSecret.status === "SUCCESS") {
this.setState({token: newToken})
}
}
);
}
}
showPrompt() {
this.setState({ hideTokenPrompt: false });
}
hidePrompt() {
this.setState({ hideTokenPrompt: true });
}
componentDidMount() {
const query = `
query($key: String!) {
actor {
nerdStorageVault {
secret(key: $key) {
value
}
}
}
}
`;
const variables = {
key: "api_token",
};
NerdGraphQuery.query(
{
query: query,
variables: variables,
}
).then(
({ loading, error, data }) => {
if (error) {
console.error(error);
this.showPrompt();
}
if (data && data.actor.nerdStorageVault.secret) {
this.setState({ token: data.actor.nerdStorageVault.secret.value })
} else {
this.showPrompt();
}
}
)
}
render() {
return <div>
<ApiTokenPrompt
hideTokenPrompt={this.state.hideTokenPrompt}
hidePrompt={this.hidePrompt}
showPrompt={this.showPrompt}
storeToken={this.storeToken}
/>
<Grid className="wrapper">
<GridItem columnSpan={6}>
<VersionDescription
description={VERSION_A_DESCRIPTION}
version="A"
/>
</GridItem>
<GridItem columnSpan={6}>
<VersionDescription
description={VERSION_B_DESCRIPTION}
version="B"
/>
</GridItem>
<GridItem columnSpan={12}><hr /></GridItem>
<GridItem columnSpan={12}><NewsletterSignups /></GridItem>
<GridItem columnSpan={6}><TotalSubscriptions /></GridItem>
<GridItem columnSpan={6}><TotalCancellations /></GridItem>
<GridItem columnSpan={6}>
<VersionTotals version='a' accountId={ACCOUNT_ID} />
</GridItem>
<GridItem columnSpan={6}>
<VersionTotals version='b' accountId={ACCOUNT_ID} />
</GridItem>
<ChartGroup>
<GridItem columnSpan={6}>
<VersionPageViews version='a' />
</GridItem>
<GridItem columnSpan={6}>
<VersionPageViews version='b' />
</GridItem>
</ChartGroup>
<GridItem columnSpan={12}>
<EndTestSection
accountId={ACCOUNT_ID}
versionADescription={VERSION_A_DESCRIPTION}
versionBDescription={VERSION_B_DESCRIPTION}
/>
</GridItem>
<GridItem columnSpan={12}>
<PastTests accountId={ACCOUNT_ID} />
</GridItem>
<GridItem columnSpan={12}>
<ApiTokenButton showPrompt={this.showPrompt} />
</GridItem>
</Grid>
</div>
}
}

Accédez à la racine de votre Nerdpack à nru-programmability-course/add-nerdstoragevault/ab-test.

Générez un nouvel UUID pour votre Nerdpack :

bash
$
nr1 nerdpack:uuid -gf

Étant donné que vous avez cloné le référentiel de cours qui contenait un Nerdpack existant, vous devez générer votre propre identifiant unique. Cet UUID mappe votre Nerdpack à votre compte New Relic. Il permet également à votre application de faire requests Nerdgraph au nom de votre compte.

Présentez votre demande localement :

bash
$
nr1 nerdpack:serve

Accédez à https://one.newrelic.com?nerdpacks=local et affichez votre application sous Apps > Your apps.

Lorsque vous visitez votre application pour la première fois, le prompt est automatiquement révélée. Saisissez « ABC123 » dans le TextField, car c'est le jeton attendu par le service tiers. Une fois que vous avez soumis votre jeton et que votre Nerdlet masque le prompt, cliquez sur Update API token en bas de votre application New Relic pour le révéler à nouveau.

Conseil

Si quelque chose ne fonctionne pas, utilisez les outils de débogage de votre navigateur pour essayer d'identifier le problème.

Assurez-vous de :

  • J'ai copié correctement le code de la leçon
  • Générer un nouvel UUID
  • Remplacé toutes les instances de <YOUR NEW RELIC ACCOUNT ID> dans votre projet par votre identifiant de compteNew Relic actuel

Transmettez votre jeton API à TotalCancellations

Dans index.js, transmettez le jeton API à TotalCancellations afin d'être prêt à faire une demande au service tiers :

import React from 'react';
import {
ChartGroup,
Grid,
GridItem,
NerdGraphMutation,
NerdGraphQuery,
} from 'nr1';
import EndTestSection from './end-test';
import NewsletterSignups from './newsletter-signups';
import PastTests from './past-tests';
import TotalCancellations from './total-cancellations';
import TotalSubscriptions from './total-subscriptions';
import VersionDescription from './description';
import VersionPageViews from './page-views';
import VersionTotals from './totals';
import { ApiTokenButton, ApiTokenPrompt } from './token-prompt';
const ACCOUNT_ID = 123456 // <YOUR NEW RELIC ACCOUNT ID>
const VERSION_A_DESCRIPTION = 'The newsletter signup message says, "Sign up for our newsletter"'
const VERSION_B_DESCRIPTION = 'The newsletter signup message says, "Sign up for our newsletter and get a free shirt!"'
export default class AbTestNerdletNerdlet extends React.Component {
constructor() {
super(...arguments);
this.state = {
hideTokenPrompt: true,
token: null,
}
this.storeToken = this.storeToken.bind(this);
this.showPrompt = this.showPrompt.bind(this);
this.hidePrompt = this.hidePrompt.bind(this);
}
storeToken(newToken) {
if (newToken != this.state.token) {
const mutation = `
mutation($key: String!, $token: SecureValue!) {
nerdStorageVaultWriteSecret(
scope: { actor: CURRENT_USER }
secret: { key: $key, value: $token }
) {
status
errors {
message
type
}
}
}
`;
const variables = {
key: "api_token",
token: newToken,
};
NerdGraphMutation.mutate({ mutation: mutation, variables: variables }).then(
(data) => {
if (data.data.nerdStorageVaultWriteSecret.status === "SUCCESS") {
this.setState({token: newToken})
}
}
);
}
}
showPrompt() {
this.setState({ hideTokenPrompt: false });
}
hidePrompt() {
this.setState({ hideTokenPrompt: true });
}
componentDidMount() {
const query = `
query($key: String!) {
actor {
nerdStorageVault {
secret(key: $key) {
value
}
}
}
}
`;
const variables = {
key: "api_token",
};
NerdGraphQuery.query(
{
query: query,
variables: variables,
}
).then(
({ loading, error, data }) => {
if (error) {
console.error(error);
this.showPrompt();
}
if (data && data.actor.nerdStorageVault.secret) {
this.setState({ token: data.actor.nerdStorageVault.secret.value })
} else {
this.showPrompt();
}
}
)
}
render() {
return <div>
<ApiTokenPrompt
hideTokenPrompt={this.state.hideTokenPrompt}
hidePrompt={this.hidePrompt}
showPrompt={this.showPrompt}
storeToken={this.storeToken}
/>
<Grid className="wrapper">
<GridItem columnSpan={6}>
<VersionDescription
description={VERSION_A_DESCRIPTION}
version="A"
/>
</GridItem>
<GridItem columnSpan={6}>
<VersionDescription
description={VERSION_B_DESCRIPTION}
version="B"
/>
</GridItem>
<GridItem columnSpan={12}><hr /></GridItem>
<GridItem columnSpan={12}><NewsletterSignups /></GridItem>
<GridItem columnSpan={6}><TotalSubscriptions /></GridItem>
<GridItem columnSpan={6}>
<TotalCancellations token={this.state.token} />
</GridItem>
<GridItem columnSpan={6}>
<VersionTotals version='a' accountId={ACCOUNT_ID} />
</GridItem>
<GridItem columnSpan={6}>
<VersionTotals version='b' accountId={ACCOUNT_ID} />
</GridItem>
<ChartGroup>
<GridItem columnSpan={6}>
<VersionPageViews version='a' />
</GridItem>
<GridItem columnSpan={6}>
<VersionPageViews version='b' />
</GridItem>
</ChartGroup>
<GridItem columnSpan={12}>
<EndTestSection
accountId={ACCOUNT_ID}
versionADescription={VERSION_A_DESCRIPTION}
versionBDescription={VERSION_B_DESCRIPTION}
/>
</GridItem>
<GridItem columnSpan={12}>
<PastTests accountId={ACCOUNT_ID} />
</GridItem>
<GridItem columnSpan={12}>
<ApiTokenButton showPrompt={this.showPrompt} />
</GridItem>
</Grid>
</div>
}
}

Dans total-cancellations.js, log le jeton à la console de votre navigateur :

import React from 'react';
import { HeadingText, PieChart } from 'nr1';
export default class TotalCancellations extends React.Component {
constructor() {
super(...arguments);
this.state = {
lastToken: null
}
}
componentDidUpdate() {
if (this.props.token && this.props.token != this.state.lastToken) {
console.log(`requesting data with api token ${this.props.token}`)
this.setState({lastToken: this.props.token})
}
}
render() {
const cancellationsA = {
metadata: {
id: 'cancellations-A',
name: 'Version A',
viz: 'main',
color: 'blue',
},
data: [
{ y: 118 },
],
}
const cancellationsB = {
metadata: {
id: 'cancellations-B',
name: 'Version B',
viz: 'main',
color: 'green',
},
data: [
{ y: 400 },
],
}
return <div>
<HeadingText className="chartHeader">
Total cancellations per version
</HeadingText>
<PieChart data={[cancellationsA, cancellationsB]} fullWidth />
</div>
}
}

Ici, vous avez implémenté une autre méthode de cycle de vie React, appelée componentDidUpdate(). Désormais, chaque fois que state.token de votre Nerdlet change, TotalCancellations obtient un nouveau jeton, ce qui déclenche componentDidUpdate(). Dans componentDidUpdate(), vous vérifiez que le jeton entrant n'est pas le même que le dernier jeton qu'il connaissait, qui est stocké dans l'état local. Si le jeton entrant est différent, vous enregistrez un message avec le nouveau jeton et mettez à jour state.lastToken.

Cette logique prépare votre code pour une modification future visant à utiliser votre jeton API dans une demande à un service tiers.

Avec votre Nerdpack servi localement, affichez votre application pour voir le log de TotalCancellations dans la console de votre navigateur. Si vous changez votre jeton, vous verrez un autre log de TotalCancellations avec votre jeton mis à jour.

Conseil

Si quelque chose ne fonctionne pas, utilisez les outils de débogage de votre navigateur pour essayer d'identifier le problème.

Assurez-vous de :

  • J'ai copié correctement le code de la leçon
  • Générer un nouvel UUID
  • Remplacé toutes les instances de <YOUR NEW RELIC ACCOUNT ID> dans votre projet par votre identifiant de compteNew Relic actuel

Une fois que vous avez terminé, arrêtez de diffuser votre application New Relic en appuyant sur CTRL+C dans la fenêtre de terminal de votre serveur local.

Vous savez maintenant comment utiliser NerdGraphQuery et NerdGraphMutation pour gérer les données dans NerdStorageVault! N'oubliez pas d'utiliser NerdStorage pour les données non sensibles de votre application New Relic et NerdStorageVault pour les éléments sensibles comme les jetons, les mots de passe et autres secrets. En bonus, vous avez créé un moyen de gérer votre jeton dans NerdStorageVault depuis l'interface utilisateur. Vous avez également transmis le jeton à votre composant TotalCancellations pour une utilisation ultérieure.

Que ce soit avec NrqlQuery, AccountStorageQuery, AccountStorageMutation, NerdGraphQuery ou NerdGraphMutation, vous avez appris plusieurs façons d'interagir avec les données New Relic dans votre application New Relic. Mais les applications New Relic ne sont pas simplement une autre façon d’afficher les données New Relic. L'objectif des applications New Relic est de vous montrer comment votre logiciel vous aide à atteindre vos objectifs commerciaux. Parfois, les données New Relic sont tout ce dont vous avez besoin pour y parvenir, mais d'autres fois, vous devez chercher au-delà de New Relic des données pour combler les lacunes.

Conseil

Cette leçon fait partie d’un cours qui vous apprend à créer une application New Relic à partir de zéro. Passez à la leçon suivante : Récupérer des données à partir d’un service tiers.

Droits d'auteur © 2025 New Relic Inc.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.