The purpose of this lab is to build on the concepts we've already explored, using NerdGraph
and exploring the NerdGraph
components to access New Relic's NerdGraph
API within your Nerdlets.
After completing this lab you should:
- Be more confident in your ability to incorporate
NerdGraph
. - Gain more practical experience with nerdGraph
- Have access to the
NerdGraph
API from your Nerdlets
Load the prequisites and follow the setup instructions in Setup and Prequisites.
Reminder: Make sure that you're ready to go with your lab5
by ensuring you've run the following commands:
# if we're not in the lab5 directory get there
cd lab5
npm install
nr1 nerdpack:uuid -gf
npm start
Open https://one.newrelic.com?nerdpacks=local and click on the Lab 5 Launcher
.
- We need to import the appropriate libraries into our Nerdlet. Open
lab5/nerdlets/lab5-nerdlet/index.js
and add the following near the top of the file.
import { NerdGraphQuery, EntityByGuidQuery, EntitiesByNameQuery, EntitiesByDomainTypeQuery, EntityCountQuery, Spinner, Stack, StackItem, HeadingText, BlockText, NerdletStateContext } from 'nr1';
- The
NerdGraphQuery
component is going to allow us to access the New Relic NerdGraph API and have access to the power of GraphQL inside of your Nerdlet.
Let's update our render method in the index.js
to use the NerdGraphQuery
component and make our first NerdGraph query.
render() {
return (
<NerdGraphQuery query={`{actor {user {name email}}}`}>
{({loading, error, data}) => {
console.debug([loading, data, error]); //eslint-disable-line
return null
}}
</NerdGraphQuery>
)
}
- Save
index.js
and watch theNerdGraph Nerdlet
reload in your browser. - Ctrl+click (or right click) on the web browser screen displaying our Nerdlet and choose the menu item
Inspect
. - In the DevTools window now open, click on the
Console
tab at the top. - In the
Console
tab, choose theverbose
option on the left hand side. (It's in the drop-down next to the 'Filter' bar.) - Go back to the browser window and reload the current page, and then go back to the DevTools window. You should be looking at a screen like the following:
In your console, you should see an output matched the basic query you made using GraphiQL in lab4
The NerdGraphQuery
component returns set of data when making a query. The loading
, error
, and data
objects that are all accessible from a child function within the NerdGraphQuery
. Next we'll make some updated to our index.js
file to output our account list on the screen
- Update your import statement in the
index.js
files with the code below to add theSpinner
andBlockText
from thenr1
library:
import { NerdGraphQuery, EntityByGuidQuery, EntitiesByNameQuery, EntitiesByDomainTypeQuery, EntityCountQuery, Spinner, Stack, StackItem, HeadingText, BlockText, NerdletStateContext } from 'nr1';
- Above your render method, add the render helper fuctions from the code below:
_renderTable(data) {
const skipHeaders = ['__typename', 'id', 'tags', 'reporting', 'account', 'guid'];
const headings = Object.keys(data[0]).filter(k => !skipHeaders.includes(k));
return <table className="table">
<tbody>
<tr>
{headings.map((name, i) => <th key={i}>{name}</th>)}
</tr>
{data.length > 1 ? data.map((item, i) => {
return <tr key={i}>
{headings.map((name, j) => <td key={j} className="table-data">{item[name]}</td>)}
</tr>
}) : <tr>
{headings.map((name, j) => <td key={j} className="table-data">{data[0][name]}</td>)}
</tr>
}
</tbody>
</table>
}
- Update your render method in the
index.js
files with the code below:
render() {
return (<Stack fullWidth directionType={Stack.DIRECTION_TYPE.VERTICAL}>
<StackItem>
<div className="container">
<NerdGraphQuery query={`{actor {accounts {id name}}}`}>
{({loading, error, data}) => {
console.debug([loading, data, error]); //eslint-disable-line
if (loading) {
return <Spinner/>;
}
if (error) {
return <BlockText>{error.message}</BlockText>;
}
return <Fragment>
<HeadingText>Accounts</HeadingText>
{this._renderTable(data.actor.accounts)}
</Fragment>
}}
</NerdGraphQuery>
</div>
</StackItem>
</Stack>)
}
Go back to the browser window and reload the current page, you should see a list with names and ids for all of the accounts your user has access to. You should be looking at a screen like the following:
Using the NerdGraphQuery
allows you to access data from using any type of query to NerdGraph
, but for convenience, additional components are provided, with pre-defined Entity Queries
- To query data about the
entity
that we have currently selected we will use theEntityByGuidQuery
. Add a secondStackItem
just below the first in therender
method:
<StackItem className="container">
<NerdletStateContext.Consumer>
{(nerdletUrlState) => {
return <EntityByGuidQuery entityGuid={nerdletUrlState.entityGuid}>
{({ loading, error, data }) => {
console.debug([loading, data, error]); //eslint-disable-line
if (loading) {
return <Spinner />;
}
if (error) {
return <HeadingText>{error.message}</HeadingText>;
}
if (data.entities.length > 0) {
return <Fragment className="fragment">
<HeadingText>Entity by ID</HeadingText>
{this._renderTable(data.entities)}
</Fragment>
}
return null
}}
</EntityByGuidQuery>
}}
</NerdletStateContext.Consumer>
</StackItem>
In order to get this section to render, you're going to need to navigate to an APM service. First, navigate to Home. Then, select Explorer. From the left navigation, choose Services - APM, and then select a service.
And you should see the following.
Your browser should show a small table that displays the name and domain of your current entity
as a part of the data object that is returned from the EntityByGuidQuery
.
- To quickly search through your account entities by domain and type we will use the
EntitiesByDomainTypeQuery
, add the code below to yourrender
method under the lastStackItem
:
<StackItem className="container">
<EntitiesByDomainTypeQuery entityDomain="APM" entityType="APPLICATION">
{({loading, error, data}) => {
console.debug([loading, data, error]); //eslint-disable-line
if (loading) {
return <Spinner/>;
}
if (error) {
return <BlockText>{JSON.stringify(error)}</BlockText>;
}
return <Fragment>
<HeadingText>Entity by Domain Type</HeadingText>
{this._renderTable(data.entities)}
</Fragment>
}}
</EntitiesByDomainTypeQuery>
</StackItem>
- Save and go back to the browser window and reload the current page, you should another table that displays the name, domain, and type of the entities we've queried by domain
Your screen will look like the following:
- For a quick way to search for
entities
by name we will use theEntitiesByNameQuery
and pass thename
prop equal to "portal'. Add the code below to yourindex.js
file in therender
method under the lastStackItem
component.
Note: the state.entityName
defined in the constructor
is hardcoded to "Portal". You'll need to change that value to something relevant to your environment.
<StackItem className="container">
<EntitiesByNameQuery name={this.state.entityName}>
{({loading, error, data}) => {
console.debug([loading, data, error]); //eslint-disable-line
if (loading) {
return <Spinner/>;
}
if (error) {
return <BlockText>{JSON.stringify(error)}</BlockText>;
}
return <Fragment>
<HeadingText>Entity by Name</HeadingText>
{this._renderTable(data.entities)}
</Fragment>
}}
</EntitiesByNameQuery>
</StackItem>
- Save and go back to the browser window and reload the current page, you should see another table with all of the entities that match the name you queried. You should be looking at a screen like the following:
- Finally, using the
EntityCountQuey
you can quickly query the number of entities available for each entityDomain and entityType. Update yourindex.js
file, adding the code below to yourrender
method under the lastStackItem
.
<StackItem className="container">
<EntityCountQuery>
{({loading, error, data}) => {
console.debug([loading, data, error]); //eslint-disable-line
if (loading) {
return <Spinner/>;
}
if (error) {
return <BlockText>{JSON.stringify(error)}</BlockText>;
}
return <Fragment>
<HeadingText>Entity Count</HeadingText>
{this._renderTable(data.types)}
</Fragment>
}}
</EntityCountQuery>
</StackItem>
- Save and go back to the browser window and reload the current page, under the table for
EntityByNameQuery
you will see one more table. This new table should be displaying the data object from theEntityCountQuery
showing the number of entities available for each entityDomain and entityType.
You should be looking at a screen like the following:
In the end, your index.js
should look like this.
import React, { Fragment } from 'react';
import { NerdGraphQuery, EntityByGuidQuery, EntitiesByNameQuery, EntitiesByDomainTypeQuery, EntityCountQuery, Spinner, Stack, StackItem, HeadingText, BlockText, NerdletStateContext } from 'nr1';
export default class MyNerdlet extends React.Component {
constructor(props) {
super(props);
console.debug(props); //eslint-disable-line
this.state = {
entityName: "Portal"
};
}
_renderTable(data) {
const skipHeaders = ['__typename', 'id', 'tags', 'reporting', 'account', 'guid'];
const headings = Object.keys(data[0]).filter(k => !skipHeaders.includes(k));
return <table className="table">
<tbody>
<tr>
{headings.map((name, i) => <th key={i}>{name}</th>)}
</tr>
{data.length > 1 ? data.map((item, i) => {
return <tr key={i}>
{headings.map((name, j) => <td key={j} className="table-data">{item[name]}</td>)}
</tr>
}) : <tr>
{headings.map((name, j) => <td key={j} className="table-data">{data[0][name]}</td>)}
</tr>
}
</tbody>
</table>
}
render() {
return (<Stack fullWidth directionType={Stack.DIRECTION_TYPE.VERTICAL}>
<StackItem>
<div className="container">
<NerdGraphQuery query={`{actor {accounts {id name}}}`}>
{({ loading, error, data }) => {
console.debug([loading, data, error]); //eslint-disable-line
if (loading) {
return <Spinner />;
}
if (error) {
return <BlockText>{error.message}</BlockText>;
}
return <Fragment>
<HeadingText>Accounts</HeadingText>
{this._renderTable(data.actor.accounts)}
</Fragment>
}}
</NerdGraphQuery>
</div>
</StackItem>
<StackItem className="container">
<NerdletStateContext.Consumer>
{(nerdletUrlState) => {
return <EntityByGuidQuery entityGuid={nerdletUrlState.entityGuid}>
{({ loading, error, data }) => {
console.debug([loading, data, error]); //eslint-disable-line
if (loading) {
return <Spinner />;
}
if (error) {
return <HeadingText>{error.message}</HeadingText>;
}
return <Fragment className="fragment">
<HeadingText>Entity by ID</HeadingText>
{this._renderTable(data.entities)}
</Fragment>
}}
</EntityByGuidQuery>
}}
</NerdletStateContext.Consumer>
</StackItem>
<StackItem className="container">
<EntitiesByDomainTypeQuery entityDomain="APM" entityType="APPLICATION">
{({ loading, error, data }) => {
console.debug([loading, data, error]); //eslint-disable-line
if (loading) {
return <Spinner />;
}
if (error) {
return <BlockText>{JSON.stringify(error)}</BlockText>;
}
return <Fragment>
<HeadingText>Entity by Domain Type</HeadingText>
{this._renderTable(data.entities)}
</Fragment>
}}
</EntitiesByDomainTypeQuery>
</StackItem>
<StackItem className="container">
<EntitiesByNameQuery name={this.state.entityName}>
{({ loading, error, data }) => {
console.debug([loading, data, error]); //eslint-disable-line
if (loading) {
return <Spinner />;
}
if (error) {
return <BlockText>{JSON.stringify(error)}</BlockText>;
}
return <Fragment>
<HeadingText>Entity by Name</HeadingText>
{this._renderTable(data.entities)}
</Fragment>
}}
</EntitiesByNameQuery>
</StackItem>
<StackItem className="container">
<EntityCountQuery>
{({ loading, error, data }) => {
console.debug([loading, data, error]); //eslint-disable-line
if (loading) {
return <Spinner />;
}
if (error) {
return <BlockText>{JSON.stringify(error)}</BlockText>;
}
return <Fragment>
<HeadingText>Entity Count</HeadingText>
{this._renderTable(data.types)}
</Fragment>
}}
</EntityCountQuery>
</StackItem>
</Stack>)
}
}