Code Monkey home page Code Monkey logo

drf-hal-json's People

Contributors

cirotix avatar cknave avatar claytondaley avatar jakubartory avatar jstaffans avatar matheusbsilva avatar pyup-bot avatar seebass avatar webjunkie avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

drf-hal-json's Issues

drf-nested-routers interoperability

I'm using alanjds/drf-nested-routers to support nested paths like:

/patients/{patient_pk}/events/

When I use a HAL serializer in these nested views, the self link isn't generated correctly. I'm able to work around the issue by manually defining self:

self = HalHyperlinkedIdentityField(
    view_name='event-detail',
)

Is there a canonical way to be handling this? Do I need to be implementing some specific method? Should this be working "out of the box"?

Include BrowsableAPIRenderer in Example code

(relocated from seebass/drf-hal-json#7)

I'm reasonably familiar with DRF and was confused by the loss of the DRF Browsable API when I followed the README example. I wasn't familiar with the setting so I ended up deleting the DEFAULT_RENDERER_CLASSES entry to "fix" things.

I suggest including BrowsableAPIRenderer in the README example to replicate stock DRF as closely as possible. Any user who has removed BrowsableAPIRenderer will know to do the same when presented with your example. However, it won't cause unexpected behavior for users who have not modified the DRF default.

Link vs. Link Contribution vs. Embedded

I built a serializer that would accept a full, nested representation for a model and create an instance for that representation. Once the representation existed, it made sense to return a _links entry for that instance. To do this, I wrapped a Serializer with a class that (in to_representation) extracted serialized[LINKS_FIELD_NAME][URL_FIELD_NAME] and inherited from HalIncludeInLinksMixin to get it put in links.

Unfortunately, this nested serializer matches both _is_link_field and _is_embedded_field. This is a problem because to_representation uses pop on link_field_names so the field is absent by the time embedded_field_names tries to access it (i.e. KeyError).

I'm looking for feedback on the situation:

  • Are asymmetric serializers anti-pattern? Should I have a separate read and write serializer? Or is it even anti-pattern to use asymmetric serializers on a view? For example, the RFC says:

    A successful PUT of a given representation would suggest that a subsequent GET on that same target resource will result in an equivalent representation being sent in a 200 (OK) response.

    At least for the sake of argument, I submit that a _links entry is "equivalent" (they did not say "identical") to the original, embedded resource.

  • If an asymmetric serializer like this is reasonable, we could improve _is_embedded_field, is_link_field, and is_link_contribution_field to ensure a field never matches more than one.

    • We would need to agree on a priority in the event of conflicts. In my case, (1) link, (2) link contribution, and (3) embedded makes sense, but maybe not in a broader analysis.
  • Other suggestions?

Asymmetric Serialization

In #64, I created test cases to illustrate the problem. Long story short, I believe it should be possible to PUT the body of a GET to the same endpoint in the default case. This does not work because drf-hal-json returns a JSON object but (seems to) expect stringified JSON.

`self` and query parameters

To avoid getting the API Browser pages, I used the format query parameter in DRF (e.g. http://localhost:8085/api/tasks/4/?format=json). While it looks like including query parameters can be valid, the format parameter does not uniquely identify the resource. I do not therefore believe it should be included.

Because other query parameters are allowed, we probably ought to exclude this one explicitly. I realize the issue is minor, but I think it's more important that HAL actually comply with the associated specification than (say) DRF.

Pagination links when there is only one page

"_links": {
    "self": {
      "href": "http://localhost:8000/api/v1/customers"
    },
    "next": {
      "href": null
    },
    "previous": {
      "href": null
    }
  }

It would make more sense to leave out the next and previous relations entirely, if there are no links.

HyperlinkedRelatedField with None

Currently:

{
   "_links": {
    "some_relation": {"href": null}
  }
}

Should maybe be:

{
   "_links": {
    "some_relation":  null
  }
}

or dropped altogether.

SlugRelatedField and _links

SlugRelatedField is getting put into the _links section even if it's not a URI (let alone a valid one).

I'm using the SlugRelatedField to extract the name of a Django group. I need the group name to tell a user who's responsible for a task (if that user is not). The groups are not available over REST so it doesn't make sense to represent them as a linkable resource. As far as REST is concerned, the slug is just an attribute of the object.

While SlugRelatedField could be used to pick a URI off an object, this behavior is not the appropriate default. Instead, I believe this feature should require a dedicated class asserting that it's representing a UriSlugRelatedField.

Add an explicit "self" field in HalModelSerializer?

My workaround for #18 was to manually declare the self field on the serializer:

self = HalHyperlinkedIdentityField(
    view_name='event-detail',
)

I also wanted to display only that field so I set fields = ['self']. Out of curiosity, I tried limiting another serializer to just self and got an error that it was not declared on the serializer.

Is there always a better way to get a link-only representation so fields = ['self'] is anti-pattern? Or is this a reasonable thing to do in some circumstance that the HalModelSerializer should explicitly declare this field (technically URL_FIELD_NAME) so it can be included in fields?

FWIW due to error checking code, the HalModelSerializer would also need a Meta.fields that includes this value.

Detached Fork

FYI. A common way to find an active version of a library is to look at the "fork" tree. This package isn't attached so even I sometimes have trouble finding it. I imagine you detached it intentionally, but I'd like to at least draw attention to one big disadvantage.

Handling a HalContributeToLinkField that returns None

I'm trying to conditionally display a HalContributeToLinkField. I tried returning None from the getter on the serializer figuring that None might be suppressed. Instead it was displayed and set to null.

I don't think creating a null is the right behavior here because it makes HAL-invalid JSON (if I understand HAL correctly). I'm not necessarily arguing that it should be suppressed (thought it would have been convenient). For example, it'd be reasonable to throw an error instead.

rel naming

While working on #20, I had to figure out the appropriate rel name (i.e. key) for a collection. This package hard-codes the word items in several locations (e.g. here). This is reasonably consistent with DRF's hard coding of "results". However, I'd like to express a series of opinions in increasing degrees of complexity:

  1. I stumbled on a case for calling it item instead of items. While the thread acknowledges that the spec is indeterminate and the spec's examples actually deviate, I think the OP is right to argue for non-plural names for collections of single items and plural names for links to collections endpoints themselves.

  2. I don't think we should hard code the name inline. _links and _embedded are both defined by the specification (i.e. immutable) and the package still uses centralized "constants".

  3. At minimum, I think we should permit a package-level configuration.

  4. Even better, I think this should be configurable using a serializer-level Meta configuration.

  5. I see a case for generating the name dynamically. While the list is a list of abstract items, it's really a named relation. The relation is not to an abstract items but to a specific type of item. It may be the case that pure-HAL should be able to deduce the type from that rel name.

While this is not a critical issue, it would produce a breaking change in the future so this is an especially good opportunity to make a change if any of the above were persuasive.

Use backwards compatible super() calls

I tried the current version of master on a py2.7 project and had issues with the empty super calls. I'll put together a PR, but want to draw attention to the issue to help avoid additional instances from being introduced in active branches.

HyperlinkRelated Query Params

Has anyone else run into a use case for a field (like HyperlinkRelatedField) that uses query params to return (only) the related items?

As a toy example, consider a list of Projects and their related Tasks. For a variety of reasons, I've been getting a list of Project Tasks through an endpoint like /projects/#/tasks. A Project's _links will include this URI. When accessed, each embedded item's self points to /tasks/#/ so the singletons have only one proper URI. This has worked out great because I can populate a HyperlinkedRelatedField using drf-nested-routers and a syntax like:

    tasks = HalHyperlinkedRelatedField(
        view_name='project-task-list',
        read_only=True,
        lookup_url_kwarg='project_pk',
        source='pk'
    )

I recently ran into a situation where it would have been more convenient to link the tasks using a URI like /tasks/?project=#. From what I've read, a URI is opaque so there's no HATEOAS reason to prefer one to the other. In fact, the query params approach may be simpler in more complicated subsets like "incomplete tasks" (/projects/#/tasks?status=incomplete is equivalent but requires support for two kinds of filtering).

I can set up DRF's filters to support this URI, but there doesn't appear to be an existing serializer field to build a URI like this. I've worked around the issue in my specific case, but am curious if anyone else has had use of a field like this (or is aware of a better, general-purpose solution).

Adding semantically meaningful `_links` to a Collection endpoint

Consider a collection URL like:

/parents/{id}/childs

In a HATEOAS world, it makes sense (to me anyway) for this collection to include a _links entry to navigate back to its parent. Since the link should be accessible even if the collection is empty, it would need to be included in the collection's _links (vs. singleton _links). I don't believe there's anything in DRF that is comparable. The closest are the links in Pagination but they're hard-coded into the Pagination class (i.e. not customizable on a per-type basis).

I contributed a HalListSerializer to this project. It seems to me that the HalListSerializer is the "right" to do this because a custom ListSerializer can be nested inside each (singleton) Serializer (even though uses rarely do). The default implementation of ListSerializer does not support serializer fields on the ListSerializer, but I could adapt our local implementation to make it possible.

Please note that Pagination classes already conflict/compete with the ListSerializer for creating a top-level representation. It may be necessary (even advisable) to rewrite the Hal pagination classes to just add/inject _links entries into the HalListSerializer (which already nests the serializer's response under _embedded['items']).

Thoughts?

Non-Model HalSerializer

I have a custom Serializer that is not a ModelSerializer. I need to incorporate HAL formatting (e.g. to_representation, but don't want/need the ModelSerializer dependendencies (which are not compatible).

It's been ages since I was in this code. Does anyone know if there are hard(ish) ModelSerializer dependencies? Or if this was just a quirk of original use case?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.