TailTemplate Build stunning websites faster with our pre-designed Tailwind CSS templates

Your first GraphQL API - Search

Search is another complementary technical when working with a large dataset. It takes an existing list, and removes items based on criteria that match/don't match.

In this tutorial, we are going to implement a search for our data table.

Understanding GraphQL searching mechanism

Search happens when we pass in a search parameter and it scans multiple fields behind the scene to get the data we want. We can use the same idea to implement filters, except that filters work in one single field.

Search can go together with pagination or alone. In our case, we are going to combine search and pagination.

Implementing searching

An imaginary searching request would look like this:

{
   articlesConnection
   (
        search: "First"
   )
   {
      edges {
        node {
          title
        }
        cursor
      }
   }
}

Note that we are using a generic "search" parameter for the query argument:

search: "First"

Since in a search request, we are trying to narrow down the result, there is no need to paginate the result.

Let's add "search" parameter to the ArticlesConnection field.

Modify build method of ArticlesConnection class:

public function build(FieldConfig $config)
{
    $this->addArguments(array_merge(
        Connection::connectionArgs(),
        ['sort' => new SortingParamsType(new ArticleType(), ['id'])],
        ['search' => new StringType()]
    ));
}

Next step is to make resolve method capable of searching the results based on our request. Normally this method will delegate to the other service class from business layer, and the service class will search the results with some sort of database calls. However, because our fake repository class simply returns a static array, we are going to sort with PHP array method array_filter.

Modify resolve method of ArticlesConnection class:

public function resolve($value, array $args, ResolveInfo $info)
{
    $result = ArticlesRepository::findAll();
 
    $result = $this->sortedResult($result, $args);
 
    $result = $this->searchResult($result, $args);
 
    return ArrayConnection::connectionFromArray($result, $args);
}
 
private function searchResult($result, array $args)
{
    if (!isset($args['search'])) {
        return $result;
    }
 
    return array_filter($result, function ($item) use ($args) {
        return strpos($item['title'], $args['search']) !== false;
    });
}

That is all the change we need for ArcilesConnection class and the final file should be as shown below:

<?php
namespace StarTutorial\Field;
 
 
use StarTutorial\Repository\ArticlesRepository;
use StarTutorial\Type\ArticleType;
use Youshido\GraphQL\Config\Field\FieldConfig;
use Youshido\GraphQL\Execution\ResolveInfo;
use Youshido\GraphQL\Field\AbstractField;
use Youshido\GraphQL\Relay\Connection\ArrayConnection;
use Youshido\GraphQL\Relay\Connection\Connection;
use Youshido\GraphQL\Type\Scalar\StringType;
use Youshido\GraphQLExtension\Type\CursorResultType;
use Youshido\GraphQLExtension\Type\Sorting\SortingParamsType;
 
class ArticlesConnection extends AbstractField
{
 
    public function getType()
    {
        return new CursorResultType(new ArticleType());
    }
 
    public function build(FieldConfig $config)
    {
        $this->addArguments(array_merge(
            Connection::connectionArgs(),
            ['sort' => new SortingParamsType(new ArticleType(), ['id'])],
            ['search' => new StringType()]
        ));
    }
 
    public function resolve($value, array $args, ResolveInfo $info)
    {
        $result = ArticlesRepository::findAll();
 
        $result = $this->sortedResult($result, $args);
 
        $result = $this->searchResult($result, $args);
 
        return ArrayConnection::connectionFromArray($result, $args);
    }
 
    private function sortedResult($result, array $args)
    {
        if (!isset($args['sort'])) {
            return $result;
        }
 
        $field = $args['sort']['field'];
 
        $order = $args['sort']['order'];
 
        uasort($result, function ($a, $b) use ($field, $order) {
            if (1 == $order) {
                return $a[$field] - $b[$field];
            }
            if (-1 == $order) {
                return $b[$field] - $a[$field];
            }
        });
 
        return $result;
    }
 
    private function searchResult($result, array $args)
    {
        if (!isset($args['search'])) {
            return $result;
        }
 
        return array_filter($result, function ($item) use ($args) {
            return strpos($item['title'], $args['search']) !== false;
        });
    }
}

Lastly, we need to create a simple request to search the result using "search" parameter:

Create a new file tutorial-search.php:

<?php
 
use StarTutorial\Field\ArticleField;
use StarTutorial\Field\ArticlesConnection;
use Youshido\GraphQL\Execution\Processor;
use Youshido\GraphQL\Schema\Schema;
use Youshido\GraphQL\Type\Object\ObjectType;
 
require_once 'vendor/autoload.php';
 
$processor = new Processor(new Schema([
    'query' => new ObjectType([
        'name' => 'RootQueryType',
        'fields' => [
            new ArticleField(),
            new ArticlesConnection()
        ]
    ]),
]));
 
$processor->processPayload(
    '{ articlesConnection(search: "First"){edges { node { id, title } cursor }} }'
);
 
echo '<pre>';
echo json_encode($processor->getResponseData()) . "\n";
echo '<pre>';

Access the page from the browser of your choice via the URL http://your-local-php-server/tutorial-search.php.

You should expect a JSON output as shown below if you have followed this tutorial correctly:

{
   "data":{
      "articlesConnection":{
         "edges":[
            {
               "node":{
                  "id":1,
                  "title":"My First GraphQL API"
               },
               "cursor":"YXJyYXljb25uZWN0aW9uOjA="
            }
         ]
      }
   }
}

Try to change the "search" parameter's value and see how GraphQL searching reflects.

The End

Next tutorial, we are going to show you how to implement nested queries in GraphQL and see how GraphQL loads data dynamically on the fly. If you like our post, please follow us on Twitter and help spread the word. We need your support to continue. If you have questions or find our mistakes in above tutorial, do leave a comment below to let us know.