Skip to content
This repository has been archived by the owner on Jun 6, 2024. It is now read-only.

marshmallow-jsonapi tries to build self links, even if id is None #249

Open
multimeric opened this issue Aug 29, 2019 · 3 comments
Open

Comments

@multimeric
Copy link

I have the following (simplified) schema:

class SampleFilterSchema(Schema):
    class Meta:
        type_ = "sample_filter"
        self_view = 'rest_api.filter'
        self_view_many = 'rest_api.filterlist'
        self_view_kwargs = {
            'sample_id': '<id>'
        }

    id = fields.String(attribute='sample_filter_id', allow_none=True)
    tag = fields.String(attribute='sample_filter_tag')

I'm writing unit tests for my REST API, and thus I want to generate some sample data, dump it using this schema, send it in a POST request, and check that everything works. However, because I am constructing new data here, I naturally have no id for this field. This is accepted by the JSON API spec, in a request, although not a response. However, when dumping, marshmallow-jsonap still tries to construct the self links, and thus tries to use the id field (which is None), and I end up with this error:

Traceback (most recent call last):
  File "/home/michael/Programming/MegaQC/tests/api/test_api.py", line 89, in test_post_resource
    request = schema(many=False, exclude=['user']).dump(instance)
  File "/home/michael/Programming/MegaQC/venv/lib/python3.6/site-packages/marshmallow/schema.py", line 545, in dump
    POST_DUMP, result, many=many, original_data=obj
  File "/home/michael/Programming/MegaQC/venv/lib/python3.6/site-packages/marshmallow/schema.py", line 993, in _invoke_dump_processors
    tag, pass_many=True, data=data, many=many, original_data=original_data
  File "/home/michael/Programming/MegaQC/venv/lib/python3.6/site-packages/marshmallow/schema.py", line 1122, in _invoke_processors
    data = processor(data, many=many, **kwargs)
  File "/home/michael/Programming/MegaQC/venv/lib/python3.6/site-packages/marshmallow_jsonapi/schema.py", line 135, in format_json_api_response
    ret = self.format_items(data, many)
  File "/home/michael/Programming/MegaQC/venv/lib/python3.6/site-packages/marshmallow_jsonapi/schema.py", line 394, in format_items
    return self.format_item(data)
  File "/home/michael/Programming/MegaQC/venv/lib/python3.6/site-packages/marshmallow_jsonapi/schema.py", line 381, in format_item
    links = self.get_resource_links(item)
  File "/home/michael/Programming/MegaQC/venv/lib/python3.6/site-packages/marshmallow_jsonapi/schema.py", line 414, in get_resource_links
    ret["self"] = self.generate_url(self.opts.self_url, **kwargs)
  File "/home/michael/Programming/MegaQC/venv/lib/python3.6/site-packages/marshmallow_jsonapi/flask.py", line 74, in generate_url
    return flask.url_for(view_name, **kwargs) if view_name else None
  File "/home/michael/Programming/MegaQC/venv/lib/python3.6/site-packages/flask/helpers.py", line 356, in url_for
    return appctx.app.handle_url_build_error(error, endpoint, values)
  File "/home/michael/Programming/MegaQC/venv/lib/python3.6/site-packages/flask/app.py", line 2061, in handle_url_build_error
    reraise(exc_type, exc_value, tb)
  File "/home/michael/Programming/MegaQC/venv/lib/python3.6/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/home/michael/Programming/MegaQC/venv/lib/python3.6/site-packages/flask/helpers.py", line 345, in url_for
    force_external=external)
  File "/home/michael/Programming/MegaQC/venv/lib/python3.6/site-packages/werkzeug/routing.py", line 1776, in build
    raise BuildError(endpoint, values, method, self)
werkzeug.routing.BuildError: Could not build url for endpoint 'rest_api.filter'. Did you forget to specify values ['filter_id']?

Is there any way to skip link generation when there is no id? Or any way to skip link generation at all? I think it would be nice to have some kind of flag that tells marshmallow that this schema is for creating a request, and so to dump a simplified version of the data, without relationships and links and IDs and such.

@multimeric
Copy link
Author

multimeric commented Aug 29, 2019

Here's an easy workaround:

class OptionalLinkSchema(Schema):
    def __init__(self, use_links=True, *args, **kwargs):
        self.use_links = use_links
        super().__init__(*args, **kwargs)

    def get_resource_links(self, item):
        if not self.use_links:
            return None
        return super().get_resource_links(item)

Then you can inherit from OptionalLinkSchema, and do:

data = MySchema(use_links=False).dump(instance)

@sloria
Copy link
Member

sloria commented Sep 5, 2019

I would review/merge a PR for this. I imagine the solution will be similar to https://github.com/marshmallow-code/flask-marshmallow/pull/125/files

@multimeric
Copy link
Author

Excellent. I'll look into it when I get some time.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants