Overview

    Properties offer a way to associate a page/user/attachment/the whole wiki with content-agnostic data that can then be retrieved and consumed by the front end or any client of the Deki API. Data is uniquely identified by the parent resource (page id/user id/file id) and by the name of the property.

    • No maximum length or content type of a property value is enforced. (A mediumblob field of 16,777,215 bytes is used)

    • Batch save API call allows multiple properties to be saved for a given resource in one request while reporting back on individual errors and status codes.
    • Page permissions are used to determine if a property can be viewed or written. Users can always modify their own properties.
    • Optimistic concurrency is used to ensure that updates are always done on top of the HEAD revision

    Property XML

    <property name="foo" href="http://og/@api/deki/pages/15126/properties/foo/info" etag="...">
            <revisions count="1" href="http://og/@api/deki/pages/15126/properties/foo/revisions"/>
            <contents type="text/plain; charset=iso-8859-1" href="http://og/@api/deki/pages/15126/properties/foo">Some content</contents>
            <date.modified>2008-11-03T20:54:27Z</date.modified>
            <user.modified id="1465" href="http://og/@api/deki/users/1465">
                <!-- user details -->
            </user.modified>
        </property>

    Integration with Permissions

    Modifying your user properties
    • Users can view all properties, their revisions, and content for properties associated with their user account.
    • Users can write properties associated with their user account with the exception of Anonymous user who has no write access.
    Page and attachment properties
    • Users require UPDATE rights to a page in order to modify its or its attachments' properties.
    Future ideas and thoughts
    • Each property may have its own ACL's associated with it.

    Optimistic Concurrency

    Just like the API ensures that page updates were performed on top of the latest page content to avoid overwriting someone elses changes, similar logic is necessary for properties.

    A standard etag header is returned with the property contents. The property XML contains an 'etag' attribute on the property element.

    Property Updates

    An etag can be included via the standard 'ETag' http header or the 'etag' query parameter when PUT'ing content on a single existing property. The batch PUT operation can accept the etag as an xml attribute on the 'property' element.

    Mismatched etag

    If the provided etag doesn't match the property's current etag then the operation fails with a status 409 - Conflict.

    Q: is a valid etag necessary when deleting a singular property or via a batch PUT? 

    Currently: Delete operation doesn't require an etag.

    Search and Indexing

    Indexing of properties is implemented as of MindTouch 9.12. Refer to the property search spec for more details and future direction.

    Versioning

    Versioning of properties is not yet supported. The data model has full support for it and the revision history is maintained but no API interface is exposed to see the history or to retrieve older items. This will be supported as soon as good use cases are revealed needing this functionality. One thing that is implemented regarding versioning is viewing a parent resource at a revision will show the property versions that were associated at the time.

    API Features

    Symmetric interface for pages, users, attachments, site. (replace users with pages and files below)

    • GET:users & GET:users/{id} return a <properties> element that contains the equivalent of get:users/{id}/properties
    • Only specific content types get displayed within the properties xml. This only includes contenttypes of plain/text (ascii or utf8). Others require an explicit get: users/{id}/properties/{key}. Properties over a given length (5k?) will not have their content returned within the property xml block.

    GET: users/{id}

    <user>    
        <!-- User info  -->
        <properties count=1 href="users/x/properties">
            <property name="foo" href="users/x/properties/foo" etag="...">
                <!-- property details here-->
            </property>
        </properties>
    </user>


    GET: users/{id}/properties

    Retrieve full list of properties at head revision for the resource. Property contents is embedded within the xml if it fits the length and content type requirement

    <properties count="2">
        <property name="foo" href="http://og/@api/deki/pages/15126/properties/foo/info" etag="...">
            <contents type="text/plain; charset=iso-8859-1" href="http://og/@api/deki/pages/15126/properties/foo">Some content</contents>
            <date.modified>2008-11-03T20:54:27Z</date.modified>
            <user.modified id="1465" href="http://og/@api/deki/users/1465">
                <!-- user details -->
            </user.modified>
        </property>
        <property name="bar" href="http://og/@api/deki/pages/15126/properties/bar/info" etag="...">
            <contents type="text/plain; charset=iso-8859-1" href="http://og/@api/deki/pages/15126/properties/bar">Some content</contents>
            <date.modified>2008-11-03T20:54:27Z</date.modified>
            <user.modified id="1465" href="http://og/@api/deki/users/1465">
                <!-- user details -->
            </user.modified>
        </property>
    </properties>


    GET: users/{id}/properties/{key}

    {property content}

    GET: users/{id}/properties/{key}/info

     Retrieve property info

    <property name="foo" href="http://og/@api/deki/pages/15126/properties/foo/info" etag="...">
            <contents type="text/plain; charset=iso-8859-1" href="http://og/@api/deki/pages/15126/properties/foo">Some content</contents>
            <date.modified>2008-11-03T20:54:27Z</date.modified>
            <user.modified id="1465" href="http://og/@api/deki/users/1465">
                <!-- user details -->
            </user.modified>
        </property>

    PUT: users/{id}/properties/{key}

    Used for updating the content of a single property with data of any type. Creating new properties with this feature is not allowed and will return a '400 Bad Request'.

    Request: New content for the property and etag (via header or query parameter) for optimistic concurrency

    Response: Status 200 and the property info

    <property name="foo" href="http://og/@api/deki/pages/x/properties/foo/info" etag="...">
            <contents type="text/plain" href="http://og/@api/deki/pages/x/properties/foo">Some value</content>
            <date.modified>2008-11-03T20:54:27Z</date.modified>
            <user.modified id="1465" href="http://og/@api/deki/users/1465">
                <!-- user details -->
            </user.modified>
    </property>

    A status '409 Conflict' may be returned if the etag did not match.

    POST: users/{id}/properties

    Allows adding a single new property to a resource of any type. This may not be used for updating an existing property. The slug header must be used to indicate the name of the property. If the name already exists a status 409 Conflict is returned. A description is provided via the 'description' query parameter.

    Request:

    POST /@api/deki/users/x/properties?description=description of foo
    Host: wikihost
    Slug: foo
    Content-Type: image/jpg
    Content-Length: 6730
    
    ... data here ...
    

    Response:

    Status code "200 Ok" with the standard property info body.

    <property name="foo" href="http://og/@api/deki/pages/x/properties/foo/info" etag="...">
            <contents type="image/jpg" href="http://og/@api/deki/pages/x/properties/foo"/>
            <date.modified>2008-11-03T20:54:27Z</date.modified>
            <user.modified id="1465" href="http://og/@api/deki/users/1465">
                <!-- user details -->
            </user.modified>
    </property>

     

    PUT: users/{id}/properties

    Allows batch properties operations including adding new properties, updating existing properties, and deleting properties. Adding or updating properties with content of only plain/text is allowed here.

    Request:

    <properties>
        <property name="foo" etag="...">
            <contents type="text/plain">Some value</contents>
        </property>
        <property name="bar">
            <contents/>
        </property>
    </properties>

    In the above example, the foo property will be updated (since an etag is provided). Since no content is provided for bar, it will be deleted.

    Response

    <properties count="2">
        <property name="foo" href="http://og/@api/deki/users/x/properties/foo/info">
            <status code="200"/>
            <contents type="text/plain">Some value</contents>
            <date.modified>2008-11-03T20:54:27Z</date.modified>
            <user.modified id="1465" href="http://og/@api/deki/users/1465">
                <!-- user details -->
            </user.modified>
        </property>
        <property name="bar" href="http://og/@api/deki/users/x/properties/bar/info">
            <status code="200"/>
            <contents/>
            <user.deleted id=1> 
                <!-- user details -->
            </user.deleted>    
            <date.deleted>2008-11-03T20:54:27Z</date.deleted>
        </property>
    </properties>

     

    DELETE: users/{id}/properties/{key}  

    Mark a property as deleted

    DB Model / Storage

    The generalized resource datastore is used for properties.  Reasons for this:

    • Don't create additional tables, sql, specialized logic for properties.
    • Inherit all functionality associated with resources (what are pages now) such as versioning, moving, hierarchy, etc
    • Will allow granular permission control in the same way as pages.
    • Allows the generalized resource code/model to be used and debugged before other types of content is migrated over

    Current work items

    • Standard paging/limits/offsets
    • Default value for contenttype on a put (if it's missing)
    • Integration with Lucene
    • Permissions integration

     

    Feature requests

    • Allow properties to be set when creating (or updating?) the parent resource such as a user or page.
    • Add short xml output when retrieving a property from the parent resource. e.g. when retrieving a user's properties don't show the user.modified information.

    Currently Implemented Properties

    Keys are prefixed with namespaces. Here are the current namespaces.

    // user specified keys
        const NS_CUSTOM = 'urn:custom.mindtouch.com#';
    
        // application specified keys
        const NS_DEKI = 'urn:deki.mindtouch.com#';
    
        // ui specific keys for html & css
        const NS_UI = 'urn:ui.deki.mindtouch.com#';
    
        // general meta namespace, not application dependent
        const NS_META = 'urn:meta.deki.mindtouch.com#';
    Tag page
    You must login to post a comment.

    Copyright © 2011 MindTouch, Inc. Powered by