]> git.ktnx.net Git - lsl.git/blobdiff - lib/App/LazyShoppingList/API/v1.pm
version is mandatory when updating a list
[lsl.git] / lib / App / LazyShoppingList / API / v1.pm
index 6e1cd3138a8b4a474dd5323c90e0912e974627bc..f65fd42787171a823eb8790de07d6f11efdbb80d 100644 (file)
@@ -13,9 +13,22 @@ use JSON();
 use experimental 'signatures';
 
 set charset      => 'UTF-8';
-set serializer   => 'JSON';
-set content_type => 'application/json';
+set serializer => 'JSON';
 
+hook before_request => sub {
+    get_database->txn_begin;
+};
+
+hook after_request => sub {
+    my $dbh = get_database;
+
+    if (response->status =~ /^5/) {
+        $dbh->txn_rollback;
+    }
+    else {
+        $dbh->txn_commit;
+    }
+};
 
 # get the URI for the list of shopping lists
 get '/' => sub {
@@ -25,7 +38,6 @@ get '/' => sub {
 # get the list of shopping lists
 get '/list' => sub {
     my $dbh = get_database;
-    $dbh->txn_begin;
 
     my %r = ( lists_version => get_lists_version($dbh), lists => [] );
     for my $list (
@@ -34,34 +46,29 @@ get '/list' => sub {
             { order_by => { -asc => 'name' } } )->all
         )
     {
-        push @{ $r{lists} }, uri_for( "/list/" . $list->id );
+        push @{ $r{lists} },
+            { uri => uri_for( "/list/" . $list->id ), name => $list->name };
     }
 
-    $dbh->txn_commit;
     return \%r;
 };
 
 # create shopping list
 post '/list' => sub {
-    my $req = decode_json(request_data);
+    my $req = request_data;
 
     my $name = $req->{name};
     unless ($name) {
-        status 400;
-        content_type 'text/plain';
-        return "Missing list name";
+        return exception 400, "Missing list name";
     }
 
     my $dbh = get_database;
-    $dbh->txn_begin;
     my $list = $dbh->resultset('ShoppingList')->create({
             name => $name});
     $list->discard_changes;
 
     my  $lists_ver = increment_lists_version($dbh);
 
-    $dbh->txn_commit;
-
     return {
         uri           => uri_for( '/list/' . $list->id ),
         version       => $list->version,
@@ -78,23 +85,21 @@ get '/list/:list_id' => sub {
 
     warn $dbh;
     my %r = ( items => [] );
-    $dbh->txn_begin;
 
     $r{lists_version} = get_lists_version($dbh);
 
     my $list = $dbh->resultset('ShoppingList')->find($list_id);
 
     unless ($list) {
-        $dbh->txn_commit;
-        status 404;
-        content_type 'text/plain';
-        return "No list with that ID found";
+        return exception 404, "No list with that ID found";
     }
 
     $r{version} = $list->version;
 
-    my @items = $dbh->resultset('ShoppingListItem')
-        ->search( undef, { order_by => { -asc => 'id' } } )->all;
+    my @items = $dbh->resultset('ShoppingListItem')->search(
+        { shopping_list => $list->id },
+        { order_by      => { -asc => 'id' } }
+    )->all;
     for my $item (@items) {
         push @{ $r{items} },
             {   uri =>
@@ -105,8 +110,6 @@ get '/list/:list_id' => sub {
             };
     }
 
-    $dbh->txn_commit;
-
     return \%r;
 };
 
@@ -116,13 +119,12 @@ post '/list/:id' => sub {
     length($list_id) and $list_id =~ /^\d{1,18}$/
         or return invalid_input('bad list ID');
 
-    my $req = decode_json(request_data);
+    my $req = request_data;
 
     my $descr = $req->{description};
     my $done  = JSON->boolean( $req->{done} // 0 );
 
     my $dbh = get_database;
-    $dbh->txn_begin;
 
     my %r = (
         lists_version => get_lists_version($dbh),
@@ -131,10 +133,7 @@ post '/list/:id' => sub {
     my $list = $dbh->resultset('ShoppingList')->find($list_id);
 
     unless ($list) {
-        $dbh->txn_commit;
-        status 404;
-        content_type 'text/plain';
-        return "No such list";
+        exception 404, "No such list";
     }
 
     my $item = $dbh->resultset('ShoppingListItem')->create(
@@ -151,8 +150,6 @@ post '/list/:id' => sub {
     $r{version} = $item->version;
     $r{list_version} = $list->version;
 
-    $dbh->txn_commit;
-
     return \%r;
 };
 
@@ -166,17 +163,17 @@ put '/list/:list_id/:item_id' => sub {
     length($item_id) and $item_id =~ /^\d{1,18}$/
         or return invalid_input('bad item ID');
 
-    my $req = decode_json(request_data);
+    my $req = request_data;
 
     my $descr = $req->{description};
-    my $done  = JSON->boolean( $req->{done} // 0 );
+    my $done =
+        exists $req->{done} ? JSON->boolean( $req->{done} // 0 ) : undef;
     my $version = $req->{version};
 
     length($version) and $version =~ /^\d{1,18}$/
         or return invalid_input('bad version');
 
     my $dbh = get_database;
-    $dbh->txn_begin;
 
     my %r = (
         lists_version => get_lists_version($dbh),
@@ -184,18 +181,12 @@ put '/list/:list_id/:item_id' => sub {
 
     my $list = $dbh->resultset('ShoppingList')->find($list_id);
     unless ($list) {
-        $dbh->txn_commit;
-        status 404;
-        content_type 'text/plain';
-        return "No such list";
+        return exception 404, "No such list";
     }
 
     my $item = $dbh->resultset('ShoppingListItem')->find({shopping_list => $list->id, id => $item_id});
     unless ($item) {
-        $dbh->txn_commit;
-        status 404;
-        content_type 'text/plain';
-        return "No such item";
+        return exception 404, "No such item";
     }
 
     # in case no real changes are needed will return the current state
@@ -203,10 +194,7 @@ put '/list/:list_id/:item_id' => sub {
         or defined($done) and $done != $item->done )
     {
         unless ($version == $item->version) {
-            $dbh->txn_commit;
-            status 409;
-            content_type 'text/plain';
-            return
+            return exception 409,
                 sprintf( 'Outdated version (current is %d)', $item->version );
         }
 
@@ -223,7 +211,98 @@ put '/list/:list_id/:item_id' => sub {
     $r{version} = $item->version;
     $r{list_version} = $list->version;
 
-    $dbh->txn_commit;
+    return \%r;
+};
+
+# modify shopping list
+put '/list/:list_id' => sub {
+    my $list_id = route_parameters->get('list_id');
+    length($list_id) and $list_id =~ /^\d{1,18}$/
+        or return invalid_input('bad list ID');
+
+    my $req = request_data;
+
+    my $name    = $req->{name} // '';
+    my $version = $req->{version};
+
+    length($version) and $version =~ /^\d{1,18}$/
+        or return invalid_input('bad version');
+
+    my $dbh = get_database;
+
+    my $list = $dbh->resultset('ShoppingList')->find($list_id);
+    unless ($list) {
+        return exception 404, "No such list";
+    }
+
+    # in case no real changes are needed will return the current state
+    if ( $name ne ( $list->name // '') ) {
+        unless ($version == $list->version) {
+            return exception 409,
+                sprintf( 'Outdated version (current is %d)', $list->version );
+        }
+
+        $list->update({
+            name =>  $name // '',
+            version => $version + 1,
+        });
+    }
+
+    return {
+        version       => $list->version,
+        lists_version => increment_lists_version($dbh),
+    };
+};
+
+# delete shopping list
+del '/list/:list_id' => sub {
+    my $list_id = route_parameters->get('list_id');
+    length($list_id) and $list_id =~ /^\d{1,18}$/
+        or return invalid_input('bad list ID');
+
+    my $dbh = get_database;
+
+    my %r = (
+        lists_version => get_lists_version($dbh),
+    );
+
+    my $list = $dbh->resultset('ShoppingList')->find($list_id);
+    if ($list) {
+        $list->delete;
+        $r{lists_version} = increment_lists_version($dbh)
+    }
+
+    return \%r;
+};
+
+# delete shopping list item
+del '/list/:list_id/:item_id' => sub {
+    my $list_id = route_parameters->get('list_id');
+    length($list_id) and $list_id =~ /^\d{1,18}$/
+        or return invalid_input('bad list ID');
+
+    my $item_id = route_parameters->get('item_id');
+    length($item_id) and $item_id =~ /^\d{1,18}$/
+        or return invalid_input('bad item ID');
+
+    my $dbh = get_database;
+
+    my %r = (
+        lists_version => get_lists_version($dbh),
+    );
+
+    my $list = $dbh->resultset('ShoppingList')->find($list_id)
+        or return exception 404, 'No such list';
+
+    my $item = $dbh->resultset('ShoppingListItem')
+        ->find( { shopping_list => $list->id, id => $item_id } );
+
+    if ($item) {
+        $item->delete;
+        $list->update({version => $list->version + 1});
+    }
+
+    $r{list_version} = $list->version;
 
     return \%r;
 };