Skip to content

Instantly share code, notes, and snippets.

@e0ipso
Last active April 7, 2024 08:19
Show Gist options
  • Select an option

  • Save e0ipso/efcc4e96ca2aed58e32948e4f70c2460 to your computer and use it in GitHub Desktop.

Select an option

Save e0ipso/efcc4e96ca2aed58e32948e4f70c2460 to your computer and use it in GitHub Desktop.

Revisions

  1. e0ipso revised this gist Jan 4, 2017. 1 changed file with 23 additions and 19 deletions.
    42 changes: 23 additions & 19 deletions JSON API Fancy Filters.md
    Original file line number Diff line number Diff line change
    @@ -9,62 +9,66 @@ The [JSON API](http://jsonapi.org/format/#fetching-filtering) specification is a
    > Note: JSON API is agnostic about the strategies supported by a server. The `filter` query parameter can be used as the basis for any number of filtering strategies.
    This specification covers the gap by specifying an strategy that can be adopted by any JSON API server. This specification will cover:
    * Filter conditions: These are the assertions made against the data store which qualify a record for inclusion in a collection result or not.
    * Filter conditions: These are the assertions made against the data store which qualify a record for inclusion in a collection result.
    * Filter groups.: These allow the creation of complex, nested queries. For example, queries with AND operators within a higher level OR condition.

    # Filter conditions
    # Filter Conditions

    Conditional objects represent a conditional statement for the backend to execute in order to retrieve the eligible records. In many data stores these are called _where_ clauses.
    Filter conditions are represented by _conditional objects_. These object codify a conditional statement that a JSON API server will execute in order to retrieve a subset of eligible records. These are called _where_ clauses in many data query languages, like SQL.

    A conditional object **MUST** have an arbitrary ID key that uniquely idenfies the conditional object inside of the `filter` parameter in the JSON API request URI. Additionally, a conditional object **MUST** contain the following keys:
    A conditional object **MUST** have an arbitrary ID which uniquely idenfies the conditional object inside of the `filter` parameter of a JSON API request URI. Additionally, a conditional object **MUST** contain the following keys:

    * `path`. The path property **MUST** be a _complex property identifier_ that identifies the property and the entity type that hosts it, upon which the condition is tested. A path identifies the record series of attributes and or relationships to follow in order to fetch the data against with the filter condition should be evaluated.
    * `path`. The path property **MUST** adhere to the _property accessor format_. The `path` identifies the property within the entity type that hosts it. The path selects the data value against which the conditional object will be applied. A path **MUST** be able to select any attribute property of an entity. A path **MAY** be able to traverse relationships.
    * `value`. The value used in the comparison made against the data value of the property identified by the `path`.

    A conditional object **MAY** also contain the following keys:

    * `operator`. The operator used during the comparison. If nothing is specified, then the operator defaults to `'='`. A JSON API server **SHOULD** implement, at least, the following operators: `=`, `<`, `>`, `<>`, `IN`, `NOT IN`, `BETWEEN`, `IS NULL` and `IS NOT NULL`.
    * `memberOf`. If this filter condition should be grouped within a parent filter group, this is that filter group's arbitrary ID key. If the contents of the `memberOf` property does not match any group definition ID, then it **MAY** be ignored. If this property is not provided, then the current condition will be assigned to the implicit _root group_.
    * `operator`. The operator used during the comparison. If nothing is specified, then the operator defaults to `'='`. A JSON API server **SHOULD** implement, at least, the following operators: `=`, `<`, `>`, `<>`. In addition to those operators, a server **MAY** support `IN`, `NOT IN`, `BETWEEN`, `IS NULL` and `IS NOT NULL`.
    * `memberOf`. If the conditional object should be grouped within a parent group object, this should be that group object's arbitrary ID. If the contents of the `memberOf` property does not match any group definition ID, then the conditional object **MAY** be ignored. If this property is not provided, then the current condition **SHOULD** be assigned to the implicit _root group_.

    In coionals with operators that act on multiple values (like `IN`), the `value` property **MUST** hold an array of values.
    In conditionals with operators that act on multiple values (like `IN`), the `value` property **MUST** hold an array of values.

    The keys for a filter conditional **MUST** be wrapped in a `condition` property to specify that the arbitrary ID is for a condition.

    ## Complex property ID
    ## Property Accessor Format

    _A complex property identifier_ is used to identify a property or sub-property in the requested entity type, or any entity type accessible via relationships from the requested entity type. _Complex property identifiers_ **MUST** contain a dot separated list of path elements. Each element **MUST** be either a relationship field, an attribute field, or the name of a property in an attribute. The end of the _complex property ID_ **MUST** be an attribute followed by an optional group attribute's property names.
    A _property accessor_ is used to identify a property or sub-property in the requested entity type, or, if the server supports it, any entity type accessible via relationships from the requested entity type. _Property accessors_ **MUST** contain be a dot separated list of path elements. Each path element **MUST** be an attribute field or the name of a property in an attribute. If the JSON API server support conditions which traverse relationship, the _property accessor_ **MAY** contain relationship names as path elements. The last path element of the _property accessor_ **MUST** be an attribute followed by an optional group attribute's property names.

    ### Example 1

    In the simplest form, just an attribute on an entity, the _complex property ID_ is just the name of the attribute. For example, the title of a `blog` entity would simply be: `title`
    In the simplest form, the _property accessor_ is just the name of the attribute. For example, the _propery accessor_ for the title attribute of a `blog` entity would simply be: `title`

    ### Example 2

    You want to get all post created by authors whose accounts were created within the last week. There exists an entity type, `blog`, and an entity type `user`. The `blog` type has a relationship to its creating user under the `author` relationship. The `user` entity type has an attribute of `created` representing the date that the user account was established. Thus, the _complex property ID_ is simply: `author.created`
    In a more complex form, you may wish to filter based on attributes accessed across a relationship. For example, you wish to get all post created by authors whose accounts were created within the last week. There exists an entity type, `blog`, and an entity type `user`. The `blog` type has a relationship to its creating user under the `author` relationship. The `user` entity type has an attribute of `created` representing the date that the user account was established. Thus, the _property accessor_ is simply: `author.created`

    ### Example 3

    You want to get all TV shows, that contain a published video in a given streaming platform ("netflix"). Assume that there is an object attribute inside of the `/videos` resource that contains a list of streaming platforms as keys with a boolean as values.

    In this case, the _complex property ID_ will be: `seasons.videos.published.netflix`. Where `seasons` and `videos` are relationships, `published` is an attribute in the videos entity type and `netflix` is a property inside of the `published` attribute.
    In this case, the _property accessor_ would be: `seasons.videos.published.netflix`. Where `seasons` and `videos` are relationships, `published` is an attribute in the videos entity type and `netflix` is a property inside of the `published` attribute.

    ### Example 4

    If property `prop` inside of the attribute `attr`, belonging to the entity type `C` wants to be used to include/exclude records in the resource `A`. Then there must be a relationship, or a chain of relationships, between entity type `A` and `C`. In this example, assume that there is a relationship `relAtoB` that goes from `A` to `B`, and relationship `relBtoC` that goes from `B` to `C`. In this scenario the _complex property identifier_ will be: `relAtoB.relBtoC.attr.prop`.
    If property `prop` inside of the attribute `attr`, belonging to the entity type `C` wants to be used to include/exclude records in the resource `A`. Then there must be a relationship, or a chain of relationships, between entity type `A` and `C`. In this example, assume that there is a relationship `relAtoB` that goes from `A` to `B`, and relationship `relBtoC` that goes from `B` to `C`. In this scenario the _property accessor_ will be: `relAtoB.relBtoC.attr.prop`.

    # Filter groups
    # Filter Groups

    A group is used to evaluate multiple conditions or other groups in tandem. They are provide the ability to specify a conjunction between multiple conditional objects and/or groups.
    A group objecst are used to evaluate multiple conditions or other groups in tandem. They provide the ability to specify a conjunction between multiple conditional objects and/or group objects.

    A group object **MUST** have an arbitrary ID key that uniquely idenfies the group object inside of the `filter` parameter in the JSON API request URI. Additionally a conditional object **MUST** contain the following keys:
    A group object **MUST** have an arbitrary ID that uniquely idenfies the group object inside of the `filter` parameter in the JSON API request URI. Additionally a group object **MUST** contain the following keys:

    * `conjunction`. Support for `AND` and `OR` **MUST** be provided. A server **MAY** support any of: `NAND`, `NOR`, `XOR`, `XNOR` and other binary logical operators.
    * `conjunction`. A JSON API server **MUST** support `AND` and `OR`. A server **MAY** support any of: `NAND`, `NOR`, `XOR`, `XNOR` and other binary logical operators.
    * `memberOf`. The result of a group might need to be evaluated inside of a group with other groups and/or conditions. To specify the group this current group belongs to, the `memberOf` key **MUST** be used.

    If no group is specified, a JSON API server **MUST** assume that all the conditional objects belong to a single implicit root group. This group uses the `AND` conjuction.
    If no group is specified, a JSON API server **MUST** assume that all the conditional objects belong to a single implicit _root group_.

    The keys for a filter conditional **MUST** be wrapped in a `group` property to specify that the arbitrary ID is for a group.

    ## Implicit Root Group

    Filter and group objects may omit the `memberOf` keys. In this case, a server **MUST** assume that these objects belong to an implicit _root group_. The JSON API **MUST** use the `AND` conjuntion for this _root group_.

    # Examples

    ## Example 1
  2. e0ipso revised this gist Jan 4, 2017. 1 changed file with 22 additions and 14 deletions.
    36 changes: 22 additions & 14 deletions JSON API Fancy Filters.md
    Original file line number Diff line number Diff line change
    @@ -9,24 +9,24 @@ The [JSON API](http://jsonapi.org/format/#fetching-filtering) specification is a
    > Note: JSON API is agnostic about the strategies supported by a server. The `filter` query parameter can be used as the basis for any number of filtering strategies.
    This specification covers the gap by specifying an strategy that can be adopted by any JSON API server. This specification will cover:
    * Filter conditions. These are the comparisons made against the data store that qualify a record in a collection as elegible or not.
    * Filter groups. If you have to use multiple conditions, groups are used to determine how the different conditions interact with each other.
    * Filter conditions: These are the assertions made against the data store which qualify a record for inclusion in a collection result or not.
    * Filter groups.: These allow the creation of complex, nested queries. For example, queries with AND operators within a higher level OR condition.

    # Filter conditions

    Conditional objects represent a conditional statement for the backend to execute in order to retrieve the elegible records. In many data stores these are called _where_ clauses.
    Conditional objects represent a conditional statement for the backend to execute in order to retrieve the eligible records. In many data stores these are called _where_ clauses.

    A conditional object **MUST** have an arbitrary ID key that uniquely idenfies the conditional object inside of the `filter` parameter in the JSON API request URI. Additionally a conditional object **MUST** contain the following keys:
    A conditional object **MUST** have an arbitrary ID key that uniquely idenfies the conditional object inside of the `filter` parameter in the JSON API request URI. Additionally, a conditional object **MUST** contain the following keys:

    * `path`. The path property **MUST** be a _complex property identifier_ that identifies the property and the entity type that hosts it, upon which the condition is tested.
    * `value`. The value used in the comparison made against the contents of the property specified in the `path`.
    * `path`. The path property **MUST** be a _complex property identifier_ that identifies the property and the entity type that hosts it, upon which the condition is tested. A path identifies the record series of attributes and or relationships to follow in order to fetch the data against with the filter condition should be evaluated.
    * `value`. The value used in the comparison made against the data value of the property identified by the `path`.

    A conditional object **MAY** also contain the following keys:

    * `operator`. The operator used during the comparison. If nothing is specified, then the operator defaults to `'='`. A JSON API server **SHOULD** implement, at least, the following operators: `=`, `<`, `>`, `<>`, `IN`, `NOT IN`, `BETWEEN`, `IS NULL` and `IS NOT NULL`.
    * `memberOf`. This is the group's arbitrary ID key this condition belongs to. If the contents of the `memberOf` property does not match any group definition ID, then it **MAY** be ignored. If this property is not provided, then the current condition will be assigned to the implicit _root group_.
    * `memberOf`. If this filter condition should be grouped within a parent filter group, this is that filter group's arbitrary ID key. If the contents of the `memberOf` property does not match any group definition ID, then it **MAY** be ignored. If this property is not provided, then the current condition will be assigned to the implicit _root group_.

    In contidionals with operators that act on multiple values (like `IN`), the `value` property **MUST** hold an array of values.
    In coionals with operators that act on multiple values (like `IN`), the `value` property **MUST** hold an array of values.

    The keys for a filter conditional **MUST** be wrapped in a `condition` property to specify that the arbitrary ID is for a condition.

    @@ -36,17 +36,25 @@ _A complex property identifier_ is used to identify a property or sub-property i

    ### Example 1

    If property `prop` inside of the attribute `attr`, belonging to the entity type `C` wants to be used to include/exclude records in the resource `A`. Then there must be a relationship, or a chain of relationships, between entity type `A` and `C`. In this example, let's assume that there is a relationship `relAtoB` that goes from `A` to `B`, and relationship `relBtoC` that goes from `B` to `C`. In this scenario the _complex property identifier_ will be: `relAtoB.relBtoC.attr.prop`.
    In the simplest form, just an attribute on an entity, the _complex property ID_ is just the name of the attribute. For example, the title of a `blog` entity would simply be: `title`

    ### Example 2

    You want to get all TV shows, that contain a plublised video in a given streaming platform ("netflix"). Let's assume that there is an object attribute inside of the `/videos` resource that contains a list of streaming platforms as keys with a boolean as values.
    You want to get all post created by authors whose accounts were created within the last week. There exists an entity type, `blog`, and an entity type `user`. The `blog` type has a relationship to its creating user under the `author` relationship. The `user` entity type has an attribute of `created` representing the date that the user account was established. Thus, the _complex property ID_ is simply: `author.created`

    In this case the _complex property ID_ will be: `seasons.videos.published.netflix`. Where `seasons` and `videos` are relationships, `published` is an attribute in the videos entity type and `netflix` is a property inside of the `published` attribute.
    ### Example 3

    You want to get all TV shows, that contain a published video in a given streaming platform ("netflix"). Assume that there is an object attribute inside of the `/videos` resource that contains a list of streaming platforms as keys with a boolean as values.

    In this case, the _complex property ID_ will be: `seasons.videos.published.netflix`. Where `seasons` and `videos` are relationships, `published` is an attribute in the videos entity type and `netflix` is a property inside of the `published` attribute.

    ### Example 4

    If property `prop` inside of the attribute `attr`, belonging to the entity type `C` wants to be used to include/exclude records in the resource `A`. Then there must be a relationship, or a chain of relationships, between entity type `A` and `C`. In this example, assume that there is a relationship `relAtoB` that goes from `A` to `B`, and relationship `relBtoC` that goes from `B` to `C`. In this scenario the _complex property identifier_ will be: `relAtoB.relBtoC.attr.prop`.

    # Filter groups

    A group is used to evaluate multiple contidions or other groups together. They are used to provide a conjunction to apply to multiple conditional objects and/or groups.
    A group is used to evaluate multiple conditions or other groups in tandem. They are provide the ability to specify a conjunction between multiple conditional objects and/or groups.

    A group object **MUST** have an arbitrary ID key that uniquely idenfies the group object inside of the `filter` parameter in the JSON API request URI. Additionally a conditional object **MUST** contain the following keys:

    @@ -61,7 +69,7 @@ The keys for a filter conditional **MUST** be wrapped in a `group` property to s

    ## Example 1

    You want to get all TV shows, that contain a plublised video in "netflix" or in "hulu". The equivalent filter object shuold be:
    You want to get all TV shows, that contain a published video in "netflix" or in "hulu". The equivalent filter object shuold be:

    * `orGroup`. A group with the or conjunction for the two conditions.
    * `hasNetflix`. A condition for the netflix published flag.
    @@ -101,4 +109,4 @@ GET /api/shows?filter[orGroup][group][conjunction]=OR&filter[hasNetflix][conditi
    Host: example.com
    Content-Type: application/vnd.api+json; ext=fancyfilters
    Accept: application/vnd.api+json; ext=fancyfilters
    ```
    ```
  3. e0ipso revised this gist Jan 2, 2017. 1 changed file with 13 additions and 13 deletions.
    26 changes: 13 additions & 13 deletions JSON API Fancy Filters.md
    Original file line number Diff line number Diff line change
    @@ -16,23 +16,23 @@ This specification covers the gap by specifying an strategy that can be adopted

    Conditional objects represent a conditional statement for the backend to execute in order to retrieve the elegible records. In many data stores these are called _where_ clauses.

    A conditional object *MUST* have an arbitrary ID key that uniquely idenfies the conditional object inside of the `filter` parameter in the JSON API request URI. Additionally a conditional object *MUST* contain the following keys:
    A conditional object **MUST** have an arbitrary ID key that uniquely idenfies the conditional object inside of the `filter` parameter in the JSON API request URI. Additionally a conditional object **MUST** contain the following keys:

    * `path`. The path property *MUST* be a _complex property identifier_ that identifies the property and the entity type that hosts it, upon which the condition is tested.
    * `path`. The path property **MUST** be a _complex property identifier_ that identifies the property and the entity type that hosts it, upon which the condition is tested.
    * `value`. The value used in the comparison made against the contents of the property specified in the `path`.

    A conditional object *MAY* also contain the following keys:
    A conditional object **MAY** also contain the following keys:

    * `operator`. The operator used during the comparison. If nothing is specified, then the operator defaults to `'='`. A JSON API server *SHOULD* implement, at least, the following operators: `=`, `<`, `>`, `<>`, `IN`, `NOT IN`, `BETWEEN`, `IS NULL` and `IS NOT NULL`.
    * `memberOf`. This is the group's arbitrary ID key this condition belongs to. If the contents of the `memberOf` property does not match any group definition ID, then it *MAY* be ignored. If this property is not provided, then the current condition will be assigned to the implicit _root group_.
    * `operator`. The operator used during the comparison. If nothing is specified, then the operator defaults to `'='`. A JSON API server **SHOULD** implement, at least, the following operators: `=`, `<`, `>`, `<>`, `IN`, `NOT IN`, `BETWEEN`, `IS NULL` and `IS NOT NULL`.
    * `memberOf`. This is the group's arbitrary ID key this condition belongs to. If the contents of the `memberOf` property does not match any group definition ID, then it **MAY** be ignored. If this property is not provided, then the current condition will be assigned to the implicit _root group_.

    In contidionals with operators that act on multiple values (like `IN`), the `value` property *MUST* hold an array of values.
    In contidionals with operators that act on multiple values (like `IN`), the `value` property **MUST** hold an array of values.

    The keys for a filter conditional *MUST* be wrapped in a `condition` property to specify that the arbitrary ID is for a condition.
    The keys for a filter conditional **MUST** be wrapped in a `condition` property to specify that the arbitrary ID is for a condition.

    ## Complex property ID

    _A complex property identifier_ is used to identify a property or sub-property in the requested entity type, or any entity type accessible via relationships from the requested entity type. _Complex property identifiers_ *MUST* contain a dot separated list of path elements. Each element *MUST* be either a relationship field, an attribute field, or the name of a property in an attribute. The end of the _complex property ID_ *MUST* be an attribute followed by an optional group attribute's property names.
    _A complex property identifier_ is used to identify a property or sub-property in the requested entity type, or any entity type accessible via relationships from the requested entity type. _Complex property identifiers_ **MUST** contain a dot separated list of path elements. Each element **MUST** be either a relationship field, an attribute field, or the name of a property in an attribute. The end of the _complex property ID_ **MUST** be an attribute followed by an optional group attribute's property names.

    ### Example 1

    @@ -48,14 +48,14 @@ In this case the _complex property ID_ will be: `seasons.videos.published.netfli

    A group is used to evaluate multiple contidions or other groups together. They are used to provide a conjunction to apply to multiple conditional objects and/or groups.

    A group object *MUST* have an arbitrary ID key that uniquely idenfies the group object inside of the `filter` parameter in the JSON API request URI. Additionally a conditional object *MUST* contain the following keys:
    A group object **MUST** have an arbitrary ID key that uniquely idenfies the group object inside of the `filter` parameter in the JSON API request URI. Additionally a conditional object **MUST** contain the following keys:

    * `conjunction`. Support for `AND` and `OR` *MUST* be provided. A server *MAY* support any of: `NAND`, `NOR`, `XOR`, `XNOR` and other binary logical operators.
    * `memberOf`. The result of a group might need to be evaluated inside of a group with other groups and/or conditions. To specify the group this current group belongs to, the `memberOf` key *MUST* be used.
    * `conjunction`. Support for `AND` and `OR` **MUST** be provided. A server **MAY** support any of: `NAND`, `NOR`, `XOR`, `XNOR` and other binary logical operators.
    * `memberOf`. The result of a group might need to be evaluated inside of a group with other groups and/or conditions. To specify the group this current group belongs to, the `memberOf` key **MUST** be used.

    If no group is specified, a JSON API server *MUST* assume that all the conditional objects belong to a single implicit root group. This group uses the `AND` conjuction.
    If no group is specified, a JSON API server **MUST** assume that all the conditional objects belong to a single implicit root group. This group uses the `AND` conjuction.

    The keys for a filter conditional *MUST* be wrapped in a `group` property to specify that the arbitrary ID is for a group.
    The keys for a filter conditional **MUST** be wrapped in a `group` property to specify that the arbitrary ID is for a group.

    # Examples

  4. e0ipso created this gist Jan 2, 2017.
    104 changes: 104 additions & 0 deletions JSON API Fancy Filters.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,104 @@
    # Status

    This extension was developed as part of the [jsonapi module for Drupal](https://drupal.org/project/jsonapi).

    # Introduction

    The [JSON API](http://jsonapi.org/format/#fetching-filtering) specification is agnostic about how a server implements filtering strategies. In fact, the spec says:

    > Note: JSON API is agnostic about the strategies supported by a server. The `filter` query parameter can be used as the basis for any number of filtering strategies.
    This specification covers the gap by specifying an strategy that can be adopted by any JSON API server. This specification will cover:
    * Filter conditions. These are the comparisons made against the data store that qualify a record in a collection as elegible or not.
    * Filter groups. If you have to use multiple conditions, groups are used to determine how the different conditions interact with each other.

    # Filter conditions

    Conditional objects represent a conditional statement for the backend to execute in order to retrieve the elegible records. In many data stores these are called _where_ clauses.

    A conditional object *MUST* have an arbitrary ID key that uniquely idenfies the conditional object inside of the `filter` parameter in the JSON API request URI. Additionally a conditional object *MUST* contain the following keys:

    * `path`. The path property *MUST* be a _complex property identifier_ that identifies the property and the entity type that hosts it, upon which the condition is tested.
    * `value`. The value used in the comparison made against the contents of the property specified in the `path`.

    A conditional object *MAY* also contain the following keys:

    * `operator`. The operator used during the comparison. If nothing is specified, then the operator defaults to `'='`. A JSON API server *SHOULD* implement, at least, the following operators: `=`, `<`, `>`, `<>`, `IN`, `NOT IN`, `BETWEEN`, `IS NULL` and `IS NOT NULL`.
    * `memberOf`. This is the group's arbitrary ID key this condition belongs to. If the contents of the `memberOf` property does not match any group definition ID, then it *MAY* be ignored. If this property is not provided, then the current condition will be assigned to the implicit _root group_.

    In contidionals with operators that act on multiple values (like `IN`), the `value` property *MUST* hold an array of values.

    The keys for a filter conditional *MUST* be wrapped in a `condition` property to specify that the arbitrary ID is for a condition.

    ## Complex property ID

    _A complex property identifier_ is used to identify a property or sub-property in the requested entity type, or any entity type accessible via relationships from the requested entity type. _Complex property identifiers_ *MUST* contain a dot separated list of path elements. Each element *MUST* be either a relationship field, an attribute field, or the name of a property in an attribute. The end of the _complex property ID_ *MUST* be an attribute followed by an optional group attribute's property names.

    ### Example 1

    If property `prop` inside of the attribute `attr`, belonging to the entity type `C` wants to be used to include/exclude records in the resource `A`. Then there must be a relationship, or a chain of relationships, between entity type `A` and `C`. In this example, let's assume that there is a relationship `relAtoB` that goes from `A` to `B`, and relationship `relBtoC` that goes from `B` to `C`. In this scenario the _complex property identifier_ will be: `relAtoB.relBtoC.attr.prop`.

    ### Example 2

    You want to get all TV shows, that contain a plublised video in a given streaming platform ("netflix"). Let's assume that there is an object attribute inside of the `/videos` resource that contains a list of streaming platforms as keys with a boolean as values.

    In this case the _complex property ID_ will be: `seasons.videos.published.netflix`. Where `seasons` and `videos` are relationships, `published` is an attribute in the videos entity type and `netflix` is a property inside of the `published` attribute.

    # Filter groups

    A group is used to evaluate multiple contidions or other groups together. They are used to provide a conjunction to apply to multiple conditional objects and/or groups.

    A group object *MUST* have an arbitrary ID key that uniquely idenfies the group object inside of the `filter` parameter in the JSON API request URI. Additionally a conditional object *MUST* contain the following keys:

    * `conjunction`. Support for `AND` and `OR` *MUST* be provided. A server *MAY* support any of: `NAND`, `NOR`, `XOR`, `XNOR` and other binary logical operators.
    * `memberOf`. The result of a group might need to be evaluated inside of a group with other groups and/or conditions. To specify the group this current group belongs to, the `memberOf` key *MUST* be used.

    If no group is specified, a JSON API server *MUST* assume that all the conditional objects belong to a single implicit root group. This group uses the `AND` conjuction.

    The keys for a filter conditional *MUST* be wrapped in a `group` property to specify that the arbitrary ID is for a group.

    # Examples

    ## Example 1

    You want to get all TV shows, that contain a plublised video in "netflix" or in "hulu". The equivalent filter object shuold be:

    * `orGroup`. A group with the or conjunction for the two conditions.
    * `hasNetflix`. A condition for the netflix published flag.
    * `hasHulu`. A condition for the hulu published flag.
    * `tags`. A condition for the tags on the TV show seasons.

    That translates to:

    ```yaml
    filter:
    orGroup:
    group:
    conjunction: OR
    hasNetflix:
    condition:
    path: seasons.videos.published.netflix
    value: true
    memberOf: orGroup
    hasHulu:
    condition:
    path: seasons.videos.published.hulu
    value: true
    memberOf: orGroup
    tags:
    condition:
    path: seasons.tags
    value:
    - awesome
    - great
    operator: IN
    ```
    Serializing the `filter` object according to [RFC 3986](https://tools.ietf.org/html/rfc3986), results in a request like:

    ```http
    GET /api/shows?filter[orGroup][group][conjunction]=OR&filter[hasNetflix][condition][path]=seasons.videos.published.netflix&filter[hasNetflix][condition][value]=1&filter[hasNetflix][condition][memberOf]=orGroup&filter[hasHulu][condition][path]=seasons.videos.published.hulu&filter[hasHulu][condition][value]=1&filter[hasHulu][condition][memberOf]=orGroup&filter[tags][condition][path]=seasons.tags&filter[tags][condition][value][]=awesome&filter[tags][condition][value][]=great&filter[tags][condition][operator]=IN HTTP/1.1
    Host: example.com
    Content-Type: application/vnd.api+json; ext=fancyfilters
    Accept: application/vnd.api+json; ext=fancyfilters
    ```