Your data. Anywhere you go.

New Relic for iOS or Android


Download on the App Store    Android App on Google play


New Relic Insights App for iOS


Download on the App Store


Learn more

Close icon

Is it possible to query the Insights API from a Nerdpack?


#1

Description
I’m developing a nerdpack to analyze users with session problems. First, I need a list of the users that use our website the most. But then, from those users I need to filter those with problems. I can identify them because they have to login too many times in a day.

The data is in Insights, in the UserEvent table. So I first need to query UserEvent to get a list of the users with the most events for one of our websites. Then I need to query for each user to get a list of how many login events has that user per day. If they login more than, say, 5 times in a day, that’s a problem.

So I thought that maybe I can just use the Insights API to get some json (instead of a NerdGraphQuery, because I don’t want to display the result of my first query). I have created an Insights Query Key and I have tested the query to the API using Postman and I get the expected results. But when I do the same query from the nerdpack (using fetch()) I get an error. I have tried using the parameter “mode: ‘cors’” (and also “mode: ‘no-cors’”), but I always get the same error:

Access to fetch at 'https://insights-api.newrelic.com/v1/accounts/ACCOUNT-ID/query?nrql=SOME-QUERY from origin 'https://0f5409a8-48da-47cd-95b4-0d788fcf8230.g0.nr-ext.net' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

So, is maybe the Insights API configured to not accept this kind of request and I’m screwed?


#2

Hey @dhernandez1

Have you tried out the <NrqlQuery> component?
https://developer.newrelic.com/client-side-sdk/index.html#data-fetching/NrqlQuery

In the example at that link, the data is being passed into a Line Chart, but you can perform manipulations on the data before charting as well.


#3

I didn’t know about that component, but it’s the same with <NerdGraphQuery>. What I don’t want is something like this:

<NerdGraphQuery query={someQuery}>
  {({loading, error, data}) => {
    // Some processing of data
    ...
  
    return (
      <>
        <NerdGraphQuery query={someQuery}>
          {({loading, error, data}) => {
            // Some more processing of data
            ...

            return <SomeComponent />;
          }}
        </NerdGraphQuery>
      </>
    );
   }}
</NerdGraphQuery>

Specially because that inner <NerdGraphQuery> would have to be inside a loop. That’s why I was trying to do all that data fetching and manipulation with fetch(). Also, some of the data fetched will be filtered out and not be displayed.


#4

Really interesting use case - and one that I’m not entirely sure on! Let me tag in @joelworrall & @dgolden - who are far greater experts in this area than I am. They may have some advice for you :slight_smile:


#5

@dhernandez1 if I understand your question, you’re trying to avoid nesting multiple queries for some reason. I’m going to presume that’s b/c you think the outer data set won’t (for your purposes) change as the user interacts with the data. (If I’m wrong in that fundamental assumption, let’s start over and talk it through).

But assuming I’m correct, you could use a React lifecycle method like componentDidMount to issue a declarative call to either a NrqlQuery or NerdGraphQuery component, store the results in the state, and hand that state to the render method for your secondary query.

For example:

async componentDidMount() {
    //see https://developer.newrelic.com/client-side-sdk/index.html#data-fetching/NrqlQuery
    const myResult = NrqlQuery.query({accountId: <my id>, query: "SELECT * from UserEvent SINCE 30 minutes AGO" });
    this.setState({myResult});
}

render() {
    const { myResult } . = this.state;
    if (!myResult) {
       return <Spinner />
    }
    // now I've got my data
    return <NerdGraphQuery ....
}

Does that help?


#6

Also, more directly, no. We didn’t design NR1 apps to query the Insights API. Instead, we gave you access to NRQL results through a bunch of data fetching components that also have a static/declarative method for execution.


#7

Ook, it’s a little tricky, but I can do my thing now. That NrqlQuery.query() gave me an idea and I tried to do the same with the <NerdGraphQuery>, but I get a really odd error: Invariant violation: 12 (I’ve been trying to look for the meaning of that cryptic error message but couldn’t find it). So I tried with the NrqlQuery and it works. The data comes in a weird format, but it’s usable, I can extract my data.

The problem with NRQL and Insights right now is that, as far as I know, it’s not possible to do JOINS in the queries, so when you need to combine data from different queries or tables, you need to be able to query Insights several times before displaying the data you really want to see.


#8

I can’t diagnose the invariant violation in this setting, but I can verify that the following code works, using the NerdGraphQuery static method and models the idea of using an initial query to feed a secondary query in the render. Maybe this is helpful.

import React from 'react';
import { Spinner, NerdGraphQuery } from 'nr1';
import { NerdGraphError } from '@newrelic/nr1-community';
import gql from "graphql-tag";
import get from 'lodash.get';
import camelCase from 'lodash.camelcase';

// https://docs.newrelic.com/docs/new-relic-programmable-platform-introduction

const accountId = 1606862; //replace with your accountId

export default class Nerdlet extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            outerResults: null
        }
    }

    async componentDidMount() {
        const outerResults = await NerdGraphQuery.query({ variables: { accountId }, query: gql`query($accountId: Int!) {
            actor {
              account(id: $accountId) {
                summary: nrql(query: "SELECT count(*) from Transaction FACET appName LIMIT 10") {
                  results
                }
              }
            }
          }`});
        console.log(outerResults);
        this.setState({ outerResults });
    }

    innerQuery() {
        const results = get(this.state, 'outerResults.data.actor.account.summary.results');
        //debugger;
        const query = `query($accountId: Int!) {
            actor {
                account(id: $accountId) {
                    ${results.map(row => {
                        console.log(row.appName);
                        const name = camelCase(row.appName);
                        return ` ${name}: nrql(query: "SELECT * from Transaction WHERE appName = '${row.appName}' LIMIT 10") {
                            results
                          } `;
                    }).join(" ")}
                }
            }
        }`;
        console.log(query);
        return query;
    }

    tableRow(summary, detailDataSet) {
        const { appName, count } = summary;
        const name = camelCase(appName);
        const rows = get(detailDataSet, `actor.account.${name}.results`);
    return <tr><td>{appName}</td><td>{count}</td><td>
        <ul>
            {rows.map(r => <li>${JSON.stringify(r)}</li>)}
        </ul>
        </td></tr>
    }

    render() {
        const { outerResults } = this.state;
        if (!outerResults) {
            return <Spinner fillContainer />
        }
        return <NerdGraphQuery query={this.innerQuery()} variables={{ accountId }}>
            {({ data, loading, error }) => {
               if (loading) {
                   return <Spinner fillContainer />
               }
               if (error) {
                   return <NerdGraphError error={error} />
               }
               //debugger;
               const summary = get(outerResults, 'data.actor.account.summary.results');
               console.log(data);
               return <table>
                   <thead>
                       <tr>
                           <th>Name</th>
                           <th>Count</th>
                           <th>Details</th>
                       </tr>
                   </thead>
                   <tbody>
                    {summary.map(s => {
                        return this.tableRow(s, data);
                    })}
                   </tbody>
               </table>
            }}
        </NerdGraphQuery>;
    }
}

#9

This is great and works like a charm. Thank you so much!


#10

Thanks so much for letting us know @dhernandez1


#11

Of course! You’re all doing a great job!