GraphQL: idiomatic way to accept an ordered list of sort parameters?

Viewed 213

I'm building a GraphQL API. I'm want to allow users to specify how records should be sorted, using multiple sorts.

What should be possible

If I expose the ability to sort monsters by name, birthdate, and id, users should be able to get the API to sort by any combination of those, including (in SQL terms):

  • ORDER BY name ASC
  • ORDER BY name ASC, birthdate DESC, id ASC
  • ... etc

What won't work

A single map, like this:

sorts: [{name: DESC, id: ASC}]

...would not tell me the order in which the sorts should be applied (maps are unordered).

What works OK, but isn't ideal

Currently, I accept a list of maps, like this:

sorts: [{name: DESC}, {id: ASC}]

Each map represents an input object, which has fields like name and id, which are enums with possible values ASC and DESC. I expect only one field to be filled per input object. ~But I don't know a way to enforce that.~

This is awkward because:

  • It would be easy for users to typo their sort parameters as a single map
  • I can't specify a default (like ASC for id) without having it added to every input object map

Is there a more idiomatic way of accepting an ordered list of sort parameters?


Update

I've now added a user-facing explanatory error when there is more than one key per map. With this change, I think this strategy is OK, but I'm still happy to hear of better ways in the future if they arise.

1 Answers

I think the short answer is "no".

Long answer: You can introspect your types at startup, and generate the schema dynamically according to some made-up convention using custom scalars to represent sorting directive, for example:

monsters(sortBy: [name___ASC, birthdate___DESC, id___ASC]) { name }

but this is also "just a convention". The "list of maps" ("array of objects") model that you listed a non-ideal might be the best option at this point:

# the query
monsters( 
  sortBy: [
    {name: asc},
    {birthdate: desc_nulls_last},
    {id: asc}
]
) {
  name
}

BUT, irrespective of which way you choose, avoid the temptation of starting hacking these things in manually - your server code will become convoluted due to this cross-cutting concern, as will your schema.

Instead, I have seen some GraphQL-to-ORM-bridging libraries make use of Directives to control the runtime schema generation (one example of this). That should be much more viable than hand-carving stuff like this.

Related