Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API V2: Filtering nested fields via query parameter (Documents &c) #601

Merged

Conversation

calumbell
Copy link
Contributor

The Issue

This PR resolves issue #576 by implementing basic filtering on nested Serializers for V2 of the Open5e API.

Currently, on the staging branch there is no way to omit fields returned from nested serializers in the same way they can be omitted on root serializers.

This is especially problematic when working with the document field returned by most serialized. In the vast majoiry of cases, the data that is required by this field at the name, key and perhaps permalink. These fields can be requested simply enough when you hit the /documents endpoint.

But this kind of filtering is not possible when the serializer is accessed as a field on another serializer. This means that all document ForeignKeys will contain the full markdown copy describing the source as well as the full text for all of the licenses that are used. This leads to slower response times on the front-end by hugely overfetching

The Solution / What has changed?

The GameContentSerializer has been extended to recursively pass query parameters included in the request down to nested serializers via the context property.

Usage / Demonstration

  1. Checkout this PR on local and start up the Django test server
  2. Visit v2/spells/srd_magic-missile. Notice that all fields are returned and nested fields return a flat url.
  3. Include the query parameter fields=name,document. This will omit all fields in the API response except those specified in the field param. Note that the document field returns a url (link)
# v2/spells/srd_magic-missile/?fields=name,document
{
    "document": "http://localhost:8000/v2/documents/srd/",
    "name": "Magic Missile"
}
  1. Add the query parameter depth=1 to the url. All fields for the nested document serializer are returned. Note that doubly-nested fields such as gamesystem and publisher return flat urls. (link)
# v2/spells/srd_magic-missile/?fields=name,document&depth=1
{
    "document": {
        "url": "http://localhost:8000/v2/documents/srd/",
        "key": "srd",
        "licenses": [
           ...
        ],
        "publisher": "http://localhost:8000/v2/publishers/wizards-of-the-coast/",
        "gamesystem": "http://localhost:8000/v2/gamesystems/o5e/",
        "name": "Systems Reference Document",
        "desc": "The Systems Reference Document (SRD) contains....",
        "author": "Mike Mearls, Jeremy Crawford, Chris Perkins, ....",
        "published_at": "2023-01-23T00:00:00",
        "permalink": "https://dnd.wizards.com/resources/systems-reference-document",
        "stats_expected": null,
        "distance_unit": "feet"
    },
    "name": "Magic Missile"
}
  1. The nested fields can be filtered by prefixing the fields= parameter with the nested field's name, seperated with a double-underscore. In this case: document__fields=name,gamesystem (link)
# v2/spells/srd_magic-missile/?fields=name,document&depth=1&document__fields=name,gamesystem
{
    "document": {
        "gamesystem": "http://localhost:8000/v2/gamesystems/o5e/",
        "name": "Systems Reference Document"
    },
    "name": "Magic Missile"
}
  1. The details of the gamesystem can be viewed by increasing the depth to 2
# v2/spells/srd_magic-missile/?fields=name,document&depth=2&document__fields=name,gamesystem
{
    "document": {
        "gamesystem": {
            "url": "http://localhost:8000/v2/gamesystems/o5e/",
            "key": "o5e",
            "name": "5th Edition",
            "desc": "Original 5E.",
            "content_prefix": ""
        },
        "name": "Systems Reference Document"
    },
    "name": "Magic Missile"
}
  1. Deeply nested returned fields can be excluded by prefixing multiple nested fields seperated by double underscores. eg. documents__gamesystem__fields=name (link)
# v2/spells/srd_magic-missile/?fields=name,document&depth=2&document__fields=name,gamesystem&document__gamesystem__fields=name

{
    "document": {
        "gamesystem": {
            "name": "5th Edition"
        },
        "name": "Systems Reference Document"
    },
    "name": "Magic Missile"
}

Other changes

The changes to the other serializer files were to make sure that the Document field is correctly configured on the other serializers to inherit from the GameContentSerializer.

The changes made to v2/views/spells.py were made to preserve functionality of PR #592. Which previously had used the Meta field to access the depth property. This is now accessed via the request object instead.

Test are failing

This is beacuse that updating the Serializer has altered the representation of data that some endpoints return when no query parameters are added. These are simple fixes, but it felt a little permature to change the tests so that this PR pasted without first discussing with the other developer

@augustjohnson augustjohnson self-assigned this Nov 7, 2024
@augustjohnson
Copy link
Collaborator

This works as expected locally. I'm liking it a lot.
The non-fields based changes are all approved too, those make sense to me using this format moving forward. Go ahead and fix the tests and resubmit. Nice work.

@calumbell calumbell merged commit 8733d54 into open5e:staging Nov 9, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants