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

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 join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants