# REST API: Filtering, Locale, and Publication State
The REST API offers the ability to filter results found with its "Get entries" method.
Using optional Strapi features can provide some more filters:
- If the Internationalization (i18n) plugin is enabled on a content-type, it's possible to filter by locale.
- If the Draft & Publish is enabled, it's possible to filter based on a liveordraftstate.
# Filtering
Queries can accept a filters parameter with the following syntax:
GET /api/:pluralApiId?filters[field][operator]=value
The following operators are available:
| Operator | Description | 
|---|---|
| $eq | Equal | 
| $ne | Not equal | 
| $lt | Less than | 
| $lte | Less than or equal to | 
| $gt | Greater than | 
| $gte | Greater than or equal to | 
| $in | Included in an array | 
| $notIn | Not included in an array | 
| $contains | Contains (case-sensitive) | 
| $notContains | Does not contain (case-sensitive) | 
| $containsi | Contains | 
| $notContainsi | Does not contain | 
| $null | Is null | 
| $notNull | Is not null | 
| $between | Is between | 
| $startsWith | Starts with | 
| $endsWith | Ends with | 
| $or | Joins the filters in an "or" expression | 
| $and | Joins the filters in an "and" expression | 
# Find users having 'John' as first name
Example request
const qs = require('qs');
const query = qs.stringify({
  filters: {
    username: {
      $eq: 'John',
    },
  },
}, {
  encodeValuesOnly: true,
});
await request(`/api/users?${query}`);
// GET /api/users?filters[username][$eq]=John
Example response
[
  {
    "id": 1,
    "username": "John",
    "email": "john@test.com",
    "provider": "local",
    "confirmed": true,
    "blocked": false,
    "createdAt": "2021-12-03T20:08:17.740Z",
    "updatedAt": "2021-12-03T20:08:17.740Z"
  }
]
# Find multiple restaurants with ids 3, 6, 8
Example request
const qs = require('qs');
const query = qs.stringify({
  filters: {
    id: {
      $in: [3, 6, 8],
    },
  },
}, {
  encodeValuesOnly: true, // prettify url
});
await request(`/api/restaurants?${query}`);
// GET /api/restaurants?filters[id][$in][0]=3&filters[id][$in][1]=6&filters[id][$in][2]=8
Example response
{
  "data": [
    {
      "id": 3,
      "attributes": {
        "name": "test3",
        // ...
      }
    },
    {
      "id": 6,
      "attributes": {
        "name": "test6",
        // ...
      }
    },
    {
      "id": 8,
      "attributes": {
        "name": "test8",
        // ...
      }
    }
  ],
  "meta": {
    // ...
  }
}
✋ CAUTION
By default, the filters can only be used from find endpoints generated by the Content-type Builder and the CLI.
# Complex filtering
Complex filtering is combining multiple filters utilizing advanced methods such as combining $and & $or. This allows for more flexibility to request exactly the data needed.
Example request: Find books with 2 possible dates & a specific author
const qs = require('qs');
const query = qs.stringify({
  filters: {
    $or: [
      {
        date: {
          $eq: '2020-01-01',
        },
      },
      {
        date: {
          $eq: '2020-01-02',
        },
      },
    ],
    author: {
      name: {
        $eq: 'Kai doe',
      },
    },
  },
}, {
  encodeValuesOnly: true,
});
await request(`/api/books?${query}`);
// GET /api/books?filters[$or][0][date][$eq]=2020-01-01&filters[$or][1][date][$eq]=2020-01-02&filters[author][name][$eq]=Kai%20doe
Example response
{
  "data": [
    {
      "id": 1,
      "attributes": {
        "name": "test1",
        "date": "2020-01-01",
        // ...
      }
    },
    {
      "id": 2,
      "attributes": {
        "name": "test2",
        "date": "2020-01-02",
        // ...
      }
    }
  ],
  "meta": {
    // ...
  }
}
# Deep filtering
Deep filtering is filtering on a relation's fields.
Example request: Find restaurants owned by a chef who belongs to a 5-star restaurant
const qs = require('qs');
const query = qs.stringify({
  filters: {
    chef: {
      restaurants: {
        stars: {
          $eq: 5,
        },
      },
    },
  },
}, {
  encodeValuesOnly: true,
});
await request(`/api/restaurants?${query}`);
// GET /api/restaurants?filters[chef][restaurants][stars][$eq]=5
Example response
{
  "data": [
    {
      "id": 1,
      "attributes": {
        "name": "GORDON RAMSAY STEAK",
        "stars": 5
        // ...
      }
    },
    {
      "id": 2,
      "attributes": {
        "name": "GORDON RAMSAY BURGER",
        "stars": 5
        // ...
      }
    }
  ],
  "meta": {
    // ...
  }
}
✋ CAUTION
- Querying your API with deep filters may cause performance issues. If one of your deep filtering queries is too slow, we recommend building a custom route with an optimized version of the query.
- Deep filtering isn't available for polymorphic relations (eg: Dynamic Zones & Media Fields).
✏️ NOTE
- Relations, media fields, components, and dynamic zones are not populated by default. Use the populateparameter to populate these data structures (see population documentation)
- It is not possible to filter on dynamic zones or media fields
# Locale
PREREQUISITES
- The Internationalization (i18n) plugin should be installed.
- Localization should be enabled for the content-type.
The locale API parameter can be used to get entries from a specific locale.
# Publication State
PREREQUISITES
The Draft & Publish feature should be enabled.
Queries can accept a publicationState parameter to fetch entries based on their publication state:
- live: returns only published entries (default)
- preview: returns both draft entries & published entries
Example request: Get both published and draft articles
const qs = require('qs');
const query = qs.stringify({
  publicationState: 'preview',
}, {
  encodeValuesOnly: true,
});
await request(`/api/articles?${query}`);
// GET /api/articles?publicationState=preview
Example response
{
  "data": [
    {
      "id": 1,
      "attributes": {
        "title": "This a Draft",
        "publishedAt": null
        // ...
      }
    },
    {
      "id": 2,
      "attributes": {
        "title": "This is Live",
        "publishedAt": "2021-12-03T20:08:17.740Z"
        // ...
      }
    }
  ],
  "meta": {
    // ...
  }
}
💡 TIP
To retrieve only draft entries, combine the preview publication state and the publishedAt fields:
GET /api/articles?publicationState=preview&filters[publishedAt][$null]=true
Example using qs
const qs = require('qs');
const query = qs.stringify({
  publicationState: 'preview',
  filters: {
    publishedAt: {
      $null: true,
    },
  },
}, {
  encodeValuesOnly: true,
});
await request(`/api/articles?${query}`);
// GET /api/articles?publicationState=preview&filters[publishedAt][$null]=true