Wagtail API Usage Guide
=======================

Listing views
-------------

Performing a ``GET`` request against one of the endpoints will get you a listing of objects in that endpoint. The response will look something like this:

.. code-block:: json

    GET /api/v1/endpoint_name/

    HTTP 200 OK
    Content-Type: application/json

    {
        "meta": {
            "total_count": "total number of results"
        },
        "endpoint_name": [
            {

            },
            {

            }
        ]
    }


This is the basic structure of all of the listing views. They all have a ``meta`` section with a ``total_count`` variable and a listing of things.


Detail views
------------

All of the endpoints also contain a "detail" view which returns information on an individual object. This view is always accessed by appending the id of the object to the URL.


The ``pages`` endpoint
----------------------

This endpoint includes all live pages in your site that have not been put in a private section.


The listing view (``/api/v1/pages/``)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This is what a typical response from a ``GET`` request to this listing would look like:

.. code-block:: json

    GET /api/v1/pages/

    HTTP 200 OK
    Content-Type: application/json

    {
        "meta": {
            "total_count": 2
        },
        "pages": [
            {
                "id": 2,
                "meta": {
                    "type": "demo.HomePage",
                    "detail_url": "http://api.example.com/api/v1/pages/2/"
                },
                "title": "Homepage"
            },
            {
                "id": 3,
                "meta": {
                    "type": "demo.BlogIndexPage",
                    "detail_url": "http://api.example.com/api/v1/pages/3/"
                },
                "title": "Blog"
            }
        ]
    }


Each page object contains the ``id``, a ``meta`` section and the fields with their values.


``meta``
^^^^^^^^

This section is used to hold "metadata" fields which aren't fields in the database. Wagtail API adds two by default:

 - ``type`` - The app label/model name of the object
 - ``detail_url`` - A URL linking to the detail view for this object


Selecting a page type
^^^^^^^^^^^^^^^^^^^^^

Most Wagtail sites are made up of multiple different types of page that each have their own specific fields. In order to view/filter/order on fields specific to one page type, you must select that page type using the ``type`` query parameter.


The ``type`` query parameter must be set to the Pages model name in the format: ``app_label.ModelName``.

.. code-block:: json

    GET /api/v1/pages/?type=demo.BlogPage

    HTTP 200 OK
    Content-Type: application/json

    {
        "meta": {
            "total_count": 3
        },
        "pages": [
            {
                "id": 4,
                "meta": {
                    "type": "demo.BlogPage",
                    "detail_url": "http://api.example.com/api/v1/pages/4/"
                },
                "title": "My blog 1"
            },
            {
                "id": 5,
                "meta": {
                    "type": "demo.BlogPage",
                    "detail_url": "http://api.example.com/api/v1/pages/5/"
                },
                "title": "My blog 2"
            },
            {
                "id": 6,
                "meta": {
                    "type": "demo.BlogPage",
                    "detail_url": "http://api.example.com/api/v1/pages/6/"
                },
                "title": "My blog 3"
            }
        ]
    }


Specifying a list of fields to return
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

As you can see, we still only get the ``title`` field, even though we have selected a type. That's because listing pages require you to explicitly tell it what extra fields you would like to see. You can do this with the ``fields`` query parameter.

Just set ``fields`` to a command-separated list of field names that you would like to use.

.. code-block:: json

    GET /api/v1/pages/?type=demo.BlogPage&fields=title,date_posted,feed_image

    HTTP 200 OK
    Content-Type: application/json

    {
        "meta": {
            "total_count": 3
        },
        "pages": [
            {
                "id": 4,
                "meta": {
                    "type": "demo.BlogPage",
                    "detail_url": "http://api.example.com/api/v1/pages/4/"
                },
                "title": "My blog 1",
                "date_posted": "2015-01-23",
                "feed_image": {
                    "id": 1,
                    "meta": {
                        "type": "wagtailimages.Image",
                        "detail_url": "http://api.example.com/api/v1/images/1/"
                    }
                }
            },
            {
                "id": 5,
                "meta": {
                    "type": "demo.BlogPage",
                    "detail_url": "http://api.example.com/api/v1/pages/5/"
                },
                "title": "My blog 2",
                "date_posted": "2015-01-24",
                "feed_image": {
                    "id": 2,
                    "meta": {
                        "type": "wagtailimages.Image",
                        "detail_url": "http://api.example.com/api/v1/images/2/"
                    }
                }
            },
            {
                "id": 6,
                "meta": {
                    "type": "demo.BlogPage",
                    "detail_url": "http://api.example.com/api/v1/pages/6/"
                },
                "title": "My blog 3",
                "date_posted": "2015-01-25",
                "feed_image": {
                    "id": 3,
                    "meta": {
                        "type": "wagtailimages.Image",
                        "detail_url": "http://api.example.com/api/v1/images/3/"
                    }
                }
            }
        ]
    }


We now have enough information to make a basic blog listing with a feed image and date that the blog was posted.


Filtering on fields
^^^^^^^^^^^^^^^^^^^

Exact matches on field values can be done by using a query parameter with the same name as the field. Any pages with the field that exactly matches the value of this parameter will be returned.

.. code-block:: json

    GET /api/v1/pages/?type=demo.BlogPage&fields=title,date_posted&date_posted=2015-01-24

    HTTP 200 OK
    Content-Type: application/json

    {
        "meta": {
            "total_count": 1
        },
        "pages": [

            {
                "id": 5,
                "meta": {
                    "type": "demo.BlogPage",
                    "detail_url": "http://api.example.com/api/v1/pages/5/"
                },
                "title": "My blog 2",
                "date_posted": "2015-01-24",
            }
        ]
    }


Filtering by section of the tree
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

It is also possible to filter the listing to only include pages with a particular parent. This is useful if you have multiple blogs on your site and only want to view the contents of one of them.

For example (imagine we are in the same project as all previous examples, and page id ``7`` refers to the other blog index):

.. code-block:: json

    GET /api/v1/pages/?child_of=7

    HTTP 200 OK
    Content-Type: application/json

    {
        "meta": {
            "total_count": 1
        },
        "pages": [
            {
                "id": 4,
                "meta": {
                    "type": "demo.BlogPage",
                    "detail_url": "http://api.example.com/api/v1/pages/4/"
                },
                "title": "Other blog 1"
            }
        ]
    }


Ordering
^^^^^^^^

Like filtering, it is also possible to order on database fields. The endpoint accepts a query parameter called ``order`` which should be set to the field name to order by. Field names can be prefixed with a ``-`` to reverse the ordering. It is also possible to order randomly by setting this parameter to ``random``.

.. code-block:: json

    GET /api/v1/pages/?type=demo.BlogPage&fields=title,date_posted,feed_image&order=-date_posted

    HTTP 200 OK
    Content-Type: application/json

    {
        "meta": {
            "total_count": 3
        },
        "pages": [
            {
                "id": 6,
                "meta": {
                    "type": "demo.BlogPage",
                    "detail_url": "http://api.example.com/api/v1/pages/6/"
                },
                "title": "My blog 3",
                "date_posted": "2015-01-25",
                "feed_image": {
                    "id": 3,
                    "meta": {
                        "type": "wagtailimages.Image",
                        "detail_url": "http://api.example.com/api/v1/images/3/"
                    }
                }
            },
            {
                "id": 5,
                "meta": {
                    "type": "demo.BlogPage",
                    "detail_url": "http://api.example.com/api/v1/pages/5/"
                },
                "title": "My blog 2",
                "date_posted": "2015-01-24",
                "feed_image": {
                    "id": 2,
                    "meta": {
                        "type": "wagtailimages.Image",
                        "detail_url": "http://api.example.com/api/v1/images/2/"
                    }
                }
            },
            {
                "id": 4,
                "meta": {
                    "type": "demo.BlogPage",
                    "detail_url": "http://api.example.com/api/v1/pages/4/"
                },
                "title": "My blog 1",
                "date_posted": "2015-01-23",
                "feed_image": {
                    "id": 1,
                    "meta": {
                        "type": "wagtailimages.Image",
                        "detail_url": "http://api.example.com/api/v1/images/1/"
                    }
                }
            }
        ]
    }


Pagination
^^^^^^^^^^

Pagination is done using two query parameters called ``limit`` and ``offset``. ``limit`` sets the number of results to return and ``offset`` is the index of the first result to return. The default value for ``limit`` is ``20`` and its maximum value is ``100`` (which can be changed using the ``WAGTAILAPI_MAX_RESULTS`` setting).

.. code-block:: json

    GET /api/v1/pages/?limit=1&offset=1

    HTTP 200 OK
    Content-Type: application/json

    {
        "meta": {
            "total_count": 2
        },
        "pages": [
            {
                "id": 3,
                "meta": {
                    "type": "demo.BlogIndexPage",
                    "detail_url": "http://api.example.com/api/v1/pages/3/"
                },
                "title": "Blog"
            }
        ]
    }


Pagination will not change the ``total_count`` value in the meta.


Searching
^^^^^^^^^

To perform a full-text search, set the ``search`` parameter to the query string you would like to search on.

.. code-block:: json

    GET /api/v1/pages/?search=Blog

    HTTP 200 OK
    Content-Type: application/json

    {
        "meta": {
            "total_count": 3
        },
        "pages": [
            {
                "id": 3,
                "meta": {
                    "type": "demo.BlogIndexPage",
                    "detail_url": "http://api.example.com/api/v1/pages/3/"
                },
                "title": "Blog"
            },
            {
                "id": 4,
                "meta": {
                    "type": "demo.BlogPage",
                    "detail_url": "http://api.example.com/api/v1/pages/4/"
                },
                "title": "My blog 1",
            },
            {
                "id": 5,
                "meta": {
                    "type": "demo.BlogPage",
                    "detail_url": "http://api.example.com/api/v1/pages/5/"
                },
                "title": "My blog 2",
            },
            {
                "id": 6,
                "meta": {
                    "type": "demo.BlogPage",
                    "detail_url": "http://api.example.com/api/v1/pages/6/"
                },
                "title": "My blog 3",
            }
        ]
    }


The results are ordered by relevance. It is not possible to use the ``order`` parameter with a search query.

If your Wagtail site is using Elasticsearch, you do not need to select a type to access specific fields. This will search anything that's defined in the models' ``search_fields``.


The detail view (``/api/v1/pages/{id}/``)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This view gives you access to all of the details for a particular page.

.. code-block:: json

    GET /api/v1/pages/6/

    HTTP 200 OK
    Content-Type: application/json

    {
        "id": 6,
        "meta": {
            "type": "demo.BlogPage",
            "detail_url": "http://api.example.com/api/v1/pages/6/"
        },
        "parent": {
            "id": 3,
            "meta": {
                "type": "demo.BlogIndexPage",
                "detail_url": "http://api.example.com/api/v1/pages/3/"
            }
        },
        "title": "My blog 3",
        "date_posted": "2015-01-25",
        "feed_image": {
            "id": 3,
            "meta": {
                "type": "wagtailimages.Image",
                "detail_url": "http://api.example.com/api/v1/images/3/"
            }
        },
        "related_links": [
            {
                "title": "Other blog page",
                "page": {
                    "id": 5,
                    "meta": {
                        "type": "demo.BlogPage",
                        "detail_url": "http://api.example.com/api/v1/pages/5/"
                    }
                }
            }
        ]
    }


The format is the same as that which is returned inside the listing view, with two additions:
 - All of the available fields are added to the detail page by default
 - A ``parent`` field has been included that contains information about the parent page


The ``images`` endpoint
-----------------------

This endpoint gives access to all uploaded images. This will use the custom image model if one was specified. Otherwise, it falls back to ``wagtailimages.Image``.


The listing view (``/api/v1/images/``)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This is what a typical response from a ``GET`` request to this listing would look like:

.. code-block:: json

    GET /api/v1/images/

    HTTP 200 OK
    Content-Type: application/json

    {
        "meta": {
            "total_count": 3
        }, 
        "images": [
            {
                "id": 4, 
                "meta": {
                    "type": "wagtailimages.Image",
                    "detail_url": "http://api.example.com/api/v1/images/4/"
                },
                "title": "Wagtail by Mark Harkin"
            }, 
            {
                "id": 5, 
                "meta": {
                    "type": "wagtailimages.Image",
                    "detail_url": "http://api.example.com/api/v1/images/5/"
                },
                "title": "James Joyce"
            }, 
            {
                "id": 6, 
                "meta": {
                    "type": "wagtailimages.Image",
                    "detail_url": "http://api.example.com/api/v1/images/6/"
                },
                "title": "David Mitchell"
            }
        ]
    }


Each image object contains the ``id`` and ``title`` of the image.


Getting ``width``, ``height`` and other fields
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Like the pages endpoint, the images endpoint supports the ``fields`` query parameter.

By default, this will allow you to add the ``width`` and ``height`` fields to your results. If your Wagtail site uses a custom image model, it is possible to have more.

.. code-block:: json

    GET /api/v1/images/?fields=title,width,height

    HTTP 200 OK
    Content-Type: application/json

    {
        "meta": {
            "total_count": 3
        }, 
        "images": [
            {
                "id": 4, 
                "meta": {
                    "type": "wagtailimages.Image",
                    "detail_url": "http://api.example.com/api/v1/images/4/"
                },
                "title": "Wagtail by Mark Harkin", 
                "width": 640, 
                "height": 427
            }, 
            {
                "id": 5, 
                "meta": {
                    "type": "wagtailimages.Image",
                    "detail_url": "http://api.example.com/api/v1/images/5/"
                },
                "title": "James Joyce", 
                "width": 500, 
                "height": 392
            }, 
            {
                "id": 6, 
                "meta": {
                    "type": "wagtailimages.Image",
                    "detail_url": "http://api.example.com/api/v1/images/6/"
                },
                "title": "David Mitchell", 
                "width": 360, 
                "height": 282
            }
        ]
    }


Filtering on fields
^^^^^^^^^^^^^^^^^^^

Exact matches on field values can be done by using a query parameter with the same name as the field. Any images with the field that exactly matches the value of this parameter will be returned.

.. code-block:: json

    GET /api/v1/pages/?title=James Joyce

    HTTP 200 OK
    Content-Type: application/json

    {
        "meta": {
            "total_count": 3
        }, 
        "images": [
            {
                "id": 5, 
                "meta": {
                    "type": "wagtailimages.Image",
                    "detail_url": "http://api.example.com/api/v1/images/5/"
                },
                "title": "James Joyce"
            }
        ]
    }


Ordering
^^^^^^^^

The images endpoint also accepts the ``order`` parameter which should be set to a field name to order by. Field names can be prefixed with a ``-`` to reverse the ordering. It is also possible to order randomly by setting this parameter to ``random``.

.. code-block:: json

    GET /api/v1/images/?fields=title,width&order=width

    HTTP 200 OK
    Content-Type: application/json

    {
        "meta": {
            "total_count": 3
        }, 
        "images": [
            {
                "id": 6, 
                "meta": {
                    "type": "wagtailimages.Image",
                    "detail_url": "http://api.example.com/api/v1/images/6/"
                },
                "title": "David Mitchell", 
                "width": 360
            },
            {
                "id": 5, 
                "meta": {
                    "type": "wagtailimages.Image",
                    "detail_url": "http://api.example.com/api/v1/images/5/"
                },
                "title": "James Joyce", 
                "width": 500
            },
            {
                "id": 4, 
                "meta": {
                    "type": "wagtailimages.Image",
                    "detail_url": "http://api.example.com/api/v1/images/4/"
                },
                "title": "Wagtail by Mark Harkin", 
                "width": 640
            }
        ]
    }


Pagination
^^^^^^^^^^

Pagination is done using two query parameters called ``limit`` and ``offset``. ``limit`` sets the number of results to return and ``offset`` is the index of the first result to return. The default value for ``limit`` is ``20`` and its maximum value is ``100`` (which can be changed using the ``WAGTAILAPI_MAX_RESULTS`` setting).

.. code-block:: json

    GET /api/v1/images/?limit=1&offset=1

    HTTP 200 OK
    Content-Type: application/json

    {
        "meta": {
            "total_count": 3
        },
        "images": [
            {
                "id": 5, 
                "meta": {
                    "type": "wagtailimages.Image",
                    "detail_url": "http://api.example.com/api/v1/images/5/"
                },
                "title": "James Joyce", 
                "width": 500, 
                "height": 392
            }
        ]
    }


Pagination will not change the ``total_count`` value in the meta.


Searching
^^^^^^^^^

To perform a full-text search, set the ``search`` parameter to the query string you would like to search on.

.. code-block:: json

    GET /api/v1/images/?search=James

    HTTP 200 OK
    Content-Type: application/json

    {
        "meta": {
            "total_count": 1
        },
        "pages": [
            {
                "id": 5, 
                "meta": {
                    "type": "wagtailimages.Image",
                    "detail_url": "http://api.example.com/api/v1/images/5/"
                },
                "title": "James Joyce", 
                "width": 500, 
                "height": 392
            }
        ]
    }


Like the pages endpoint, the results are ordered by relevance and it is not possible to use the ``order`` parameter with a search query.



The detail view (``/api/v1/images/{id}/``)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This view gives you access to all of the details for a particular image.

.. code-block:: json

    GET /api/v1/images/5/

    HTTP 200 OK
    Content-Type: application/json

    {
        "id": 5, 
        "meta": {
            "type": "wagtailimages.Image",
            "detail_url": "http://api.example.com/api/v1/images/5/"
        },
        "title": "James Joyce", 
        "width": 500, 
        "height": 392
    }


The ``documents`` endpoint
--------------------------

This endpoint gives access to all uploaded documents.


The listing view (``/api/v1/documents/``)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The documents listing supports the same features as the images listing (documented above) but works with Documents instead.


The detail view (``/api/v1/documents/{id}/``)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This view gives you access to all of the details for a particular document.

.. code-block:: json

    GET /api/v1/documents/1/

    HTTP 200 OK
    Content-Type: application/json

    {
        "id": 1, 
        "meta": {
            "type": "wagtaildocs.Document",
            "detail_url": "http://api.example.com/api/v1/documents/1/",
            "download_url": "http://api.example.com/documents/1/usage.md"
        }, 
        "title": "Wagtail API usage"
    }
