Allow a subordinate entry resource under a resource where there would normally be a field

Bug #387487 reported by Leonard Richardson
14
This bug affects 2 people
Affects Status Importance Assigned to Milestone
Launchpad itself
Fix Released
High
Barry Warsaw
lazr.restful
Fix Released
High
Barry Warsaw

Bug Description

We've designed our field resources based around the example of IBug.owner. Every bug has an owner but the owner can be any person at all. It makes sense to get bugs/1/owner to find out who the owner is, or PUT bugs/1/owner to change the owner.

But there's another use case, exemplified by IBranch.code_import. A code import has no existence independent of its branch. The most logical absoluteURL for an ICodeImport is /branches/[branch name]/code_import. But under the current system, that spot is already taken by a field resource. If you GET the field resource it will tell you where the ICodeImport is, but that URL will never change, because one ICodeImport is forever associated with one IBranch.

It would make more sense if /branches/[branch name]/code_import designated a subordinate entry resource instead of a field resource.

In the meantime, a workaround: if you're in this situation there's a one-to-one relationship between the parent resource (IBranch) and the subordinate (ICodeImport). Do they really need to be separate resources just because they're separate in the underlying application? Maybe it makes sense to give IBranch the fields of ICodeImport and delegate reads and writes to the underlying object.

Tags: lp-registry

Related branches

Revision history for this message
Francis J. Lacoste (flacoste) wrote :

AFIACT, this is already supported. You just have to make sure that the web application can traverse to <branch>/code_import. Field navigation only kicks in after the regular web application traversal has taken place.

So adding the proper navigation to Branch to get to code_import would be work.

Revision history for this message
Leonard Richardson (leonardr) wrote :

This already works, if you have the navigation for it. The problem that led me to file this bug was a lack of navigation.

Changed in lazr.restful:
status: New → Invalid
Revision history for this message
Barry Warsaw (barry) wrote :

I'm uninvalidating this because I'm having exactly the same problem. Mailing lists are subordinate to teams, so it makes sense to access them through ~myteam/mailing_list. But this only returns that url back to me and I cannot get a MailingList as an entry, which is really what I want.

I do not want to expose mailing list properties on the IPerson, so I need to fix this.

Changed in lazr.restful:
status: Invalid → Triaged
Revision history for this message
Barry Warsaw (barry) wrote :

Bug 385180 is blocked on this.

Curtis Hovey (sinzui)
Changed in launchpad-registry:
importance: Undecided → Low
status: New → Triaged
Revision history for this message
Barry Warsaw (barry) wrote :

So, I'm having a very difficult time creating a lazr.restful test for this problem. I have a test case and a code fix for Launchpad, but I'm in a twisty maze of hurt trying to reproduce the problem in lazr.restful itself.

What I have so far: lp:~barry/lazr.restful.387487-subordinate

but it sucks :(

However, in src/lazr/restful/publisher.py, the following code fixes the
problem:

    def traverseName(self, request, ob, name):
        """See `zope.publisher.interfaces.IPublication`.

        In addition to the default traversal implementation, this publication
        also handles traversal to collection scoped into an entry.
        """
        # If this is the last traversal step, then look first for a scoped
        # collection. This is done because although Navigation handles
        # traversal to entries in a scoped collection, they don't usually
        # handle traversing to the scoped collection itself.
        if len(request.getTraversalStack()) == 0:
            try:
                entry = IEntry(ob)
            except TypeError:
                pass
            else:
                field = entry.schema.get(name)
                if ICollectionField.providedBy(field):
                    result = self._traverseToScopedCollection(
                        request, entry, field, name)
                    if result is not None:
                        return result
                elif IBytes.providedBy(field):
                    return self._traverseToByteStorage(
                        request, entry, field, name)
                elif IObject.providedBy(field):
                    sub_entry = getattr(entry, name, None)
                    if sub_entry is None:
                        raise NotFound(ob, name, request)
                    else:
                        return sub_entry
                elif field is not None:
                    return EntryField(entry, field, name)
                else:
                    # Falls through to our parent version.
                    pass
        return super(WebServicePublicationMixin, self).traverseName(
            request, ob, name)

Note the new goodness in the "elif IObject" stanza.

Revision history for this message
Curtis Hovey (sinzui) wrote : Re: [Bug 387487] Re: Allow a subordinate entry resource under a resource where there would normally be a field

On Fri, 2009-07-24 at 15:46 +0000, Barry Warsaw wrote:
> So, I'm having a very difficult time creating a lazr.restful test for
> this problem. I have a test case and a code fix for Launchpad, but I'm
> in a twisty maze of hurt trying to reproduce the problem in lazr.restful
> itself.
>
> What I have so far: lp:~barry/lazr.restful.387487-subordinate
>
> but it sucks :(
>
> However, in src/lazr/restful/publisher.py, the following code fixes the
> problem:
>
> def traverseName(self, request, ob, name):
...
> elif IObject.providedBy(field):
> sub_entry = getattr(entry, name, None)
> if sub_entry is None:
> raise NotFound(ob, name, request)
> else:
> return sub_entry
...

I think you want to update WadlAPITestCase to add a suborinate interface
to verify the wadl is correct.

Travering is tested in doc/webservice.txt. I think you want to add a
subordinate object to the test objects (ingredient, instructions,
wine_pairing). There is some URL tests that verify objects are found.
These tests deal with PATCH, but GET can be added.

Barry Warsaw (barry)
Changed in lazr.restful:
status: Triaged → Fix Committed
importance: Undecided → High
status: Fix Committed → Fix Released
Barry Warsaw (barry)
Changed in launchpad-registry:
status: Triaged → Fix Released
assignee: nobody → Barry Warsaw (barry)
Changed in lazr.restful:
assignee: nobody → Barry Warsaw (barry)
milestone: none → 0.9.2
Changed in launchpad-registry:
importance: Low → High
milestone: none → 2.2.8
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.