Okay, I'll say it. I love search. Let's just get that out of the way. I've done a lot of search implementations over the years and when I saw that Sitecore JSS now exposes the Content Search API via it's GraphQL endpoint, I knew I had to see what was possible to do with it.

What's available?

Keyword search is available with the keyword parameter. It's optional and we can leverage this to handle user input into a search box.

{
  search(keyword:"GraphQL") {
    results {
      totalCount
    }
  }
}

Faceting is possible as well with the facetOn parameter. We can pass in an array of fields we'd like to facet on to build some sidebar components that let users quickly refine their queries.

{
  search(facetOn:["categoryname"]) {
    facets {
      name
    }
  }
}

Pagination is also present in the API with two parameters, first and after. first is an integer and specifies how many results you would like back. after is the page cursor (or page offset). In the response we can select hasNextPage and hasPreviousPage which are really helpful when building simple back/next pagination on the search page.

{
  search(keyword:"Article") {
    results {
      pageInfo {
        endCursor,
      	hasNextPage,
        hasPreviousPage,
        startCursor
      }
    }
  }
}

The final important parameter we'll be using is fieldsEqual. We can pass this an object or an array of object with name and value properties. All of these properties get ANDed together when the query executes. We'll use this to filter our search results some and also pass in facet value filtering.

{
  search(fieldsEqual:[
    {name:"_fullpath", value:"/sitecore/content/home*" },
    {name:"categoryname", value:"Article" }
   ]) {
    results {
      items {
        name
      }
    }
  }
}

Some other parameters we won't be using but it's good to be aware of:

  • rootItem - Accepts a path or ID to limit our scope to. All results will be descendants of  this item.
  • language - Override the context language to filter by a specific language.
  • latestVersion - Default value for this is true. Will only return the latest versions of results (other versions will be filtered out.)
  • index - If you have a different / custom Content Search API index you'd like to query, you can pass in the name here.

Let's pause for a second

All of the parameters that I outlined are...

I think that's absolutely huge. I've spent time programming a lot of these features before. I've written that search manager class with a parameters class to wrap the ContentSearchManager. Now we get these features out of the box. Wild.

Now, about the search page.

Well, the code for the prototype page I built is up on GitHub here and it looks like this.

The page itself was built with React, querying using the parameters we outlined above. I didn't write a single line of back end code to build it out.

Our complete query for the initial page load looks like this:

{
  search(
    fieldsEqual:[{name:"_fullpath", value:"/sitecore/content/home*" }]
    	facetOn:["contenttype", "category"]
  		first: 5
  		after: "0") {
    facets {
      name
      values {
        value
        count
      }
    }
    results {
      items {
        item {
          name
          path
          url
        }
      }
      totalCount
      pageInfo {
        hasNextPage
        hasPreviousPage
      }
    }
  }
}

If a user selects a value from a facet, we pass in the selected facet values using fieldsEqual and will pass in an object that looks like this:

{name:"contenttype",value:"Article"}

Conclusion

I loved prototyping with this GraphQL endpoint and would consider using it in the future for an actual implementation. One thing that would hold me back from doing it is the lack of "or" operations for query conditions in fieldsEqual. The page I produced is functional and allowed me to implement all of the features I was hoping to out of the box.

I'll continue to refine the code in the GitHub repository so feel free to watch it if you're interested in seeing how it develops in the future.