Index: trunk/Bookmark.pm
===================================================================
--- trunk/Bookmark.pm	(revision 24)
+++ trunk/Bookmark.pm	(revision 25)
@@ -1,10 +1,34 @@
 package Bookmark;
 
-use Class::Accessor qw{antlers};
+use Moose;
 
-has id    => ( is => 'ro' );
-has uri   => ( is => 'ro' );
-has ctime => ( is => 'ro' );
-has mtime => ( is => 'ro' );
+has id    => ( is => 'rw' );
+has uri   => ( is => 'rw' );
+has title => ( is => 'rw' );
+has ctime => ( is => 'rw' );
+has mtime => ( is => 'rw' );
+has tags  => ( is => 'rw' );
+has bookmark_uri => ( is => 'rw' );
+
+sub BUILD {
+    my $self = shift;
+    my $args = shift;
+    if ($args->{base_uri}) {
+        $self->bookmark_uri(URI->new_abs($self->id, $args->{base_uri}));
+    }
+}
+
+sub TO_JSON {
+    my $self = shift;
+    return {
+        id    => $self->id,
+        uri   => $self->uri,
+        title => $self->title,
+        ctime => $self->ctime,
+        mtime => $self->mtime,
+        tags  => $self->tags,
+        ($self->bookmark_uri ? (bookmark_uri => $self->bookmark_uri->canonical->as_string) : ()),
+    };
+}
 
 # module return
Index: trunk/BookmarkApp.pm
===================================================================
--- trunk/BookmarkApp.pm	(revision 24)
+++ trunk/BookmarkApp.pm	(revision 25)
@@ -90,5 +90,5 @@
         );
         return decode_utf8(
-            encode_json({
+            JSON->new->utf8->convert_blessed->encode({
                 bookmarks => \@resources,
             })
Index: trunk/Bookmarks.pm
===================================================================
--- trunk/Bookmarks.pm	(revision 24)
+++ trunk/Bookmarks.pm	(revision 25)
@@ -8,4 +8,11 @@
 has dbh      => ( is => 'rw' );
 has base_uri => ( is => 'ro', isa => 'URI' );
+
+has _sth_tags_from_uri => (
+    is       => 'ro',
+    init_arg => undef,
+    lazy     => 1,
+    default  => sub { $_[0]->dbh->prepare('select tag from tags where uri = ? order by tag'); },
+);
 
 sub BUILD {
@@ -29,4 +36,6 @@
     my $self = shift;
     my $params = shift;
+
+    # look for bookmark by id or uri
     my $sth;
     if ($params->{id}) {
@@ -40,13 +49,11 @@
     }
     my $bookmark = $sth->fetchrow_hashref;
-    if ($bookmark) {
-        my $sth_tag = $self->dbh->prepare('select tag from tags where uri = ? order by tag');
-        $sth_tag->execute($bookmark->{uri});
-        $bookmark->{tags} = [ map { $$_[0] } @{ $sth_tag->fetchall_arrayref } ];
-        if ($self->base_uri) {
-            $bookmark->{bookmark_uri} = URI->new_abs($bookmark->{id}, $self->base_uri);
-        }
-    }
-    return $bookmark;
+    return unless $bookmark;
+
+    return Bookmark->new({
+        %$bookmark,
+        tags     => [ $self->get_tags({ uri => $bookmark->{uri} }) ],
+        base_uri => $self->base_uri,
+    });
 }
 
@@ -85,13 +92,11 @@
     $sth_resource->execute(@bind);
 
-    my $sth_tag = $self->dbh->prepare('select tag from tags where uri = ? order by tag');
     my @resources;
     while (my $resource = $sth_resource->fetchrow_hashref) {
-        $sth_tag->execute($resource->{uri});
-        $resource->{tags} = [ map { $$_[0] } @{ $sth_tag->fetchall_arrayref } ];
-        if ($self->base_uri) {
-            $resource->{bookmark_uri} = URI->new_abs($resource->{id}, $self->base_uri);
-        }
-        push @resources, $resource;
+        push @resources, Bookmark->new({
+            %$resource,
+            tags     => [ $self->get_tags({ uri => $resource->{uri} }) ],
+            base_uri => $self->base_uri,
+        });
     }
     return @resources;
@@ -101,9 +106,16 @@
     my $self = shift;
     my $params = shift;
-    my $tag = $params->{selected};
-    my $sth_all_tags = $self->dbh->prepare('select tag, count(tag) as count, tag = ? as selected from tags group by tag order by tag');
-    $sth_all_tags->execute($tag);
-    my $all_tags = $sth_all_tags->fetchall_arrayref({});
-    return @{ $all_tags };
+    if (my $uri = $params->{uri}) {
+        # get the tags for a particular URI
+        $self->_sth_tags_from_uri->execute($uri);
+        return map { $$_[0] } @{ $self->_sth_tags_from_uri->fetchall_arrayref };
+    } else {
+        # return all tags
+        my $tag = $params->{selected};
+        my $sth_all_tags = $self->dbh->prepare('select tag, count(tag) as count, tag = ? as selected from tags group by tag order by tag');
+        $sth_all_tags->execute($tag);
+        my $all_tags = $sth_all_tags->fetchall_arrayref({});
+        return @{ $all_tags };
+    }
 }
 
