GraphQL, Practically Speaking: Exploring the State of JavaScript API

GraphQL often gets framed as a challenging technology to master, but consuming an existing GraphQL API is a much quicker win. The State of JavaScript team has made this particularly easy by exposing the very API that powers its annual survey site—and the queries that built it—for anyone to experiment with. The 2019 edition of the survey gathered responses from over 20,000 developers, and all that data is now queryable at api.stateofjs.com/graphql.

The project previously used static YAML files, generated from ElasticSearch, to feed its Gatsby-based showcase site. Since Gatsby ultimately exposes all its data sources as GraphQL, the team decided to cut out the intermediate file generation step and query the data directly via a dedicated GraphQL API—one they're now opening up to the public.

What GraphQL Actually Does

GraphQL is a syntax for requesting data from an API, not a database query language in the SQL sense. Your query goes to an API endpoint, which then fetches data from whatever backend it uses. Its key advantage over REST is that the client gets to specify exactly which fields it needs, and those fields can be nested arbitrarily:

query {
  user(id: "foo123") {
    name
  }
}

That returns a user object containing only the name field. Need the email too? Add the field to the same query:

query {
  user(id: "foo123") {
    name
    email
  }
}

Observe that user accepts an id argument. The real power comes with nesting:

query {
  user(id: "foo123") {
    name
    email
    posts { 
      title
      body
    }
  }
}

This asks the API to resolve the user's posts and return their title and body fields. The API layer handles the behind-the-scenes work of fetching that nested data in the requested shape, regardless of how the data is actually organized in the underlying store.

A Guided Tour of GraphiQL

GraphiQL is the standard interactive IDE for exploring GraphQL endpoints, and the State of JavaScript deployment—at graphiql.stateofjs.com—connects automatically to the live API. The interface has three main sections: an Explorer panel (for browsing the schema), the Query Builder (where you write or paste queries), and the Results panel.

Building our first query with GraphiQL, the IDE for GraphQL

The Explorer here is actually a customized, enhanced version of GraphiQL developed by OneGraph, which the State of JavaScript team integrated into their setup. If you want your own instance, their example repository shows how to deploy it.

You don't need to write any code from scratch to get started. Since the site is built on this API, the project also exposes the queries it uses. Visit any chart on the 2019 site—say, React experience over four years—click its "Export" button, switch to the "GraphQL" tab, copy the query, and paste it into the Query Builder. Hit "Play" and the data appears in the Results panel.

Source URL
The GraphQL tab in the modal that triggers when clicking Export.

Dissecting that query shows the structure clearly:

query react_experienceQuery {
  survey(survey: js) {
    tool(id: react) {
      id
      entity {
        homepage
        name
        github {
          url
        }
      }
      experience {
        allYears {
          year
          total
          completion {
            count
            percentage
          }
          awarenessInterestSatisfaction {
            awareness
            interest
            satisfaction
          }
          buckets {
            id
            count
            percentage
          }
        }
      }
    }
  }
}

The query keyword begins the operation, and react_experienceQuery gives it a name (optional, but handy for debugging). Then the query drills down: survey takes a survey argument to distinguish the JavaScript survey from the State of CSS's; tool takes an id argument to pick a specific library. From there, entity yields descriptive information about the chosen tool, while experience holds its actual statistics.

One more trick for deciphering unfamiliar queries: Command+click (or Control+click) any field inside GraphiQL to summon the Docs panel. The API is self-documenting because the server exposes descriptions written into its schema definition, falling into GraphiQL's built-in documentation viewer.

Achieving the Same Result with the Explorer

The Explorer tree is a full visualization of the API's schema. If you open a fresh GraphiQL tab, you can rebuild the React query without typing a line. Click survey, then its tool node, and press Play. The tool's id field is added automatically to the query, which is the right moment to change the default argument from typescript to react.

entity, if added without subfields, shows a red squiggle because it requires at least one child field. Add id, name, and homepage. A fast way to scaffold everything is to option+control+click a field in the Explorer, which auto-selects every subfield it offers. Do the same under experience, and the Query Builder repopulates itself to match the exported query you pasted earlier.

It's as easy to customize as it is to recreate default queries: swap react for vuejs in the Query Builder, and thanks to autocomplete suggestions, an exact replacement is trivial.

Filtering Aggregations

Where the API goes beyond what the website provides is in slicing its aggregate data. Under experience, a purple filters node exposes arguments that restrict which respondents' answers go into the aggregation. Expanding filters reveals companySize with options like eq for equality. Selecting eq and range_more_than_1000 gives React's popularity among developers at large companies; switching to range_1 yields the same metric for freelancers and independents.

Notably, filters such as eq, in, and nin are not GraphQL standards. GraphQL only offers the low-level primitives of fields and arguments. These filter arguments are custom additions designed by the State of JavaScript team while building the API.

API Field Glossary

The full API documentation, including endpoint addresses and its GitHub repository, lives at api.stateofjs.com. A quick rundown of the main fields any query can target:

  • Demographics: Aggregated respondent background data (gender, company size, salary).
  • Entity: Descriptive details for a specific library, framework, or language.
  • Feature: Usage numbers for an individual JavaScript or CSS feature.
  • Features: The same across a set of features.
  • Matrices: The cross-referential data powering the site's heatmaps.
  • Opinion: Attitudinal responses to specific survey questions.
  • OtherTools: Data for text editors, browsers, bundlers, and related categories.
  • Resources: Data for the sites, blogs, and podcasts section.
  • Tool: Usage and experience stats for a single tool.
  • Tools: The same across multiple tools.
  • ToolsRankings: Awareness, interest, and satisfaction rankings across tools.

Several field groups also share common subfields worth knowing:

  • Completion: The fraction of all respondents who answered a given question.
  • Buckets: The array that holds the numerical data points.
  • Year/allYears: Pick one survey year's results or an array spanning them all.

Querying a GraphQL API is, in the end, not a monumental task—and tools like GraphiQL make the first steps positively gentle. The language itself is simple; the complexity of a GraphQL project typically lurks in application-level data transport, not in writing the queries.