Filtering

FastAPI-JSONAPI has a very flexible filtering system. The filtering system is directly attached to the data layer used by the ResourceList manager. These examples show the filtering interface for SQLAlchemy’s data layer but you can use the same interface for your custom data layer’s filtering implementation as well. The only requirement is that you have to use the “filter” query string parameter to filter according to the JSON:API 1.0 specification.

Note

Examples are not urlencoded for a better readability

SQLAlchemy

The filtering system of SQLAlchemy’s data layer has exactly the same interface as the one used in Flask-Restless. So this is a first example:

GET /users?filter=[{"name":"first_name","op":"eq","val":"John"}] HTTP/1.1
Accept: application/vnd.api+json

In this example we want to retrieve user records for people named John. So we can see that the filtering interface completely fits that of SQLAlchemy: a list a filter information.

name:

the name of the field you want to filter on

op:

the operation you want to use (all SQLAlchemy operations are available)

val:

the value that you want to compare. You can replace this by “field” if you want to compare against the value of another field

Example with field:

GET /users?filter=[{"name":"first_name","op":"eq","field":"birth_date"}] HTTP/1.1
Accept: application/vnd.api+json

In this example, we want to retrieve people whose name is equal to their birth_date. This example is absurd, it’s just here to explain the syntax of this kind of filter.

If you want to filter through relationships you can do that:

[
  {
    "name": "group",
    "op": "any",
    "val": {
      "name": "name",
      "op": "ilike",
      "val": "%admin%"
    }
  }
]
GET [{"name":"group","op":"any","val":{"name":"name","op":"ilike","val":"%admin%"}}] HTTP/1.1
Accept: application/vnd.api+json

Note

When you filter on relationships use the “any” operator for “to many” relationships and the “has” operator for “to one” relationships.

There is a shortcut to achieve the same filtering:

GET /users?filter=[{"name":"group.name","op":"ilike","val":"%admin%"}] HTTP/1.1
Accept: application/vnd.api+json

You can also use boolean combination of operations:

[
  {
    "name":"group.name",
    "op":"ilike",
    "val":"%admin%"
  },
  {
    "or": [
      {
        "not": {
          "name": "first_name",
          "op": "eq",
          "val": "John"
        }
      },
      {
        "and": [
          {
            "name": "first_name",
            "op": "like",
            "val": "%Jim%"
          },
          {
            "name": "date_create",
            "op": "gt",
            "val": "1990-01-01"
          }
        ]
      }
    ]
  }
]
GET /users?filter=[{"name":"group.name","op":"ilike","val":"%admin%"},{"or":[{"not":{"name":"first_name","op":"eq","val":"John"}},{"and":[{"name":"first_name","op":"like","val":"%Jim%"},{"name":"date_create","op":"gt","val":"1990-01-01"}]}]}] HTTP/1.1
Accept: application/vnd.api+json

Filtering records by a field that is null

GET /users?filter=[{"name":"name","op":"is_","val":null}] HTTP/1.1
Accept: application/vnd.api+json

Filtering records by a field that is not null

GET /users?filter=[{"name":"name","op":"isnot","val":null}] HTTP/1.1
Accept: application/vnd.api+json

Common available operators:

  • any: used to filter on “to many” relationships

  • between: used to filter a field between two values

  • endswith: checks if field ends with a string

  • eq: checks if field is equal to something

  • ge: checks if field is greater than or equal to something

  • gt: checks if field is greater than something

  • has: used to filter on “to one” relationships

  • ilike: checks if field contains a string (case insensitive)

  • in_: checks if field is in a list of values

  • is_: checks if field is a value

  • isnot: checks if field is not a value

  • like: checks if field contains a string

  • le: checks if field is less than or equal to something

  • lt: checks if field is less than something

  • match: checks if field matches against a string or pattern

  • ne: checks if field is not equal to something

  • notilike: checks if field does not contain a string (case insensitive)

  • notin_: checks if field is not in a list of values

  • notlike: checks if field does not contain a string

  • startswith: checks if field starts with a string

Note

Available operators depend on the field type in your model

Simple filters

Simple filters add support for a simplified form of filters and support only the eq operator. Each simple filter is transformed into a full filter and appended to the list of filters.

For example

GET /users?filter[first_name]=John HTTP/1.1
Accept: application/vnd.api+json

equals:

GET /users?filter=[{"name":"first_name","op":"eq","val":"John"}] HTTP/1.1
Accept: application/vnd.api+json

You can also use more than one simple filter in a request:

GET /users?filter[first_name]=John&filter[gender]=male HTTP/1.1
Accept: application/vnd.api+json

which is equal to:

[
   {
      "name":"first_name",
      "op":"eq",
      "val":"John"
   },
   {
      "name":"gender",
      "op":"eq",
      "val":"male"
   }
]
GET /users?filter=[{"name":"first_name","op":"eq","val":"John"},{"name":"gender","op":"eq","val":"male"}] HTTP/1.1

You can also use relationship attribute in a request:

GET /users?filter[group_id]=1 HTTP/1.1
Accept: application/vnd.api+json

which is equal to:

GET /users?filter=[{"name":"group.id","op":"eq","val":"1"}] HTTP/1.1