Content API

API Endpoints

When you create a Content Type you will have a certain number of REST API endpoints available to interact with it.

WARNING

Components don’t have API endpoints

As an example, let’s consider the following models:

Content Types:

  • Restaurant (Collection Type)
  • Homepage (Single Type)

Components:

  • Opening hours (category: restaurant)
  • Title With Subtitle (category: content)
  • Image With Description (category: content)

Restaurant Content Type

FieldsTypeDescriptionOptions
namestringRestaurant’s title
sluguidRestaurant’s slugtargetField=”name”
covermediaRestaurant’s cover image
contentdynamiczoneThe restaurant profile content
opening_hourscomponentRestaurant’s opening hours componentrepeatable

Homepage Content Type

FieldsTypeDescriptionOptions
titlestringHomepage title
subTitlestringHomepage sub title
contentdynamiczoneHomepage content

Opening hours Component

FieldsTypeDescription
day_intervalstringMeta’s day interval
opening_hourstringMeta’s opening hour
closing_hourstringMeta’s closing hour

Title With Subtitle Component

FieldsTypeDescription
titlestringThe title
subTitlestringThe sub title

Image With Description Component

FieldsTypeDescription
imagemediaThe image file
titlestringThe image title
descriptiontextThe image description

Endpoints

Here is the list of endpoints generated for each of your Content Types.

MethodPathDescription
GET/{content-type}Get a list of {content-type} entries
GET/{content-type}/:idGet a specific {content-type} entry
GET/{content-type}/countCount {content-type} entries
POST/{content-type}Create a {content-type} entry
DELETE/{content-type}/:idDelete a {content-type} entry
PUT/{content-type}/:idUpdate a {content-type} entry
MethodPathDescription
GET/{content-type}Get the {content-type} content
PUT/{content-type}Update the {content-type} content
DELETE/{content-type}Delete the {content-type} content

Examples

Here are some Content Type examples

Single Types

Homepage Content Type

MethodPathDescription
GET/homepageGet the homepage content
PUT/homepageUpdate the homepage content
DELETE/homepageDelete the homepage content

Contact Content Type

MethodPathDescription
GET/contactGet the contact content
PUT/contactUpdate the contact content
DELETE/contactDelete the contact content
Collection Types

Restaurant Content Type

MethodPathDescription
GET/restaurantsGet a list of restaurants
GET/restaurants/:idGet a specific restaurant
GET/restaurants/countCount restaurants
POST/restaurantsCreate a restaurant
DELETE/restaurants/:idDelete a restaurant
PUT/restaurants/:idUpdate a restaurant

Article Content Type

MethodPathDescription
GET/articlesGet a list of articles
GET/articles/:idGet a specific article
GET/articles/countCount articles
POST/articlesCreate a article
DELETE/articles/:idDelete a article
PUT/articles/:idUpdate a article

Product Content Type

MethodPathDescription
GET/productsGet a list of products
GET/products/:idGet a specific product
GET/products/countCount products
POST/productsCreate a product
DELETE/products/:idDelete a product
PUT/products/:idUpdate a product

Category Content Type

MethodPathDescription
GET/categoriesGet a list of categories
GET/categories/:idGet a specific category
GET/categories/countCount categories
POST/categoriesCreate a category
DELETE/categories/:idDelete a category
PUT/categories/:idUpdate a category

Tag Content Type

MethodPathDescription
GET/tagsGet a list of tags
GET/tags/:idGet a specific tag
GET/tags/countCount tags
POST/tagsCreate a tag
DELETE/tags/:idDelete a tag
PUT/tags/:idUpdate a tag

Get entries

Returns entries matching the query filters. You can read more about parameters here.

Example request

  1. GET http://localhost:1337/restaurants

Example response

  1. [
  2. {
  3. "id": 1,
  4. "name": "Restaurant 1",
  5. "cover": {
  6. "id": 1,
  7. "name": "image.png",
  8. "hash": "123456712DHZAUD81UDZQDAZ",
  9. "sha256": "v",
  10. "ext": ".png",
  11. "mime": "image/png",
  12. "size": 122.95,
  13. "url": "http://localhost:1337/uploads/123456712DHZAUD81UDZQDAZ.png",
  14. "provider": "local",
  15. "provider_metadata": null,
  16. "created_at": "2019-12-09T00:00:00.000Z",
  17. "updated_at": "2019-12-09T00:00:00.000Z"
  18. },
  19. "content": [
  20. {
  21. "__component": "content.title-with-subtitle",
  22. "id": 1,
  23. "title": "Restaurant 1 title",
  24. "subTitle": "Cozy restaurant in the valley"
  25. },
  26. {
  27. "__component": "content.image-with-description",
  28. "id": 1,
  29. "image": {
  30. "id": 1,
  31. "name": "image.png",
  32. "hash": "123456712DHZAUD81UDZQDAZ",
  33. "sha256": "v",
  34. "ext": ".png",
  35. "mime": "image/png",
  36. "size": 122.95,
  37. "url": "http://localhost:1337/uploads/123456712DHZAUD81UDZQDAZ.png",
  38. "provider": "local",
  39. "provider_metadata": null,
  40. "created_at": "2019-12-09T00:00:00.000Z",
  41. "updated_at": "2019-12-09T00:00:00.000Z"
  42. },
  43. "title": "Amazing photography",
  44. "description": "This is an amazing photography taken..."
  45. }
  46. ],
  47. "opening_hours": [
  48. {
  49. "id": 1,
  50. "day_interval": "Tue - Sat",
  51. "opening_hour": "7:30 PM",
  52. "closing_hour": "10:00 PM"
  53. }
  54. ]
  55. }
  56. ]

Get an entry

Returns an entry by id.

Example request

  1. GET http://localhost:1337/restaurants/1

Example response

  1. {
  2. "id": 1,
  3. "title": "Restaurant 1",
  4. "cover": {
  5. "id": 1,
  6. "name": "image.png",
  7. "hash": "123456712DHZAUD81UDZQDAZ",
  8. "sha256": "v",
  9. "ext": ".png",
  10. "mime": "image/png",
  11. "size": 122.95,
  12. "url": "http://localhost:1337/uploads/123456712DHZAUD81UDZQDAZ.png",
  13. "provider": "local",
  14. "provider_metadata": null,
  15. "created_at": "2019-12-09T00:00:00.000Z",
  16. "updated_at": "2019-12-09T00:00:00.000Z"
  17. },
  18. "content": [
  19. {
  20. "__component": "content.title-with-subtitle",
  21. "id": 1,
  22. "title": "Restaurant 1 title",
  23. "subTitle": "Cozy restaurant in the valley"
  24. },
  25. {
  26. "__component": "content.image-with-description",
  27. "id": 1,
  28. "image": {
  29. "id": 1,
  30. "name": "image.png",
  31. "hash": "123456712DHZAUD81UDZQDAZ",
  32. "sha256": "v",
  33. "ext": ".png",
  34. "mime": "image/png",
  35. "size": 122.95,
  36. "url": "http://localhost:1337/uploads/123456712DHZAUD81UDZQDAZ.png",
  37. "provider": "local",
  38. "provider_metadata": null,
  39. "created_at": "2019-12-09T00:00:00.000Z",
  40. "updated_at": "2019-12-09T00:00:00.000Z"
  41. },
  42. "title": "Amazing photography",
  43. "description": "This is an amazing photography taken..."
  44. }
  45. ],
  46. "opening_hours": [
  47. {
  48. "id": 1,
  49. "day_interval": "Tue - Sat",
  50. "opening_hour": "7:30 PM",
  51. "closing_hour": "10:00 PM"
  52. }
  53. ]
  54. }

Count entries

Returns the count of entries matching the query filters. You can read more about parameters here.

Example request

  1. GET http://localhost:1337/restaurants/count

Example response

  1. 1

Create an entry

Creates an entry and returns its value.

Example request

  1. POST http://localhost:1337/restaurants
  1. {
  2. "title": "Restaurant 1",
  3. "cover": 1,
  4. "content": [
  5. {
  6. "__component": "content.title-with-subtitle",
  7. "title": "Restaurant 1 title",
  8. "subTitle": "Cozy restaurant in the valley"
  9. },
  10. {
  11. "__component": "content.image-with-description",
  12. "image": 1, // user form data to upload the file or an id to reference an exisiting image
  13. "title": "Amazing photography",
  14. "description": "This is an amazing photography taken..."
  15. }
  16. ],
  17. "opening_hours": [
  18. {
  19. "day_interval": "Tue - Sat",
  20. "opening_hour": "7:30 PM",
  21. "closing_hour": "10:00 PM"
  22. }
  23. ]
  24. }

Example response

  1. {
  2. "id": 1,
  3. "title": "restaurant 1",
  4. "cover": {
  5. "id": 1,
  6. "name": "image.png",
  7. "hash": "123456712DHZAUD81UDZQDAZ",
  8. "sha256": "v",
  9. "ext": ".png",
  10. "mime": "image/png",
  11. "size": 122.95,
  12. "url": "http://localhost:1337/uploads/123456712DHZAUD81UDZQDAZ.png",
  13. "provider": "local",
  14. "provider_metadata": null,
  15. "created_at": "2019-12-09T00:00:00.000Z",
  16. "updated_at": "2019-12-09T00:00:00.000Z"
  17. },
  18. "content": [
  19. {
  20. "__component": "content.title-with-subtitle",
  21. "id": 1,
  22. "title": "Restaurant 1 title",
  23. "subTitle": "Cozy restaurant in the valley"
  24. },
  25. {
  26. "__component": "content.image-with-description",
  27. "id": 1,
  28. "image": {
  29. "id": 1,
  30. "name": "image.png",
  31. "hash": "123456712DHZAUD81UDZQDAZ",
  32. "sha256": "v",
  33. "ext": ".png",
  34. "mime": "image/png",
  35. "size": 122.95,
  36. "url": "http://localhost:1337/uploads/123456712DHZAUD81UDZQDAZ.png",
  37. "provider": "local",
  38. "provider_metadata": null,
  39. "created_at": "2019-12-09T00:00:00.000Z",
  40. "updated_at": "2019-12-09T00:00:00.000Z"
  41. },
  42. "title": "Amazing photography",
  43. "description": "This is an amazing photography taken..."
  44. }
  45. ],
  46. "opening_hours": [
  47. {
  48. "id": 1,
  49. "day_interval": "Tue - Sat",
  50. "opening_hour": "7:30 PM",
  51. "closing_hour": "10:00 PM"
  52. }
  53. ]
  54. }

Update an entry

Partially updates an entry by id and returns its value. Fields that aren’t sent in the query are not changed in the db. Send a null value if you want to clear them.

Example request

  1. PUT http://localhost:1337/restaurants/1
  1. {
  2. "title": "Restaurant 1",
  3. "content": [
  4. {
  5. "__component": "content.title-with-subtitle",
  6. // editing one of the previous item by passing its id
  7. "id": 2,
  8. "title": "Restaurant 1 title",
  9. "subTitle": "Cozy restaurant in the valley"
  10. },
  11. {
  12. "__component": "content.image-with-description",
  13. "image": 1, // user form data to upload the file or an id to reference an exisiting image
  14. "title": "Amazing photography",
  15. "description": "This is an amazing photography taken..."
  16. }
  17. ],
  18. "opening_hours": [
  19. {
  20. // adding a new item
  21. "day_interval": "Sun",
  22. "opening_hour": "7:30 PM",
  23. "closing_hour": "10:00 PM"
  24. },
  25. {
  26. // editing one of the previous item by passing its id
  27. "id": 1,
  28. "day_interval": "Mon - Sat",
  29. "opening_hour": "7:30 PM",
  30. "closing_hour": "10:00 PM"
  31. }
  32. ]
  33. }

Example response

  1. {
  2. "id": 1,
  3. "title": "Restaurant 1",
  4. "cover": {
  5. "id": 1,
  6. "name": "image.png",
  7. "hash": "123456712DHZAUD81UDZQDAZ",
  8. "sha256": "v",
  9. "ext": ".png",
  10. "mime": "image/png",
  11. "size": 122.95,
  12. "url": "http://localhost:1337/uploads/123456712DHZAUD81UDZQDAZ.png",
  13. "provider": "local",
  14. "provider_metadata": null,
  15. "created_at": "2019-12-09T00:00:00.000Z",
  16. "updated_at": "2019-12-09T00:00:00.000Z"
  17. },
  18. "content": [
  19. {
  20. "__component": "content.title-with-subtitle",
  21. "id": 1,
  22. "title": "Restaurant 1 title",
  23. "subTitle": "Cozy restaurant in the valley"
  24. },
  25. {
  26. "__component": "content.image-with-description",
  27. "id": 2,
  28. "image": {
  29. "id": 1,
  30. "name": "image.png",
  31. "hash": "123456712DHZAUD81UDZQDAZ",
  32. "sha256": "v",
  33. "ext": ".png",
  34. "mime": "image/png",
  35. "size": 122.95,
  36. "url": "http://localhost:1337/uploads/123456712DHZAUD81UDZQDAZ.png",
  37. "provider": "local",
  38. "provider_metadata": null,
  39. "created_at": "2019-12-09T00:00:00.000Z",
  40. "updated_at": "2019-12-09T00:00:00.000Z"
  41. },
  42. "title": "Amazing photography",
  43. "description": "This is an amazing photography taken..."
  44. }
  45. ],
  46. "opening_hours": [
  47. {
  48. "id": 1,
  49. "day_interval": "Mon - Sat",
  50. "opening_hour": "7:30 PM",
  51. "closing_hour": "10:00 PM"
  52. },
  53. {
  54. "id": 2,
  55. "day_interval": "Sun",
  56. "opening_hour": "7:30 PM",
  57. "closing_hour": "10:00 PM"
  58. }
  59. ]
  60. }

Delete an entry

Deletes an entry by id and returns its value.

Example request

  1. DELETE http://localhost:1337/restaurants/1

Example response

  1. {
  2. "id": 1,
  3. "title": "Restaurant 1",
  4. "cover": {
  5. "id": 1,
  6. "name": "image.png",
  7. "hash": "123456712DHZAUD81UDZQDAZ",
  8. "sha256": "v",
  9. "ext": ".png",
  10. "mime": "image/png",
  11. "size": 122.95,
  12. "url": "http://localhost:1337/uploads/123456712DHZAUD81UDZQDAZ.png",
  13. "provider": "local",
  14. "provider_metadata": null,
  15. "created_at": "2019-12-09T00:00:00.000Z",
  16. "updated_at": "2019-12-09T00:00:00.000Z"
  17. },
  18. "content": [
  19. {
  20. "__component": "content.title-with-subtitle",
  21. "id": 1,
  22. "title": "Restaurant 1 title",
  23. "subTitle": "Cozy restaurant in the valley"
  24. },
  25. {
  26. "__component": "content.image-with-description",
  27. "id": 2,
  28. "image": {
  29. "id": 1,
  30. "name": "image.png",
  31. "hash": "123456712DHZAUD81UDZQDAZ",
  32. "sha256": "v",
  33. "ext": ".png",
  34. "mime": "image/png",
  35. "size": 122.95,
  36. "url": "http://localhost:1337/uploads/123456712DHZAUD81UDZQDAZ.png",
  37. "provider": "local",
  38. "provider_metadata": null,
  39. "created_at": "2019-12-09T00:00:00.000Z",
  40. "updated_at": "2019-12-09T00:00:00.000Z"
  41. },
  42. "title": "Amazing photography",
  43. "description": "This is an amazing photography taken..."
  44. }
  45. ],
  46. "opening_hours": [
  47. {
  48. "id": 1,
  49. "day_interval": "Mon - Sat",
  50. "opening_hour": "7:30 PM",
  51. "closing_hour": "10:00 PM"
  52. },
  53. {
  54. "id": 2,
  55. "day_interval": "Sun",
  56. "opening_hour": "7:30 PM",
  57. "closing_hour": "10:00 PM"
  58. }
  59. ]
  60. }

API Parameters

WARNING

By default, the filters can only be used from find and count endpoints generated by the Content Type Builder and the CLI.

Available operators

The available operators are separated in five different categories:

Filters

When using filters you can either pass simple filters in the root of the query parameters or pass them in a _where parameter.

Filters are used as a suffix of a field name:

FilterDescription
No suffix or eqEqual
neNot equal
ltLess than
gtGreater than
lteLess than or equal to
gteGreater than or equal to
inIncluded in an array
ninNot included in an array
containsContains
ncontainsDoesn’t contain
containssContains, case sensitive
ncontainssDoesn’t contain, case sensitive
nullIs null or not null

Examples

Find users having John as first name.

GET /users?firstName=John or GET /users?firstName_eq=John

Find restaurants having a price equal or greater than 3.

GET /restaurants?price_gte=3

Find multiple restaurant with id 3, 6, 8.

GET /restaurants?id_in=3&id_in=6&id_in=8

Using _where

GET /restaurants?_where[price_gte]=3

GET /restaurants?_where[0][price_gte]=3&[0][price_lte]=7

Complex queries

NOTE

OR and AND operations are available starting from v3.1.0

When building more complex queries you must use the _where query parameter in combination with the qsContent API - 图1 (opens new window) library.

We are taking advantage of the capability of qs to parse nested objects to create more complex queries.

This will give you full power to create complex queries with logical AND and OR operations.

NOTE

We strongly recommend using qs directly to generate complex queries instead of creating them manually.

AND operator

The filtering implicitly supports the AND operation when specifying an array of expressions in the filtering.

Examples

Restaurants that have 1 stars and a pricing less than or equal to 20:

  1. const query = qs.stringify({
  2. _where: [{ stars: 1 }, { pricing_lte: 20 }],
  3. });
  4. await request(`/restaurants?${query}`);
  5. // GET /restaurants?_where[0][stars]=1&_where[1][pricing_lte]=20

Restaurants that have a pricing greater than or equal to 20 and a pricing less than or equal to 50:

  1. const query = qs.stringify({
  2. _where: [{ pricing_gte: 20 }, { pricing_lte: 50 }],
  3. });
  4. await request(`/restaurants?${query}`);
  5. // GET /restaurants?_where[0][pricing_gte]=20&_where[1][pricing_lte]=50

OR operator

To use the OR operation, you will need to use the _or filter and specify an array of expressions on which to perform the operation.

Examples

Restaurants that have 1 stars OR a pricing greater than 30:

  1. const query = qs.stringify({ _where: { _or: [{ stars: 1 }, { pricing_gt: 30 }] } });
  2. await request(`/restaurant?${query}`);
  3. // GET /restaurants?_where[_or][0][stars]=1&_where[_or][1][pricing_gt]=30

Restaurants that have a pricing less than 10 OR greater than 30:

  1. const query = qs.stringify({ _where: { _or: [{ pricing_lt: 10 }, { pricing_gt: 30 }] } });
  2. await request(`/restaurant?${query}`);
  3. // GET /restaurants?_where[_or][0][pricing_lt]=10&_where[_or][1][pricing_gt]=30

Implicit OR operator

The query engine implicitly uses the OR operation when you pass an array of values in an expression.

Examples

Restaurants that have 1 or 2 stars:

GET /restaurants?stars=1&stars=2

or

  1. const query = qs.stringify({ _where: { stars: [1, 2] } });
  2. await request(`/restaurant?${query}`);
  3. // GET /restaurants?_where[stars][0]=1&_where[stars][1]=2

NOTE

When using the in and nin filters the array is not transformed into a OR.

Combining AND and OR operators

Restaurants that have (2 stars AND a pricing less than 80) OR (1 stars AND a pricing greater than or equal to 50)

  1. const query = qs.stringify({
  2. _where: {
  3. _or: [
  4. [{ stars: 2 }, { pricing_lt: 80 }], // implicit AND
  5. [{ stars: 1 }, { pricing_gte: 50 }], // implicit AND
  6. ],
  7. },
  8. });
  9. await request(`/restaurants?${query}`);
  10. // GET /restaurants?_where[_or][0][0][stars]=2&_where[_or][0][1][pricing_lt]=80&_where[_or][1][0][stars]=1&_where[_or][1][1][pricing_gte]=50

This also works with deep filtering

Restaurants that have (2 stars AND a pricing less than 80) OR (1 stars AND serves French food)

  1. const query = qs.stringify({
  2. _where: {
  3. _or: [
  4. [{ stars: 2 }, { pricing_lt: 80 }], // implicit AND
  5. [{ stars: 1 }, { 'categories.name': 'French' }], // implicit AND
  6. ],
  7. },
  8. });
  9. await request(`/restaurants?${query}`);
  10. // GET /restaurants?_where[_or][0][0][stars]=2&_where[_or][0][1][pricing_lt]=80&_where[_or][1][0][stars]=1&_where[_or][1][1][categories.name]=French

WARNING

When creating nested queries, make sure the depth is less than 20 or the query string parsing will fail for now.

Deep filtering

Find restaurants owned by a chef who belongs to a restaurant with star equal to 5 GET /restaurants?chef.restaurant.star=5

WARNING

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 your query.

TIP

This feature doesn’t allow you to filter nested models, e.g. Find users and only return their posts older than yesterday.

To achieve this, there are three options:

  • Build a custom route.
  • Modify your services.
  • Use GraphQL.

WARNING

This feature isn’t available for polymorphic relations. This relation type is used in media, component and dynamic zone fields.

Sort

Sort according to a specific field.

Example

Sort users by email.
  • ASC: GET /users?_sort=email:ASC
  • DESC: GET /users?_sort=email:DESC
Sorting on multiple fields
  • GET /users?_sort=email:asc,dateField:desc
  • GET /users?_sort=email:DESC,username:ASC

Limit

Limit the size of the returned results.

The default limit is 100

Example

Limit the result length to 30.

GET /users?_limit=30

You can require the full data set by passing a limit equal to -1.

Start

Skip a specific number of entries (especially useful for pagination).

Example

Get the second page of results.

GET /users?_start=10&_limit=10

Publication State

NOTE

This parameter can only be used on models with the Draft & Publish feature activated

Only select entries matching the publication state provided.

Handled states are:

  • live: Return only published entries (default)
  • preview: Return both draft entries & published entries

Example

Get published articles

GET /articles OR GET /articles?_publicationState=live

Get both published and draft articles

GET /articles?_publicationState=preview

NOTE

If you only want to retrieve your draft entries, you can combine the preview mode and the published_at field. GET /articles?_publicationState=preview&published_at_null=true