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

Your first GraphQL API - Sorting

Similar to pagination, sorting is another complementary technical for loading large data set.

In this tutorial, we are going to implement sorting for our articles table.

Understanding GraphQL sorting mechanism

The mechanism behind sorting is much simpler comparing to pagination. We pass in a field and its order to the request and we get the results accordingly.

In most cases, sorting goes together with pagination and we are going to do the same for our example.

Implementing sorting

An imaginary sorting and pagination request would look like this:

{
   articlesConnection
   (
        first:2,
        sort:{
          field:id,
          order:ASC
        }
   )
   {
      edges {
        node {
          title
        }
        cursor
      }
      pageInfo {
        endCursor
        hasNextPage
      }
   }
}

The only additional code block is the sort parameter:

sort:{
    field:id,
    order:ASC
}

GraphQL Extensions provides reusable classes for sorting similar to pagination.

First step is to add available sort parameters to the ArticlesConnection field. To keep our tutorial simple, we will make "id" field available as the only sort parameter.

Modify build method of ArticlesConnection class:

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

We are using the SortingParamsType class from GraphQL Extensions to build the sorting parameter.

Next step is to make resolve method capable of sorting the results based on our request. Normally this method will delegate to the other service class from business layer, and the service class will sort 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 uasort.

Modify resolve method of ArticlesConnection class:

public function resolve($value, array $args, ResolveInfo $info)
{
    $result = ArticlesRepository::findAll();
 
    $result = $this->sortedResult($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;
}

Note the value of "DESC" is -1 and "ASC" is 1 from $args.

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\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'])]
        ));
    }
 
    public function resolve($value, array $args, ResolveInfo $info)
    {
        $result = ArticlesRepository::findAll();
 
        $result = $this->sortedResult($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;
    }
}

Lastly, we need to create a simple request to sort the result using id field:

Create a new file tutorial-sorting.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(first:2, sort: {field: id, order: ASC}){edges { node { id, title } cursor }, pageInfo { endCursor hasNextPage }} }'
);
 
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-sorting.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="
      ``},
      ``{
        ``"node":{
         ``"id":2,
         ``"title":"GraphQL History"
        ``},
        ``"cursor":"YXJyYXljb25uZWN0aW9uOjE="
      ``}
     ``],
     ``"pageInfo":{
      ``"endCursor":"YXJyYXljb25uZWN0aW9uOjE=",
      ``"hasNextPage":true
     ``}
   ``}
}

Try to change the order parameter's value(DESC or ASC) and see how GraphQL sorting reflects.

The End

Next tutorial, we will implement search feature. 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.