V1 API
======

This API describes the different ways of interacting with Glare service via HTTP protocol
using Representational State Transfer concept (ReST).

**Glossary**

* *Glare* (from GLare Artifact REpository) - a service that provides access
  to a unified catalog of immutable objects with structured meta-information as
  well as related binary data (these structures are also called *'artifacts'*).
  Glare controls artifact consistency and guaranties that binary data and
  fields won't change during artifact lifetime.

  .. note::

    Artifact type developer can declare fields whose values may be
    changed, but he has to do it explicitly, because by default all fields
    are considered as immutable.

* *Artifact* - in terms of Glare, an Artifact is a structured immutable object
  with some fields, related binary data, and metadata.

* *Artifact Version* - field of an artifact that defines its version in SemVer
  format.

* *Artifact type* - defines artifact structure of both its binary data and
  fields. Examples of OpenStack artifact types that will be supported
  in Glare are: Heat templates, Murano Packages, Nova Images, Tacker VNFs and
  so on. All artifact types are inherited from abstract Base type and extended
  with new fields. Base type is inherited from Base class
  from oslo_versionedobjects library (oslo_vo).

* *Artifact status* - specifies the state of the artifact and the possible
  actions that can be done with it. List of possible artifact statuses:

  * *drafted* - Artifact is created but not activated, so it can be changed by
    Artifact owner or Administrator.

  * *active* - Artifact is activated and marked as ready for usage.
    Only mutable fields can be changed since that.

  * *deactivated* - Artifact is not available to other users except
    administrators. Used when Cloud Admin need to check the artifact.

  * *deleted* - Artifact's deleted.

.. list-table::  **Artifact status transition table**
   :header-rows: 1

   * - Artifacts Status
     - drafted
     - active
     - deactivated
     - deleted

   * - **drafted**
     - X
     - activate Artifact
     - N/A
     - delete Artifact

   * - **active**
     - N/A
     - X
     - deactivate Artifact
     - delete Artifact

   * - **deactivated**
     - N/A
     - reactivate Artifact
     - X
     - delete Artifact

   * - **deleted**
     - N/A
     - N/A
     - N/A
     - X


* *Artifact Field* - field of an artifact that defines some information
  about the artifact. Artifact fields always have name, type, value and
  several additional parameters, described below.

  Glare uses several primitive types from oslo.versionedobjects directly:

  * *String*;

  * *Integer*;

  * *Float*;

  * *Boolean*;

  And also Glare expands this list with custom types:

  * *Blob*;

  * *Link*;

  * Structured generic types *Dict* or *List*.

  Each field has additional properties:

  * **required_on_activate** - boolean value indicating if the field value
    should be specified for the artifact before activation. (Default: True)

  * **mutable** - boolean value indicating if the field value may be changed
    after the artifact is activated. (Default: False)

  * **system** - boolean value indicating if the field value cannot be edited
    by User. (Default: False)

  * **sortable** - boolean value indicating if there is a possibility to sort by
    this field's values. (Default: False)

  .. note::

    Only the fields of 4 primitive types may be sortable: integer, string, float
    and boolean.

  * **nullable** - boolean value indicating if field's value can be empty
    (Default: True).

  * **default** - a default value for the field may be specified by the Artifact
    Type. (Default: None)

  * **validators** - a list of objects. When a user sets a value to the field with
    additional validators, Glare applies them before setting the value and
    raises `ValueError` if at least one of the validator requirements is not
    satisfied.

  * **filter_ops** - a list of available filter operators for the field. There
    are seven available operators: 'eq', 'neq', 'lt', 'lte', 'gt', 'gte', 'in'.

* *Artifact Link* - field type that defines soft dependency of the
  Artifact from another Artifact. It is an url that allows user to obtain
  some Artifact data. For external links the format is the following:
  *http(s)://<netloc>/<path>*
  For internal links its value contains only <path>.
  Example of <path>:
  ``/artifacts/<artifact_type>/<artifact identifier>``

* *Artifact Blob* - field type that defines binary data for Artifact.
  User can download Artifact blob from Glare. Each blob field has a flag
  *external*, that indicates if the field was created during file upload
  (False) or by direct user request (True). In other words, “external” means
  that blob field url is just a reference to some external file and Glare
  does not manage the blob operations in that case.
  Json schema that defines blob format:

  .. code-block:: javascript

        {
            "type": "object",
            "properties": {
                "url": {"type": ["string", "null"], "format": "uri",
                        "maxLength": 2048},
                "size": {"type": ["number", "null"]},
                "md5": {"type": ["string", "null"]},
                "sha1": {"type": ["string", "null"]},
                "sha256": {"type": ["string", "null"]},
                "external": {"type": "boolean"},
                "id": {"type": "string"},
                "status": {"type": "string",
                           "enum": ["saving", "active"]},
                "content_type": {"type": ["string", "null"]},
            },
            "required": ["url", "size", "md5", "sha1", "sha256", "external",
                         "status", "id", "content_type"]
        }

  Artifact blob fields may have the following statuses:

  * *saving* - Artifact blob record created in table, blob upload started.

  * *active* - blob upload successfully finished.

.. list-table::  **Blob status transition table**
   :header-rows: 1

   * - Blob Status
     - saving
     - active

   * - **saving**
     - X
     - finish blob upload

   * - **active**
     - N/A
     - X

* *Artifact Dict and List* - compound generic field types that
  implement Dict or List interfaces respectively, and contain values of some
  primitive type, defined by `element_type` attribute.

* *Artifact visibility* - defines who may have an access to Artifact.
  Initially there are 2 options:

      * `private` artifact is accessible by its owner and
         admin only. When artifact is 'drafted' its visibility is always `private`.

      * `public`, when all users have an access to the artifact by default.

   It's allowed to change visibility only when artifact has `active` status.

* *Artifact immutability* - when artifact is *drafted* all its fields
  are editable, but when it becomes *active* it is "immutable" and cannot be modified
  (except for those fields explicitly declared as `mutable`).

* *Base type json-schema*:

  .. code-block:: javascript

        {
            "name": "Base artifact type",
            "properties": {
                "activated_at": {
                    "description": "Datetime when artifact has became active.",
                    "filter_ops": ["eq",
                        "neq",
                        "in",
                        "gt",
                        "gte",
                        "lt",
                        "lte"
                    ],
                    "format": "date-time",
                    "glareType": "DateTime",
                    "readOnly": true,
                    "required_on_activate": false,
                    "sortable": true,
                    "type": ["string",
                        "null"
                    ]
                },
                "created_at": {
                    "description": "Datetime when artifact has been created.",
                    "filter_ops": ["eq",
                        "neq",
                        "in",
                        "gt",
                        "gte",
                        "lt",
                        "lte"
                    ],
                    "format": "date-time",
                    "glareType": "DateTime",
                    "readOnly": true,
                    "sortable": true,
                    "type": "string"
                },
                "description": {
                    "default": "",
                    "description": "Artifact description.",
                    "filter_ops": ["eq",
                        "neq",
                        "in"
                    ],
                    "glareType": "String",
                    "maxLength": 4096,
                    "mutable": true,
                    "required_on_activate": false,
                    "type": ["string",
                        "null"
                    ]
                },
                "id": {
                    "description": "Artifact UUID.",
                    "filter_ops": ["eq",
                        "neq",
                        "in"
                    ],
                    "glareType": "String",
                    "maxLength": 255,
                    "pattern": "^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$",
                    "readOnly": true,
                    "sortable": true,
                    "type": "string"
                },
                "metadata": {
                    "additionalProperties": {
                        "type": "string"
                    },
                    "default": {},
                    "description": "Key-value dict with useful information about an artifact.",
                    "filter_ops": ["eq",
                        "neq"
                    ],
                    "glareType": "StringDict",
                    "maxProperties": 255,
                    "required_on_activate": false,
                    "type": ["object",
                        "null"
                    ]
                },
                "name": {
                    "description": "Artifact Name.",
                    "filter_ops": ["eq",
                        "neq",
                        "in"
                    ],
                    "glareType": "String",
                    "maxLength": 255,
                    "required_on_activate": false,
                    "sortable": true,
                    "type": "string"
                },
                "owner": {
                    "description": "ID of user/tenant who uploaded artifact.",
                    "filter_ops": ["eq",
                        "neq",
                        "in"
                    ],
                    "glareType": "String",
                    "maxLength": 255,
                    "readOnly": true,
                    "required_on_activate": false,
                    "sortable": true,
                    "type": "string"
                },
                "status": {
                    "default": "drafted",
                    "description": "Artifact status.",
                    "enum": ["drafted",
                        "active",
                        "deactivated",
                        "deleted"
                    ],
                    "filter_ops": ["eq",
                        "neq",
                        "in"
                    ],
                    "glareType": "String",
                    "sortable": true,
                    "type": "string"
                },
                "tags": {
                    "default": [],
                    "description": "List of tags added to Artifact.",
                    "filter_ops": ["eq",
                        "neq",
                        "in"
                    ],
                    "glareType": "StringList",
                    "items": {
                        "type": "string"
                    },
                    "maxItems": 255,
                    "mutable": true,
                    "required_on_activate": false,
                    "type": ["array",
                        "null"
                    ]
                },
                "updated_at": {
                    "description": "Datetime when artifact has been updated last time.",
                    "filter_ops": ["eq",
                        "neq",
                        "in",
                        "gt",
                        "gte",
                        "lt",
                        "lte"
                    ],
                    "format": "date-time",
                    "glareType": "DateTime",
                    "readOnly": true,
                    "sortable": true,
                    "type": "string"
                },
                "version": {
                    "default": "0.0.0",
                    "description": "Artifact version(semver).",
                    "filter_ops": ["eq",
                        "neq",
                        "in",
                        "gt",
                        "gte",
                        "lt",
                        "lte"
                    ],
                    "glareType": "String",
                    "pattern": "/^([0-9]+)\\.([0-9]+)\\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?(?:\\+[0-9A-Za-z-]+)?$/",
                    "required_on_activate": false,
                    "sortable": true,
                    "type": "string"
                },
                "visibility": {
                    "default": "private",
                    "description": "Artifact visibility that defines if artifact can be available to other users.",
                    "filter_ops": ["eq"],
                    "glareType": "String",
                    "maxLength": 255,
                    "sortable": true,
                    "type": "string"
                }
            },
            "required": ["name"],
            "type": "object"
        }

Basics
------

Glare API complies with OpenStack API-WG guidelines:

  * `Filtering, sorting and pagination
    <https://github.com/openstack/api-wg/blob/master/guidelines/
    pagination_filter_sort.rst>`_

  * `Errors
    <http://specs.openstack.org/openstack/api-wg/guidelines/errors.html>`_

For updating artifact field values, Glare API uses `json-patch
<http://jsonpatch.com/>`_.

Glare supports microversions to define what API version it should use:
`API-WG microversion guidelines <http://specs.openstack.org/openstack/
api-wg/guidelines/microversion_specification.html>`_.

For description of artifact type `json-schema <http://json-schema.org/>`_ is
used.

Media types
^^^^^^^^^^^

Currently this API relies on JSON to represent states of REST resources.

Error states
^^^^^^^^^^^^

The common HTTP Response Status Codes (https://github.com/for-GET/know-your-http-well/blob/master/status-codes.md) are used.

Application root [/]
^^^^^^^^^^^^^^^^^^^^
Application Root provides links to all possible API versions for Glare. URLs
for other resources described below are relative to Application Root.

API schemas root [/schemas/]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
All the API urls are relative to schemas of artifact types.

* **List of enabled artifact type schemas**
   * **GET /schemas** - JSON-schemas list of all enabled artifact types

   * HTTP Responses:
        * 200

   * Response schema: JSON dictionary with elements <type_name>: <JSON_schema>

* **Get artifact type schema**
   * **GET /schemas/{artifact_type}** - get JSON-schema of artifact type `artifact_type`

   * HTTP Responses:
        * 200 if `artifact_type` is enabled
        * 404 if no artifact type is defined to handle the specified value of `artifact_type`

   * Response schema: JSON-schema for requested type


API artifacts root [/artifacts/]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
All the API urls are relative to artifacts.

All the APIs which are specific to the particular artifact type are
placed to `/artifacts/{artifact_type}`, where `artifact_type` is a constant
defined by the artifact type definition (i.e. by the related oslo_vo class).
For example, for artifacts of type "images" the API endpoints will start
with `/artifacts/images`.

The `artifact_type` constant should unambiguously identify the
artifact type, so the values of this constants should be unique among all the
enabled artifact types.


* **List artifacts**
   * **GET /artifacts/{artifact_type}** - list artifacts of given type

        Returns the list of artifacts having the specified type and scoped
        by the current tenant. If the user is ``administrator``, it
        returns the artifacts owned by all the tenants.

   * **GET /artifacts/all** - list artifacts regardless of their type

        Returns the list of artifacts of all types for given tenant. Only
        common fields will be shown in the output. All type-specific fields
        are skipped.

   * URL parameters:
       * `artifact_type` identifier of the artifact type, should be equal to a
          valid constant defined in one of the enabled oslo_vo classes.

   * Query parameters:
        Query may contain parameters intended for filtering and soring by most
        of the common and type-specific artifact fields.
        The set of parameters and their values should be compliant to the
        schema defined by the artifact type and its version.

        **Filtering**:

        * Filter keys may be any common or type-specific fields of
          primitive type, like 'String', 'Float', 'Integer' and 'Boolean'. Also
          it is possible to filter artifacts by Dict keys and Dict or List
          values.

          Direct comparison requires a field name to be specified as query
          parameter and the filtering value as its value, e.g. `?name=some_name`

          Parameter names and values are case sensitive.

        * Artifact API supports filtering operations in the format
          `?name=<op>:some_name`, where `op` is one of the following:

          1. **eq**: equal;
          2. **neq**: not equal;
          3. **gt**: greater than;
          4. **gte**: greater or equal than;
          5. **lt**: lesser than;
          6. **lte**: lesser or equal than;
          7. **in**: in a list of.

          Operator `eq` is default and may be omitted, i.e. filter
          `<field_name>=eq:<value>` is equal to `<field_name>=<value>`

        * Set comparison requires a field name to be specified as query
          parameter. The parameter may be repeated several times, e.g. the query
          `?name=qwerty&version=gt:1.0&version=lt:5.0` will filter the artifacts
          having name `qwerty` and versions from 1.0 to 5.0 excluding.

        * If it's required to filter the artifacts by any of the values, **in** operator
          should be used. List of comma-separated values should be provided for
          this operator. Query `?name=in:abc,def,ghi` will return all artifacts
          with names `abc`, `def` and `ghi`.

        * Filtering by Dict values is performed in format
          `<dict_name>.<key_name>=[<op_name>:]<value>`. This filter returns only
          those artifacts, that have the key `key_name` in their Dict `dict_name`
          and the `value` of the key satisfies the right part of the filter.
          It is allowed to filter values for Dict of primitive types only.

        * Dicts can be filtered by their keys in format
          `dict_name`=[<op_name>:]<value>. Only `eq`, `neq`, `in` can be used
          as filtering operators. For `eq`, it returns all artifacts, that have
          key `value` in their Dict field `dict_name`; for `neq`, it returns all artifacts
          that don't have that key in Dict `dict_name`; for `in`, it returns
          artifacts with any of the keys in comma-separated list `value`.

        * Filtering by List values may be performed in the same manner as by
          Dict keys.

        **Sorting**

        In order to retrieve data in any sort order and direction, artifacts
        REST API accepts multiple sort keys and directions.

        Artifacts API will align with the `API Working group sorting guidelines
        <https://github.com/openstack/api-wg/blob/master/guidelines/
        pagination_filter_sort.rst>`_ and support the following parameter on
        the request:

        * sort: Comma-separated list of sort keys. Each key is optionally
          appended with <:dir>, where 'dir' is the direction for the
          corresponding sort key (supported values are 'asc' for ascending
          and 'desc' for descending)

        Sort keys may be any generic and type-specific metadata fields of
        primitive type, like 'string', 'numeric', 'int' and 'bool'. But sorting
        by type-specific fields is allowed only when artifact version
        is provided.

        Default value for sort direction is 'desc'. Default value for sort key
        is 'created_at'.

        **Pagination**

        `limit` and `marker` query parameters may be used to paginate through
        the artifacts collection in the same way as it is done in the current
        version of Glance "List Images" API.

        Maximum `limit` number is 1000. It is done for security reasons to protect
        the system from intruders to prevent them from sending requests that can
        pull the entire database at a time.

   * HTTP Responses:
        * 200 if `artifact_type` is enabled
        * 400 if query has incorrect filter or sort parameters
        * 404 if no artifact type is defined to handle the specified value of `artifact_type`

   * Response schema:

       .. code-block:: javascript

            {
                "<type_name>": [<JSON_list_with_artifacts_data>],
                "first": "/artifacts/<type_name>",
                "schema": "/schemas/<type_name>",
                "next": "<url_to_the_next_page>"
            }

* **Create a new artifact**

   * **POST /artifacts/{artifact_type}**

   * Creates a new artifact record in database. The status of artifact is set
     to `drafted`. Request body may contain initial metadata of the artifact.
     It's mandatory to define at least artifact `name` and `version` in the request
     body.

   * URL parameters:

       * `artifact_type` identifier of the artifact type. It should be equal to a
         valid constant defined in one of the enabled oslo_vo classes.

   * HTTP Responses:

      * 201 if everything went fine.

      * 409 if an artifact of this type with the same name and version already
        exists for tenant.

      * 400 if incorrect initial values were provided in request body.

      * 404 if no Artifact Type is defined to handle the specified value of `artifact_type`.

  * Request content-type: `application/json`

  * Response content-type: `application/json`

  * Response schema: JSON with definition of created artifact

* **Get an artifact info**

    * **GET /artifacts/{artifact_type}/{id}**

    * Returns an artifact record with all the common and type-specific fields

    * URL parameters:

       * `artifact_type` identifier of the artifact type. It should be equal to a
         valid constant defined in one of the enabled oslo_vo classes.

       * `id` identifier of the artifact.

    * HTTP Responses:

       * 200 if everything went fine.

       * 404 if no artifact with the given ID was found.

       * 404 if the type of the found artifact differs from the type specified by `artifact_type`
       parameter.

    * Response content-type: `application/json`.

    * Response body: JSON with artifact definition.

    * **GET /artifacts/all/{id}**

    * Returns an artifact record with common fields only, regardless of its type.

    * URL parameters:

       * `id` identifier of the artifact

    * HTTP Responses:

       * 200 if everything went fine

       * 404 if no artifact with the given ID was found

    * Response content-type: `application/json`

    * Response schema: JSON with artifact definition

* **Update an Artifact**

    * **PATCH /artifacts/{artifact_type}/{id}**

    * Updates artifact's fields using json-patch notation. If the artifact
      has a status other than `drafted` then only mutable fields may be updated.

    * URL parameters:

       * `artifact_type` identifier of the artifact type, should be equal to a
         valid constant defined in one of the enabled oslo_vo classes.

       * `id` identifier of the artifact.

    * HTTP Responses:

       * 200 if everything went fine.

       * 404 if no artifact with the given ID was found.

       * 404 if the type of the found artifact differs from type specified by
         `artifact_type` parameter.

       * 403 if the PATCH attempts to modify the immutable field while the
         artifact's state is other than `drafted`.

       * 400 if incorrect initial values were provided in request body.

       * 409 if artifact with updated name and version already exists for the
         tenant.

    * Request content-type: `application/json-patch+json`

    * Response content-type: `application/json`

    * Response body: JSON definition of updated artifact

* **Delete an Artifact**

    * **DELETE /artifacts/{artifact_type}/{id}**

    * Deletes an artifact db record and all its binary data from store.

    * URL parameters:

       * `artifact_type` identifier of the artifact type. It should be equal to a
         valid constant defined in one of the enabled oslo_vo classes.

       * `id` identifier of the artifact

    * HTTP Responses:

       * 204 if everything went fine.

       * 404 if no artifact with the given ID was found.

       * 404 if the type of the found artifact differs from type specified by
         `artifact_type` parameter.

* **Upload a blob**

    * **PUT /artifacts/{artifact_type}/{id}/{blob_name}[/{key_name}]**

    * Uploads binary data to a blob field.

    * URL parameters:

       * `artifact_type` identifier of the artifact type, should be equal to a
         valid constant defined in one of the enabled oslo_vo classes.

       * `id` identifier of the artifact.

       * `blob_name` name of blob field.

       * optional: `key_name` name of a key if user uploads data in blob
       dictionary.

    * HTTP Responses:

       * 200 if everything went fine.

       * 404 if no artifact with the given ID was found.

       * 404 if the type of the found artifact differs from type specified by.
         `artifact_type` parameter.

       * 400 if `blob_name` field doesn't exist in `artifact_type` or it's not
         a blob field.

       * 409 if blob is already uploaded and has status `active`.

       * 409 if blob has status `saving`.

       * 413 if blob size exceeds the limit specified by artifact type.

    * Request content-type: any, except
      `application/vnd+openstack.glare-custom-location+json`.

    * Response content-type: `application/json`.

    * Response body: JSON definition of the artifact.

* **Download a blob**

    * **GET /artifacts/{artifact_type}/{id}/{blob_name}[/{key_name}]**

    * Downloads binary data from a blob field.

    * URL parameters:

       * `artifact_type` identifier of the artifact type, should be equal to a
         valid constant defined in one of the enabled oslo_vo classes.

       * `id` identifier of the artifact.

       * `blob_name` name of blob field.

       * optional: `key_name` name of a key if user downloads data from blob
       dictionary.

    * HTTP Responses:

       * 200 if everything went fine.

       * 301 if blob has `external` location.

       * 404 if no artifact with the given ID was found.

       * 404 if the type of the found artifact differs from type specified by
         `artifact_type` parameter.

       * 400 if `blob_name` field doesn't exist in `artifact_type` or it's not
         a blob field.

       * 403 if artifact has status `deactivated`.

    * Response content-type: specified by `content-type` field from the blob
      description.

    * Response body: binary data of the blob.

* **Add location to a blob**

    * **PUT /artifacts/{artifact_type}/{id}/{blob_name}[/{key_name}]**

    * Adds external location to a blob field instead of upload data.

    * URL parameters:

       * `artifact_type` identifier of the artifact type, should be equal to a
         valid constant defined in one of the enabled oslo_vo classes.

       * `id` identifier of the artifact.

       * `blob_name` name of blob field.

       * optional: `key_name` name of a key if user inserts location in blob
       dictionary.

    * HTTP Responses:

       * 200 if everything went fine.

       * 404 if no artifact with the given ID was found.

       * 404 if the type of the found artifact differs from type specified by
         `artifact_type` parameter.

       * 400 if `blob_name` field doesn't exist in `artifact_type` or it's not
         a blob field.

       * 409 if blob is already uploaded and has status `active`.

       * 409 if blob has status `saving`.

    * Request content-type: `application/vnd+openstack.glare-custom-location+json`.

    * Response content-type: `application/json`.

    * Response body: JSON definition of the artifact.

.. note::

      Json-schema for `application/vnd+openstack.glare-external-location+json` and
      `application/vnd+openstack.glare-internal-location+json`:

      .. code-block:: javascript

            {
                "type": "object",
                "properties": {
                    "url": {"type": ["string", "null"], "format": "uri",
                            "max_length": 255}
                },
                "required": ["url"]
            }

A detailed example
^^^^^^^^^^^^^^^^^^

For this example, we have an artifact type 'example_type' with fields:

* id: StringField

* name: StringField

* visibility: StringField

* status: StringField

* blob_file: BlobField

* metadata: DictOfStringsField

* version:  VersionField

.. note::

  For output simplicity this artifact type doesn't contain all required
  fields from Base artifact type.

1. Create artifact

  Request:

    * Method: POST

    * URL: http://host:port/artifacts/example_type

    * Body:

        .. code-block:: javascript

          {
             "name": "new_art",
             "version": "1.0"
          }

  Response:

      201 Created

      .. code-block:: javascript

           {
                "status": "drafted",
                "name": "new_art",
                "id": "art_id1",
                "version": "1.0.0",
                "blob_file": null,
                "metadata": {},
                "visibility": "private"
            }

2. Get artifact

  Request:

    * Method: GET

    * URL: http://host:port/artifacts/example_type/art_id1

  Response:

      200 OK

      .. code-block:: javascript

           {
                "status": "drafted",
                "name": "new_art",
                "id": "art_id1",
                "version": "1.0.0",
                "blob_file": null,
                "metadata": {},
                "visibility": "private"
            }

3. List artifacts

  Request:

    * Method: GET

    * URL: http://host:port/artifacts/example_type

  Response:

      200 OK

      .. code-block:: javascript

        {
            "example_type": [{
                "status": "drafted",
                "name": "new_art",
                "id": "art_id1",
                "version": "1.0.0",
                "blob_file": null,
                "metadata": {},
                "visibility": "private"
            }, {
                "status": "drafted",
                "name": "old_art",
                "id": "art_id2",
                "version": "0.0.0",
                "blob_file": null,
                "metadata": {},
                "visibility": "private"
            }, {
                "status": "drafted",
                "name": "old_art",
                "id": "art_id3",
                "version": "1.0.0",
                "blob_file": null,
                "metadata": {},
                "visibility": "private"
            }],
            "first": "/artifacts/example_type",
            "schema": "/schemas/example_type"
        }

  Request:

    * Method: GET

    * URL: http://host:port/artifacts/example_type?name=eq:old_art

  Response:

      200 OK

      .. code-block:: javascript

        {
            "example_type": [{
                "status": "drafted",
                "name": "old_art",
                "id": "art_id2",
                "version": "0.0.0",
                "blob_file": null,
                "metadata": {},
                "visibility": "private"
            }, {
                "status": "drafted",
                "name": "old_art",
                "id": "art_id3",
                "version": "1.0.0",
                "blob_file": null,
                "metadata": {},
                "visibility": "private"
            }],
            "first": "/artifacts/example_type?name=eq%3Aold_art",
            "schema": "/schemas/example_type"
        }

4. Update artifact

  Request:

    * Method: PATCH

    * URL: http://host:port/artifacts/example_type/art_id1

    * Body:

        .. code-block:: javascript

            [{
                "op": "replace",
                "path": "/name",
                "value": "another_artifact"
            }, {
                "op": "add",
                "path": "/metadata/item",
                "value": "qwerty"
            }]

  Response:

      200 OK

      .. code-block:: javascript

        {
            "status": "drafted",
            "name": "another_artifact",
            "id": "art_id1",
            "version": "1.0.0",
            "blob_file": null,
            "metadata": {
                "item": "qwerty"
            },
            "visibility": "private"
        }

5. Upload blob

  Request:

    * Method: PUT

    * URL: http://host:port/artifacts/example_type/art_id1/blob_file

    * Body: ``some binary data``

  Response:

      200 OK

      .. code-block:: javascript

        {
            "status": "drafted",
            "name": "another_artifact",
            "id": "art_id1",
            "version": "1.0.0",
            "metadata": {
                "item": "qwerty"
            },
            "blob_file": {
                "status": "active",
                "checksum": "8452e47f27b9618152a2b172357a547d",
                "external": false,
                "size": 594,
                "content_type": "application/octet-stream",
                "md5": "35d83e8eedfbdb87ff97d1f2761f8ebf",
                "sha1": "942854360eeec1335537702399c5aed940401602",
                "sha256": "d8a7834fc6652f316322d80196f6dcf294417030e37c15412e4deb7a67a367dd",
                "url": "/artifacts//example_type/art_id1/blob_file"
            },
            "visibility": "private"
        }

6. Download blob

  Request:

    * Method: GET

    * URL: http://host:port/artifacts/example_type/art_id1/blob_file

  Response:

      200 OK

      Body: ``blob binary data``


7. Activate artifact

  Request:

    * Method: PATCH

    * URL: http://host:port/artifacts/example_type/art_id1

    * Body:

       .. code-block:: javascript

            [{
                "op": "replace",
                "path": "/status",
                "value": "active"
            }]

  Response:

      200 OK

      .. code-block:: javascript

        {
            "status": "active",
            "name": "another_artifact",
            "id": "art_id1",
            "version": "1.0.0",
            "metadata": {
                "item": "qwerty"
            },
            "blob_file": {
                "status": "active",
                "checksum": "8452e47f27b9618152a2b172357a547d",
                "external": false,
                "size": 594,
                "content_type": "application/octet-stream",
                "md5": "35d83e8eedfbdb87ff97d1f2761f8ebf",
                "sha1": "942854360eeec1335537702399c5aed940401602",
                "sha256": "d8a7834fc6652f316322d80196f6dcf294417030e37c15412e4deb7a67a367dd",
                "url": "/artifacts//example_type/art_id1/blob_file"
            },
            "visibility": "private"
        }

8. Deactivate artifact

  Request:

    * Method: PATCH

    * URL: http://host:port/artifacts/example_type/art_id1

    * Body:

       .. code-block:: javascript

            [{
                "op": "replace",
                "path": "/status",
                "value": "deactivated"
            }]

  Response:

      200 OK

      .. code-block:: javascript

        {
            "status": "deactivated",
            "name": "another_artifact",
            "id": "art_id1",
            "version": "1.0.0",
            "metadata": {
                "item": "qwerty"
            },
            "blob_file": {
                "status": "active",
                "checksum": "8452e47f27b9618152a2b172357a547d",
                "external": false,
                "size": 594,
                "content_type": "application/octet-stream",
                "md5": "35d83e8eedfbdb87ff97d1f2761f8ebf",
                "sha1": "942854360eeec1335537702399c5aed940401602",
                "sha256": "d8a7834fc6652f316322d80196f6dcf294417030e37c15412e4deb7a67a367dd",
                "url": "/artifacts//example_type/art_id1/blob_file"
            },
            "visibility": "private"
        }

9. Reactivate artifact

  Request:

    * Method: PATCH

    * URL: http://host:port/artifacts/example_type/art_id1

    * Body:

       .. code-block:: javascript

            [{
                "op": "replace",
                "path": "/status",
                "value": "active"
            }]

  Response:

      200 OK

      .. code-block:: javascript

        {
            "status": "active",
            "name": "another_artifact",
            "id": "art_id1",
            "version": "1.0.0",
            "metadata": {
                "item": "qwerty"
            },
            "blob_file": {
                "status": "active",
                "checksum": "8452e47f27b9618152a2b172357a547d",
                "external": false,
                "size": 594,
                "content_type": "application/octet-stream",
                "md5": "35d83e8eedfbdb87ff97d1f2761f8ebf",
                "sha1": "942854360eeec1335537702399c5aed940401602",
                "sha256": "d8a7834fc6652f316322d80196f6dcf294417030e37c15412e4deb7a67a367dd",
                "url": "/artifacts//example_type/art_id1/blob_file"
            },
            "visibility": "private"
        }

10. Publish artifact

  Request:

    * Method: PATCH

    * URL: http://host:port/artifacts/example_type/art_id1

    * Body:

       .. code-block:: javascript

            [{
                "op": "replace",
                "path": "/visibility",
                "value": "public"
            }]

  Response:

      200 OK

      .. code-block:: javascript

        {
            "status": "active",
            "name": "another_artifact",
            "id": "art_id1",
            "version": "1.0.0",
            "metadata": {
                "item": "qwerty"
            },
            "blob_file": {
                "status": "active",
                "checksum": "8452e47f27b9618152a2b172357a547d",
                "external": false,
                "size": 594,
                "content_type": "application/octet-stream",
                "md5": "35d83e8eedfbdb87ff97d1f2761f8ebf",
                "sha1": "942854360eeec1335537702399c5aed940401602",
                "sha256": "d8a7834fc6652f316322d80196f6dcf294417030e37c15412e4deb7a67a367dd",
                "url": "/artifacts//example_type/art_id1/blob_file"
            },
            "visibility": "public"
        }

11. Delete artifact

  Request:

    * Method: DELETE

    * URL: http://host:port/artifacts/example_type/art_id1

  Response:

      204 No Content

References
==========
#. `Filtering and sorting API-WG guideline <http://specs.openstack.org/openstack/api-wg/guidelines/pagination_filter_sort.html>`_

#. `Errors API-WG guideline <http://specs.openstack.org/openstack/api-wg/guidelines/errors.html>`_

#. `json-patch description <http://jsonpatch.com/>`_

#. `json-schema description <http://json-schema.org/>`_
