Tuesday, October 13, 2015

Adding and deleting notes (springdo-5)



Adding a note

At this point, we can edit a todo note. We have a delete button, which we will deal with below. We would like to create new notes so we have something to mark as done and then later delete, right?
User Story The user can add a todo item by clicking on a button. The item is initially empty and not marked 'done'.
We will attack this problem in a few steps. First, we are going to create the frontend functionality, which includes: 1/ A button to add a todo item; 2/ a javascript function which creates an extra item in our $scope.listofitems array; 3/ some magic to show that new item.

Inserting items to the UI

A button is easily made and we make no attempt to make it look nice:
<div ng-click="plusbutton()">Plus</div>
But when the plusbutton function is run, how are we going to add an item to the UI? In a pre-AngularJS world, you may have thought to manipulate the DOM (the text on the browser's page) and insert an extra html item. The most popular library for this is jQuery, which gives you convenient functions to locate the insertion point (here is a brief overview of the things you won'tneed) and to create new items and insert them at some point (jQuery tutorial).
AngularJS has some minimal version of jQuery built in, but for simple projects you won't need it as AngularJS can do the work for you. Remember that AngularJS has a two-way data binding? Changing the UI state (via user input) immediately changes the javascript variables, and changing the javascript variables immediately changes the UI. This last point is obviously true for variable insertion, like <p>{{item.content}}</p>: If we change item.content, the user's content will be updated. Interestingly, this is also true for more complex AngularJS constructs, like:
<ul>
  <div ng-repeat="item for listofitems">
     <li>{{item.title}</li>
  </div>
</ul>
This will create a bulleted list of item titles. If we add an item to the javascript variable listofitems, AngularJS will also expand the list displayed to the user. In fact, if we remove the 3rd item of the list, AngularJS will remove that item from the display and nicely animate its removal. I have created a JSFiddle that shows how this works with much of the complexity of our current html removed, play around with it to see how changing variables affects the UI. You can also checkout this other tutorial.
As you can see, AngularJS uses a short animation to make it clear to the user what is happening: If you instantly remove an item from a list, chances are the user will never notice it. The animation support in Angular has changed quite a bit over time and the new 2.0 version is supposed to be fully centered around it. In this second fiddle, you can explore how changing the animation parameters is a matter of adding a class on the ng-repeat element and then using CSS to supply animation parameters for that transition. More explanation and demos of some quite over the top animations (like 3D rotation) are shown over at nganimate.org.

Templates

In the example above and in the JSFiddle, our loop looks very neat and tidy because we just write the item's title with <li>{{item.title}}. The current code in index.html is much harder to read because of the viewing and editing state of each item, and the logic for showing and hiding content. Wouldn't it be nice if our loop could be written like
<div ng-repeat="item in listofitems">
     <div ng-include src="'itemform.html'"></div>
</div>
In fact, we can do just that by providing a 'partial', an html fragment for insertion into our current pages. Note the double quotation on the partial: The name is a constant that needs quoted once for html and once more for AngularJS. The canonical source of a partial is to download it separately, here we inline it:
<script type="text/ng-template" id="itemform.html">
   <div class="list-group-item row">  <!-- rest of template goes here -->
The partial makes our html much more readable and it would also be a nice solution if we generated items in two places (which we currently don't do). Another approach would be to create your own AngularJS directive, ie. a new pseudo html element like <myitem ..>. Directives are very powerful and recommended when you are rewriting the DOM; they are overkill for this simple application. The main advantage of a directive is that it has its own scope, just like a javascript function has its own local variables. This allows you to write reusable code that does not depend on the parent scope, like an include does. This stackoverflow answer discusses the differences in more detail.

New versus create

TLDR A create endpoint is better than a new endpoint.
Something slipped into the last commit that should technically not have been there (splitting up historical commits to make a good tutorial is more complicated than you think). At the bottom of ListOfItemsController, I wrote a note to myself on a future endpoint for creating a new note:
post('/resource/new/title/content/done/')
That seemed like a logical choice, but there are a few problems that we encountered when we thought it through.
Let's first talk about the big benefit of this approach, namely unconnected operation. The frontend can create a note and allow the user to edit it without contacting and possibly waiting for the backend. That is a big gain, but it also means that if the backend is unavailable, we can only signal an error when the user has entered and edited the complete note. It is not hard to predict what users will think, say or shout when a note disappears into virtual reality upon hitting 'Submit'. It is much better to not let them create a new note if the server is unavailable, as the users will not lose any work. In the worst case, they will pick up their pencil-and-paper todo list again.
We could of course design some fancy local storage for the note and have the frontend and backend talk asynchronously. This sounds like a great project if you want to learn more about asynchronous operation! But before you start, this may work very well for mobile apps (where this type of operation is quite common), but it is much less well suited for a webbrowser. The infrastructure is there: we can use localStorage from the WebStorage API, which will allow us to store a key-value pair that persists over browser restarts.
However, the modern user often uses different browsers at different points over the day. They will seamlessly switch from Chrome to Firefox and onward to the browser on their phone or tablet. Imagine we used localStorage on a tablet browser, but the tablet was shut down soon after the note was created so the change is never propagated to the server. The user will not understand what happened with that note and be even more surprised when it resurfaces a day or so later, when the tablet was started up again for completely different reasons. There is only one way in which we can provide persistent storage over browsers: using our own backend.
Instead of a save endpoint, we will be using a create endpoint which returns the ID and contents of an empty note. This has the aforementioned disadvantage of not being able to start a new note if you are offline. It solves an issue we had not addressed yet: Each note has to have a unique ID and in an offline operation, we would have to rely on large random numbers to avoid collision (for example using UUID.randomUUID). The current system makes our backend the only source of IDs so it is easy to maintain uniqueness. Why does the create endpoint return the contents of an empty node when that is, well, empty?? In the future, the server could add all kinds of metadata to the note (like date created, user profile) or it could serve several types of skeleton notes (shopping lists, holiday todos etc). We don't use this functionality now but it is good to keep that option in there.
TLDR Server generated unique IDs scale / Now what happens if our excellent ToDo service goes viral, we have 10,000s of users and we need multiple many backend servers? How do we maintain uniqueness under that scenario? We could just tie each user to one a specific backend server and that server would continue to provide unique IDs for those user, just like in the simple case.

Can we finally see some code?

This is all fine and well but our User Story has not been addressed at all. Let's fix that fast, by first making a frontend only solution that just shows that we can do this. We added a simple button to our html above, that calls the plusbutton function. A simple-minded way to implement that function would be:
$scope.plusbutton = function () {
 $scope.listofitems.push({"id": 6, "title": "new item", "content": "Hi", "done": "no"});
};
Full code is in the commit below. When you check it out, it will work just fine and add a dummy item when you click the button. You can hit the button multiple times and get multiple new items. Try opening one of the new items and you see we have introduced a bug. Can you figure out what causes this behavior?
That was great, we are ready to actually move this to the backend. Let's do this right and start by writing a test for the backend functionality:
@Test
public void whenCreateIsHitANewItemIsCreatedAndReturned() throws Exception {
    mvc.perform(get("/resource/create/"))
     .andExpect(status().isOk())
     .andDo(print())
     .andExpect(jsonPath("$.title", is("")))
     .andExpect(jsonPath("$.content", is("")))
     .andExpect(jsonPath("$.done", is("no")));
}
The new javascript function is a little more complicated than our old one, but nothing too fancy: We do a GET request to the new endpoint and put a success function in that captures the returning data. As a slight novelty, the data is not only the item's ID but the full item this time (this assumes all our items are JSON serializable). We add the item to listofitems (javascript), expand the new item and start edit mode on it.
$scope.plusbutton = function () {
 $http.get('resource/create/').then(function(success) {
  newitem = success.data;
  $scope.listofitems.push(newitem);
  $scope.toggleContent(newitem.id);
  $scope.goedit(newitem);
 });
};
The definition of the endpoint is even shorter: All we have to do is create a new Item, save it to the database and return it.
@RequestMapping(value="/resource/create/", method=RequestMethod.GET)
Item postSaveUpdate() {
    Item item = itemRepository.save(new Item());
    return item;
}
If you run the example, you can see that you can reload the page and your changes persist. We have implemented saving new notes.
There is a small UI error with our version so far: When you create a new item and hit 'Submit' right away, you get an empty title field. There is nothing inherently wrong with that, other than that that means there is nothing to click on any more, which means we cannot open the item, which in turn means that we cannot edit it anymore. Before you read on, take a moment to think how you would solve this, or maybe even solve it. Two solutions are sketched next.
A quick fix would be to add a bit of space (non breaking space, &nbsp;) to the end of the title, so there is always something clickable there:
<div ng-click="toggleContent(item.id)"><b>{{item.title}}</b>&nbsp;</div>
A better solution is to check whether there is a title and display a substitute title if there is none. This can be done with the ng-if directive, which removes a html element if the 'if' is not true:
<div ng-click="toggleContent(item.id)">
    <b>{{item.title}}</b>
    <span ng-if="item.title.length == 0">-No Title-</span>
</div>
This is what the result looks like:
Screen+Shot+2015-10-13+at+2.45.16+PM.png

Deleting a note

Deleting a note is the 'D' in the CRUD acronym of common interfaces. This means that JPA is ready to deal with it, it provides a delete(id) call to handle item deletion (there are several other ways to call delete, see the docs).
Before we start writing the code, we should write the test. We then run the test and watch it fail, because the endpoint does not exist yet.
@Test
public void whenDeleteIsHitItemIsTrashed() throws Exception {
    // setup
    String newtitle = "New Test Title";
    Item item = new Item("Test Todo", "Do Lots of stuff - then delete");
    itemRepository.save(item);
    // now remove it
    mvc.perform(post(String.format("/resource/delete/%d/", item.id)))
     .andExpect(status().isOk());
    Item newItem = itemRepository.findOne(item.id);  // returns Null if not found
    assertNull(newItem);
}
Now for the implementation: On the html side, we add a click function to the trash can icon: godelete(item). This javascript function will contact the endpoint and if deletion was successful, delete the item locally:
$scope.godelete = function (item) {
    $http.post('/resource/delete/' + item.id + '/').then(
        function (success) {
            listofitems = $scope.listofitems;
            for (i = listofitems.length - 1; i >= 0; i--) {
                if (listofitems[i].id == item.id) {
                    listofitems.splice(i, 1);
                } } }); };
In a future version, we should get an update from the server telling us what the change in the listofitems is, for now we just remove the item ourselves. This is not great because we are duplicating the actions on the backend in the frontend, and this will surely come back and bite us one day. But it is really ok for now.
The endpoint is a simple application of JPA delete, as promised:
@RequestMapping(value="/resource/delete/{id}") //, method=RequestMethod.POST)
String deleteItem(@PathVariable long id) {
    itemRepository.delete(id);
    return "[\"ok\"]";
}
See you next time!

Thanks

A big thanks to everyone who read and commented on this tutorial, to Pivotal Labs for letting me write these tutorials, and to Navyasri Canumalla, who sat down with me to learn Spring and wrote half the code you see here.

Monday, October 12, 2015

Dynamic content and editing entries (springdo-4)



Hiding and showing content

You may have noticed that we are only showing the notes titles, IDs and the done status so far (and those IDs are only there for us, they will be removed in future version). That leaves the content of the notes hidden from the user's view. Recall, the content was background information to the note, so it is a great design decision to leave it hidden at first. However, our user wants to be able to view it at times:
User Story The user can click on a title to make the content visible.
The story is not complete, we imagine that
  1. all items come up as closed first (content hidden)
  2. opening one item closes any other open items
  3. clicking on the title of an already open item closes it again.
We will dive a little deeper into AngularJS to see how we can accomplish this task. As showing and hiding parts of a page is very standard functionality, AngularJS built a great system to hide/show almost any part of a webpage.
 1: <div ng-controller="home" ng-cloak class="ng-cloak">
 2:     <div class="list-group">
 3:  <div ng-repeat="item in listofitems">
 4:      <div class="list-group-item row">
 5:   <div ng-click="toggleContent(item.id)" class="col-md-6">{{item.title}} ({{item.id}})
 6:       <p ng-show="content[item.id]">{{item.content}}</p>
 7:   </div>
 8:   <form name="form{{item.id}}">
 9:       <div class="col-md-6">Done
10:    <input type="checkbox" ng-model="item.done"
11:           ng-true-value="'yes'" ng-false-value="'no'"
12:           ng-click='onDoneClick(item)'>
This is the same controller we saw before, but in line 6 we see a new <p> which wraps {{item.content}}. Crucially, this paragraph is shown or hidden under control of some javascript variable thanks to ng-show. If the value of ng-show is true, the tag that ng-show is part of is shown, otherwise it is hidden (documentation). If a transition between shown and hidden occurs, the transition is animated. Like all AngularJS, the webpage will (almost) immediately reflect any changes you make to the variable.
The easiest way to use ng-show would be with a simple variable, like so
<div ng-show="showit">Hide or show me </div>
Note that showit is a variable at the javascript level, but it should be quoted in the ng-show statement because HTML will not know about it. In the matching AngularJS we will refer to the same variable as $scope.showit. Because we have more than one item to show and hide, we use an array content instead (again, we did not choose the best possible name here,contentVisible[item.id] would have been much better).
Why does the array variable have to be quoted? What AngularJS does under the hood is to have javascript evaluate content[item.id] in the context stored in $scope. Different controllers have different scopes, which gives you a way to separate namespaces without having to name those spaces: Another controller could also have a content variable, but that would be in another scope. This concept of scope is very similar to dynamic languages like Python.
Two asides: First, in the code above we have added Bootstrap formatting classes like col-md-6 in places. Second, if you want to use a constant in an angular directive you have to double quote it, once for HTML and once for the javascript evaluate, like so:
<div ng-show="'constant'"> Text will be shown </div>
Hiding the content of the item is great, now we need a means to show it. Line 5 has a div with the an ng-click attribute, and a function to call when this div is clicked on, the function will have to be defined in the home controller as $scope.toggleContent. Note that any item can have a ng-click attribute (thanks to the HTML onClick event, which can basically be attached to any html element), we do not have to create a button.
Here is part of that function:
$scope.content = [];
$scope.toggleContent = function(itemid) {
 $scope.content[itemid] = !$scope.content[itemid]; };
In javascript, 'undefined' is falsy which means that all content will be hidden by default. The boolean negator ! will turn anything falsy into true and the relevant item content will be shown. The initialization of the content array in line 1 is crucial, without that the code will not run (Whereas accessing a non-existing item on an existing array returns undefined, accessing a non-existing item on a non-existing array will throw a 'Uncaught reference error'; gone are the good old days of Awk where this was totally fine).

Closing the other items

TLDR Front end testing really helps to check that we do not introduce regressions when adding new functionality.
This solves the user story and our considerations 1 and 3 above. We have not dealt with consideration 2: "Opening one item closes any other open items". If you look at the interface like this, it seems nice enough. But apparently on further probing, our product manager wanted the app to look more like a mobile app, where this 'one thing open at a time' behavior is very common. From a UI perspective, it makes the display less busy and cluttered, but it means users cannot compare the full contents of two todo items easily. On the web, this kind of UI also exists: jQuery calls this the Accordion Widget and you can easily create a very similar widget in pure Bootstrap.
Implementing it is not hard but the there is a small catch. Before I go over those I suggest you take the previous commit and try to implement this behavior for yourself: We managed it in three lines of javascript and you may be able to do it in less.
OK, the catch that we missed at first (and did not find during our testing either), is conderation 3: "Clicking on an already open item should close it again". The code at the commit above has this behavior, but we implemented consideration 2 by closing all items before we toggle the current one, like this code but without line 2.
1: for (var key in $scope.content) {
2:  if (key != itemid) {
3:   $scope.content[key] = false; }}
4: $scope.content[itemid] = !$scope.content[itemid];
Closing all items first and toggling the current one will give us the correct behavior when we open an item, but it will make it impossible to close one. So the if becomes necessary to guard against this. We did not notice this for a while because we had tested at earlier stage, when it still worked, and we never tested it again as we were focussing on closing the other items. Again, we will not be adding test to our AngularJS code to keep this tutorial focussed, but for any serious coding exercise, you should.

Debugging front end code

Restarting the spring backend for every small change in the front end code is slow and tedious. IntelliJ has some support for live editing of html and css files, but it is hard to set up and (in our setup) prone to breaking. Because you can easily write a mock version of your controllers in AngularJS (simply add a couple of hard-coded variable assignments), it is often more practical to use JSFiddle, Plunker, or similar tools to test your code (read this nice comparison). Make your changes there and then copy and paste the new parts back into your project. You can view some experimentation we did with this code here: https://jsfiddle.net/dirkjot/gjtmpksw/
You can also find and explore some darker corners of AngularJS that way: In the code on the fiddle, we added a div to make the title bold. The item id now goes to the next line, so a sensible thing would be to change the div into a span. Try this and click around on the first and then the second title, and you will see the first title disappear when the first item's content is hidden. After some probing, we found that wrapping a div around the the p that contains the content helps; without part of the ng-show seems to leak out of the p into the surrounding div. (If you have a more precise explanation, please leave a comment!)
Either way, this closes the user story so we make a commit of these three lines of code.

Editing todo items (front end)

Our Product Manager is very happy with us as we are making great progress. Let's move on to user contributed content, in the form of this story:
User Story The user can edit the title and content of a story
The story does not specify how this edit is started. We cannot tie it to a click on the title, as that already expands the item. We thought it was most appropriate to add some well-known icons to the expanded todo item, so we keep a very clean interface. Here is an artist impression of what we want to create:
Screen+Shot+2015-10-09+at+12.16.31+PM.png
Obviously, the placement of the icons and the done checkbox is not perfect, but we can improve on this later and focus on writing code for now.
Our first step is to pull in the font-awesome icons so we can use them here. We simply put four glyphicons files in the correct directory (main/resource/static/fonts) and we are good to go. To use them, we add two lines of html to our index.html:
<span class="glyphicon glyphicon-pencil" ng-click="goedit(item.id)"></span>
<span class="glyphicon glyphicon-trash"></span>
We already added a javascript function to a click on the edit icon; we leave the delete icon for later. You can see this code in action on this JSFiddle (we removed some experimentation we added in the previous fiddle).

Actual editing

To actually edit the form we have to write a fair amount of html, as each of the items will be in one of three interface states, listed below with the combination of variables that determines the state:
  • collapsed: Only title and done checkbox shown. Shown when content[item.id] is falsy.
  • opened: Title, content and done shown, edit and trash icons visible. Shown when content[item.id] is truthy and editorEnabled is false.
  • editing: Title and content turn into input boxes, submit button, no other elements. Shown when content[item.id] is truthy and editorEnabled is true.
This image shows an item in 'editing' state. Because you can only move to 'editing' via 'opened', all other items are necessarily 'collapsed' at this time.
Screen+Shot+2015-10-09+at+2.24.09+PM.png
The html for each item will now have three parts, one for each of the three states. I refer to the full html in index.html, lines 15-40 on this github commit, here are the highlights:
 1: <div class="list-group-item row">
 2:     <!-- not editing: -->
 3:     <form name="form{{item.id}}"   
 4:  ng-show="!content[item.id] || (content[item.id] && !editorEnabled)">
 5:      <div ng-click="toggleContent(item.id)"><b>{{item.title}}</b></div>
 6:      <div ng-show="content[item.id] && !editorEnabled">
 7:   <p>{{item.content}}</p>
 8:     [...]
 9:     <!-- editing: -->
10:     <div ng-show="content[item.id] && editorEnabled">
11:  <form name="formedit{{item.id}}"  ng-submit="saveedit(item)" role="form">
12:      <div class="form-group">
13:   <input type="text" ng-model="item.titleField" class="form-control"><br>
14:   <textarea type="text" ng-model="item.contentField"  class="form-control">
15:      </textarea><br>
16:   <input type="submit" id="submit" value="Submit"  class="form-control btn btn-warning">
What happened:
  • The html page has become quite complex: Each item has two forms, one for the not-editing state (with only a checkbox as a form element) and one for editing the title and content. Each item has these forms, so there are a lot of forms open at the same time.
  • The two forms have names specific to the item they are working on: One form is form.. (insert item.id at the dots) and the editing form is formedit... For each item, only one of them is visible at a time; and only one item can be opened (or editing) at the same time.
  • Aside While debugging, we actually disabled this ng-show mechanism to make it clearer what was happening. I encourage you do the same.
  • The ng-show on line 4 controls the heading (the title). The heading should be shown when this item is collapsed, or when it is open but we are not editing.
  • We bolded all the item titles and removed the id numbers. We decided against angular magic to make only the title of the currently open todo item bold. This would look nice but was more work than we were willing to invest.
  • On line 13, we create an input field and connect it to the item.titleField attribute. Angular will 'live' update that variable as the user is typing. We could have used item.title here instead and there would be no need to copy values back and forth between item.title and item.titleField (see index.js). However, the drawback of that method is that you cannot undo your edits. Even though we did not have a Cancel button in the original design, we will be adding one soon. To be able to cancel, we need to either save the old value, or run the input box on another variable.
  • in line 14, we do the same for the content, using a textarea.
As you may recall, the edit button calls goedit, and the submit button (line 16 and 11 above) calls saveedit. We will write these functions now. The first one, goedit is not complicated as we have to change state and populate the titleField and contentField variables:
// editing content
$scope.editorEnabled = false;

$scope.goedit = function (item) {
 $scope.editorEnabled = true;
 item.titleField = item.title;
 item.contentField = item.content;
};
The saveedit function has two parts: Moving the edit from the editing fields into the AngularJS model, then moving the changes into the backend. We will only write the first part for now. The code is not hard, you could probably write it (or jot it down on a piece of paper) in a minute or so. The one addition I made below is a promise to myself to what I want the backend update to look like: A POST to /resource/save/.
Save edit therefore is more or less the opposite of goedit:
$scope.saveedit = function (item) {
 item.title = item.titleField;
 item.content = item.contentField;
 $scope.editorEnabled = false;
 // TODO post this stuff
 // post('/resource/save/id/title/content/done/')
};
Lesson Learned This is actually not a great choice for posting material. It would be safer and better to put the item content in the body of the POST, instead of the URL. Then again, we are not sending sensitive information around and the length of our notes is not being constraint too much by the maximum recommended length of a URL, 2000~characters (and Chrome can easily go over 150,000 characters)
At this point, you can make edits and hit 'submit'. If you open and close the item, you will see that your saved content has been saved locally. However, a page reload will contact the server again and you will get the original items back. We are finished with our story, but we can see the need to persist changes in the backend.

Updating the backend

User Story The user's edits are persisted.
The third story in this episode is going to be very quick: All we have to do is communicate the edits from the frontend to the backend and then persist those edits on the backend. We just have to apply what we already know about endpoints and the JPA.
In 'index.js', we make the post that we sketched above more concrete:
$http.post('/resource/save/' + item.id + '/' + item.title + '/' + item.content + '/' + item.done + '/');
In 'ListOfItems.java', we add the endpoint. There is not that much code here: First some java boilerplate to get the parts of the URL into variables. Next, we retrieve the old item from the database. We do a check whether the 'done' status is indeed only yes or no (but we don't really know what to do if it is not, a common problem in programming). The actual saving of the new item is one line of code thanks to the JPA.
@RequestMapping(value="/resource/save/{id}/{title}/{content}/{done}/", method=RequestMethod.POST)
String postSaveUpdate(@PathVariable long id, 
        @PathVariable String title, 
        @PathVariable String content, 
        @PathVariable String done) {
    Item item = itemRepository.findOne(id);
    if (done.equals("yes") || done.equals("no")) {
 item.done = done; }
    else {
 System.out.println("Invalid argument to postSaveUpdate:  " + done); }
    item.title = title;
    item.content = content;
    itemRepository.save(item);
    return "[\"ok\"]";
}
It is nice to see how we can add major user-facing functionality with a few lines of code. In our enthusiasm to implement this, we forgot to do proper Test Driven Development: We should have written a test for the new endpoint before implementing it. Writing a test after the fact is still better than not writing a test at all, so off we go. We should
  • create an new item (for testing purposes)
  • submit it to the database, holding on to its ID
  • POST to the endpoint with a changed title and contents
  • retrieve the new item from the database
  • confirm that title and content have changed.
The code is almost as few lines as that and I recommend you try to write it yourself before you peek at the committed version (near the end of the file).
Final state at the end of this tutorial:
See you next time!

Thursday, October 8, 2015

Adding check boxes (springdo-3)



Adding checkboxes

"I'm Doing 120 plowing over check boxes" (Beastie Boys, High Plains Drifter)
We left off with the project in a good state: Two todo items are served by the Spring backend (ListItemController.java) and the angular code in index.html will retrieve them and then loop over them. Our user story that things "looked nice" has been finished as was the second user story, requiring "two items to be displayed". So it is time to pick up another story:
User Story A user can mark the (placeholder) task as completed
Now our todo items so far have been a little unusual in that they have a title and content. This was a design decision we never discussed but let's assume it came out of some user requirement: After all, there is often some content that is connected to a todo item, like an address, a link, or just some more information (in actual fact, it comes out of a requirement to have more backend functionality later on). What our items lacked was a todo/done toggle, which our users really need.
In case you lost it, this is our code at the end of the last tutorial.
We start by adding the checkboxes in the back end. The changes are minimal, as can be seen from this diff: We just add one line.
    @RequestMapping(value="/resource/list/", method= RequestMethod.GET)
    List listOfItems() {
  List<Map<String, String>> result = new ArrayList<Map<String, String>>();
  Map<String, String> map1 = new HashMap<String, String>();
  map1.put("id", "1");
  map1.put("title", "Go for a swim");
  map1.put("content", "Go swimming on Monday night");
+        map1.put("done","yes");
Lesson Learned You may think (and we thought) that using a boolean value for the 'done' flag is more natural. However, we have declared our the 'return' variable in our function to be of the type List<Map<String, String>>, which means that map1.put("done", true) will give you a type error at compile time. Now the clever thing to do would be to define 'result' as List<Map<String, Object>> (which means we can have strings and booleans). The very java thing to do would be to create a 'StringOrBool' abstract class, which is extended by two helper classes that are empty but for one data field, and then declare List<Map<String, StringOrBool>> result.
Because we were just trying something out, we made the quick decision to use string values 'yes' and 'no'. Then we built tests, more functions, and before we knew, it would be fair amount of refactoring to get rid of these strings and go back to booleans. We will do this later but leave these strings here for now.
Another good point is that there is no need for a map here. An object 'item' would be much better, with attributes like 'item.title'. In fact, that is what we will do later in this episode, when we interface with a database.

On the frontend side

To show these checkboxes, we need to add a small form to our 'index.html'. This is done inside the ng-repeat so each item will be formatted with this:
<dt>{{item.title}} ({{item.id}})</dt>
<dd>{{item.content}}</dd>
<form name="form{{item.id}}">
    <label>Done
 <input type="checkbox" ng-model="item.done"
        ng-true-value="'yes'" ng-false-value="'no'"
        ng-click='onDoneClick(item)'>
    </label></form>
Because we have multiple items, we will have multiple forms and we distinguish these by adding the item number to each. So for item 1, the form will be 'form1'. The <input> tag introduces several new Angular features:
  • An ng-model links the field to a javascript variable, it is the two-way binding counterpart to {{item.id}}. If the user clicks the checkbox, item.done will be updated immediately.
  • Our unfortunate decision to use 'yes' and 'no' instead of a boolean is fully supported by AngularJS through the ng-true-value and matching false-value option. Our checkbox will natively toggle between 'yes' and 'no'.
  • We also want to notify the backend of the change in status, so we connect our custom function 'onDoneClick' to the checkbox.
The 'onDoneClick' function contacts a new endpoint on the server (/resource/done/{itemnumber}/{state}/) and that is basically it. This means that the local update to the javascript AngularJS MVC is now independent from the backend update to Spring. That is good news in so far that the connection to the back end could be slow but the user experience is smooth and interactive.
It is also bad news in that we can have a discrepancy between what Spring thinks the user state is and what Angular thinks the user state is, while the user only sees the Angular state. We could only update the checkbox when we get a confirmation of the update from Spring and that would assure consistency, but that would come at the cost of interactivity. The most popular middle way seems to connect a failure function to the server update fired by onDoneClick, and show a popup to the user saying something like "We are having trouble contacting the server".
angular.module('index', []).
    controller('home', function($scope, $http) {
    // stuff deleted
 $scope.onDoneClick = function (item) {
     console.log(item.done);
     $http.post('/resource/done/' + item.id + '/' + item.done + '/');
If you try this, everything will work but in the console log of the spring server and in the console of the browser, you will see that the post to /resource/done/.. is not successful as there is no endpoint. The Spring boot log will also alert you to a not implemented POST method.
The checkout is below, if you want you can imlement a simple alert message when the server cannot be reached (as is the case right now), or even show a more fancy floating HTML element on the page itself. Please link to your solutions in the comments!

Adding state changes to the backend – using a real database

We have an interesting problem right now: We would like to store the state change (from 'done is no' to 'done is yes', or the other way around) in the backend but we do not really have a model of the todo item in the backend. We have made do with the minimal thing that works, which was a list of maps, with one map for each todo item. We can of course continue on this hacky path but it seems time to introduce a real database to our project.
There are many databases out there and each of them have their own niche. Do we want to tie down our project to one particular database right now? Probably not. Also, there are great advantages to using an in-memory database for development, but a real on-disk database for production. JDBC is a java standard for using databases through a standardized API, but it is cumbersome and low-level, like many things java. A new standard JPA has emerged which is object oriented, much higher level, and supported by Spring (see this StackOverflow questionfor a good comparison).
If you have ever seen any Object-Relational Mapping (ORM) code, you will feel at home when using Spring Data JPA. I show only the essential parts of the source here, look at the repository for the full details.
@Entity
public class Item {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    public long id;
    public String title;
    public String content;
    public String done;
In JPA notation, an @Entity is a class that will be stored in the database (usually this class will get its own table). Our entity 'Item' has the two values we already saw before, title and content. It also has a string for its done value. The string should only ever be 'yes' or 'no', but we do not currently enforce that. Finally, everything database needs a unique id, so we add a column for that and tell JPA to get some type of unique value in here (we will get an incrementing counter, it turns out).
What Spring Boot adds to this is fine JPA syntax is the auto configuration of the first database on path at runtime. In the project setup back in episode 1, we instructed you to do the following: "Under dependencies, check 'Web', 'JPA', 'HSQLDB'". We chose the HSQLDB database for a very simple reason: It is implemented in pure Java so we can simply pull it in with maven and build it with the rest of the project. It is a fine database otherwise, as you can read on its homepage. Lacking any further instructions as to user and password for the database, Spring Boot will set up a temporary in-memory database and give you a handle to it. The data will persist until you stop the Spring boot process, which is perfect for our needs.
Back to the Item we have defined above, which is a class that describes a single row in the database table (if you come from an SQL background) or a document in a collection (if you come from NOSQL like MongoDB). Item allows us to define properties at this level, but we also need to say things about the table (collection) itself. We do this in a helper class which is customarily called 'ItemRepository'. It is short and sweet:
public interface ItemRepository extends CrudRepository<Item, Long> {
   }
A CRUD (Create - Read - Update - Delete) repository allows us to do simple things with the basic entities, as described in the acronym. For a todo list, this is a great fit. We get a number of standard methods on our repository, including:
  • Entity save (Entity)
  • Entity findOne (PrimaryKey)
  • Iterable of Entity findAll ()
  • void delete (PrimaryKey)
If you want to read more: Try the documentation, the CrudRepository is best discussed under the General Concepts of JDA. Oliver Gierke shared this great overview of the two major types of Spring JPA classes on StackOverflow.
How do we use this great repository in our project? This involves a fair amount of small changes in various places. For starters, we want to populate the database on startup. The easiest way to do something like this is to add a 'run' method to our main class SpringdoApplication, see the code:
Lesson Learned: Do not forget to change the main class to implements CommandLineRunner, or run will not work and you will get java compiler errors on the @Override.
@Override
public void run(String... strings) throws Exception {
    itemRepository.save(new Item("swim", "in the pool"));
    itemRepository.save(new Item("run", "around the park"));
    itemRepository.save(new Item("shop", "for new shoes"));
    itemRepository.save(new Item("drive", "to great viewpoint"));
    itemRepository.save(new Item("sleep", "at least 8 hours"));
We are using the JPA save method on a newly created Item object. This is all very straightforward and a whole lot easier than trying to come up with the correct SQL syntax for this, making sure the column names match our property names, etc. But wait, how does run know what the itemrepository is and where it lives? Hold on to that question just for a minute.
With this saved, we can change our /resource/list/ end point to not hand-create a map, but query the database using the findAll function. Let's start with line 10 in the code below, where we do just that:
  • The findAll method returns an 'iterable' over type 'Item'. We want to extract the items from this iterable.
  • We create an empty ArrayList to hold the items later
  • We apply '.iterator()' to obtain an actual iterator (something you can iterate over) from the iterable. This is relatively confusing, but basically the 'iterable' is a factory function that creates fresh iterators every time you use its .iterator method. Each of these iterators is independent, ie. you could run two for loops over two of these iterators simultaneously and they would not interfere with each other.
  • In line 14, we use Java 8 to avoid a for-loop on the iterator altogether. Using a construction that is borrowed from more functional languages like Ruby and Python, we tell the iterator to apply a function to each of its elements with forEachRemaining. The function we want to apply is result::add, which is the add method of the result List we have just created (see
this SO answer if you are a little uncertain about your Java 8 syntax here).
 1: public class ListOfItemsController {
 2: 
 3:     ItemRepository itemRepository;
 4: 
 5:     @Autowired
 6:     ListOfItemsController(ItemRepository itemRepository) {
 7:  this.itemRepository = itemRepository;
 8:     }
 9: 
10:     @RequestMapping(value="/resource/list/", method= RequestMethod.GET)
11:     List listOfItems() {
12:  Iterable<Item> iterable = itemRepository.findAll();
13:  List<Item> result = new ArrayList<>();
14:  iterable.iterator().forEachRemaining(result::add);
15:  return result;
16:     }
Lines 3 to 7 deal with the question we raised before: How does the class local variable itemRepository get its value? Line 6 contains a constructor for ListOfItemsController which is called with one argument, the itemRepository.
The @Autowired annotation right above it tells Spring that we want it to have Dependency Injection, which means:
  • to find an existing object of the Itemrepository class
  • lacking that, to instantiate an object of the ItemRepository class
  • and call our constructor with that object so we can store the object internally
Because this is a very common requirement and it is kind of boring to have to write a constructor for this, we can abbreviate this for classes for which we don't need our own constructor. Specifically, these two lines below will mark the object-local variable 'itemRepository' as to-be-autowired and Spring will construct the same constructor as we wrote out above. This comes in really handy when you have multiple values to inject.
@Autowired
ItemRepository itemRepository;
We already had a function 'listOfItems', which served from a hand constructed map. We moved this out of the way by renaming it listOfDummyItems and having it connect to /resource/dummylist/. I like to keep these old controllers around for a bit so I can keep my old tests running while I develop the new functionality. We will see it come in handy in a minute.
Next we need to implement the backend for toggling the 'done' state of a todo item. In the AngularJS part (in index.js), we made a call like this:
$http.post('/resource/done/' + item.id + '/' + item.done + '/');
To implement this, we need a function postDoneUpdate:
  • It connects to an endpoint that interprets variables in the url (item.id and item.done). Spring supplies the /{id}/ syntax for this, together with a @PathVariable annotation on the function argument, as explained in the Spring MVC documentation.
  • With that id in hand, we will use the database to find the actual item.
  • Assign the new value of 'done' to the retrieved item
  • Save the item back to the database
The code is in the repository, at the next commit, but I encourage you to try to write it yourself. To help you, here is a test that you can run to see whether your code works (this code is already in the commit above):
@Test
public void whenItemIsCheckedAsDoneModelIsUpdated() throws Exception {
    Item item = new Item("Fake Todo", "Do Lots of stuff");
    // post item into db
    itemRepository.save(item);

    // call the backend function and set the 'done' to 'yes' for this item
    mvc.perform(post(String.format("/resource/done/%d/yes/", item.id)))
     .andDo(print())
     .andExpect(status().isOk());
    // retrieve updated item from db
    Item newItem = itemRepository.findOne(item.id);
    // check that for updated item, done == yes, while
    assertEquals(item.done, "no");
    assertEquals(newItem.done, "yes");
}

Problems with AngularJS

This test should be fairly self-explanatory: We create a new todo item and instert it into the database with an itemRepository.save call. Then we update the done state of the newly created item via a call to our endpoint, inserting the correct item.id in the POST. Next, we retrieve a new copy of the item from the database and assert that the new item has done set, and the original item did not have it set.
For my implementation of postDoneUpdate, this test works. I then ran Spring and tested the whole application by hand and indeed, checkboxes were present and could be toggled. A reload of the browser made the checkboxes come back to the state they were last in, indicating that we are indeed using the backend database. (Note that the database is in-memory, so it does not preserve state between runs of the application).
So all seems well but there is a problem: If you open the console of the browser, it turns out AngularJS is having some serious trouble and is throwing a 'syntax error'. This message shows up when we check or uncheck a box, and it is repeated for every check-action. The stack trace shows lots of routines inside the angular javascript stack, and never seems to touch our code. What is going wrong here?
angular-syntax-error.png
The problem, it turns out, is that my version of postDoneUpdate is returning an ok message. I did this so I could post a change myself (using the excellent Postman tool) and see that we got a happy return value from this:
return "['ok']";
This sounds all nice and dandy, but there is a problem here that is easy to miss: All methods of ListOfItemsController are return JSON by virtue of this being a @RestController. Specifically, AngularJS expects all responses to be valid JSON. And ="['ok']"= may look like valid JSON, but a quick check via jsonlint.com will tell you it is not. We start with [, which is correct because JSON requires every return object to be a list or a map. But JSON also requires double quotes around strings (for reasons that are nicely discussed in this StackOverflow reply) and even though some JSON parsers have gotten flexible about this, AngularJS enforces that.
The solution therefore is the a bunch less pretty but very straightforward:
return "[\"ok\"]";
With the finer details of JSON syntax out of the way, the question arises how this error was present yet we did not detect it until we opened the browser's console. The first reason is that AngularJS $http.post (in index.js) does not have a .then clause. In other words, AngularJS will parse the return value of the post, crash, but because nothing is supposed to happen after this post, there are no consequences for our program logic.
We can make this more visible by adding the success and failure functions via a .then:
$http.post('/resource/done/' + item.id + '/' + item.done + '/')
   .then(function (success) { console.log("backend received done state change", success) },
         function (failure) { console.log("backend error", failure) });
The second reason is that AngularJS is trying to be nice and show 'graceful degregation': Something is not working right but there is no reason to crash the browser or throw an 'Aw snap' message at the user. Instead we just move on, hoping that things will otherwise work fine. This is great behavior for sloppy webdesigners, but unhappy for people who want to ensure and test that each part of their application is working correctly.
The third and most important reason we missed this is therefore that we did not write any tests for AngularJS, nor did we write any end-to-end tests, acceptance tests, or whatever you may want to call these. On visual inspection, AngularJS was working fine but a good test should have caught the syntax error in the console. Because testing AngularJS is not trivial and slightly outside of the scope of this tutorial, we will leave this issue here, but keep in mind that for now, we are only testing whether the Spring framework is working well.
The user story ("A user can mark the (placeholder) task as completed") is finished, time to end this episode.
See you next time!

Tuesday, October 6, 2015

Adding Angular and creating a nice list (springdo-2)



Making it official

First of all, you need a github repo for any code. The repository has three branches (at the time of writing): Tutorial is the default branch and follows these posts. Master contains the code and the commit as they happened when we originally wrote it, and documentation contains the source to these blogposts (in emacs org-mode format).
I will be tagging the repository to indicate where the blog posts are. The format is springdo-1-final, indicating the code at the end of tutorial 1. Any intermediate commits will be named, like springdo-2-tests (which we will commit later after we have implemented the tests).

A new user story

User Story When I open the site, I want it to look nice and be interactive and responsive.
I have created artificially simple stories here, but for a tutorial like this it is nice to take baby steps.

Adding AngularJS and Bootstrap

TLDR We include our own css and js files with AngularJS, Bootstrap and jQuery.
Spring is written in java and runs on servers, providing the back end to a web application. Spring can serve static webpages and it can also use a templating system to create personalized pages ("Hello Mr <insert name here>"). However, modern web applications want to be interactive and responsive, just like desktop programs and apps.
This can be accomplished by using a front end framework that helps you create a separate model-view-controller system in the user's browser: This system will run in javascript (the only programming language that browsers support) and have javascript models of our data that will be rendered to user views by the front end framework. The main advantage of this approach is speed: The front end framework can immediately update the browser and notify the server (Spring) at its leasure. AngularJS is one such framework, we chose it because of its popularity.
Whereas AngularJS is concerned with interactivy, Bootstrap is concerned with the responsiveness: It creates a grid on your webpage and it will rearrange items to fit any size of screen. We won't spend much time with the (excellent) Bootstrap package here but just use it.
Now we could just simply include a reference to these packages in our page, using the free CDN (content delivery network) copies that Google and Twitter provide. However, in real applications that is rarely done because you want to provide your own version of these tools for various reasons. Our own version combines all the necessary files in two files: One js file and one css file, which were made using a tool called wro4j(steps detailed in the same Spring Tutorial). One more advantage, during development we will be loading and reloading the page often and having a local copy makes this faster.

Creating a test page

Let's create a page called 'hello-angular.html'. We create this page under src/main/resources/static: Any pages in that directory will show up under the root (/) of our server, so this page will show up aslocalhost:8080/hello-angular.js.
# hello-angular.html
<body ng-app="hello">
<div class="container">
    <h1>Greeting</h1>
    <p>
 If this is formatted nicely and shows 'the ID is' below, angular and bootstrap are
 working.   You need an endpoint at /resource for actual ID values to show up here, but
    we don't worry about that now </p>

    <div ng-controller="home" ng-cloak class="ng-cloak">
 <p>The ID is {{greeting.id}}</p>
 <p>The content is {{greeting.content}}</p>
    </div>
</div>
<script src="js/angular-bootstrap.js" type="text/javascript"></script>
<script src="js/hello.js"></script>
</body>
The ng-app directive on body tells Angular to parse the html of our page and do its magic with it. It also tells us that the controller(s) for this page will be called 'hello', which would normally be found in a file hello.js. Standard html follows, as one of the nicest things of angular is that it is valid html.
Things are getting more interesting around the <div ng-controller part: Here we tell angular that this div should be connected to the home controller. The cloak directives are there to make sure the page doesn't flash while loading. Finally, we see double curlies (moustaches) in the text, inserting the value of javascript objects greeting.id and greeting.content in the html.
The corresponding js looks like this:
# hello.js
angular.module('hello', [])
    .controller('home', function($scope, $http) {
     //$http.get('resource/hello').then(
     //        function(success) {
     //            $scope.greeting = success.data; });
     $scope.greeting = {id: 'xxx', content: 'Hello World!'};
});
In the js, we create a module 'hello', which has one controller 'home' under it. This controller will later contact an endpoint on our server, but that code is commented out for now. For now it assignes a hard coded value to the greeting object. To make sure that any assignment persists after the controller function completes, we have to modify variables on the $scope, so we write $scope.greeting.
There is much more to learn about AngularJS but this is hopefully clear enough to (roughly) understand what this does. Proceed by commenting out the hard assignment to greeting and putting the $http.get back in. Run the resulting code.
Remember we talked about dependency injection in AngularJS earlier? Here we see it in action: The 'home' controller is a function (like most things in javascript), but when it is invoked its arguments will be filled with a reference to the global scope and a reference to a service that can do http GET requests. What those things are and where they come from is of no interest to us now, AngularJS will make sure they are there and will pass us a reference to them: Dependency injection.
If you look at the AngularJS help pages for $http, you will see that this service returns 'promises' (well explained in the spring documentation). A promise returns right away, allowing the program to continue so your browser won't hang. But the actual response from the backend may take a while and this is where the magic of a promise comes in: The then function will be activated at some point: If the data comes in, the first function will be run. If a timeout or error occurs, the (optional) second function is run (not used here).
When we visit the page, AngularJS will call the 'home' controller to resolve the {{meeting.id}} reference. However, the endpoint resource/hello does not exist yet on the Spring backend and the http function fails. You can see this if you open the browser's console, a 404 error is shown on that endpoint. For a normal user, the webpage looks fine other than that no ID or content is shown. This is another nice property of AngularJS: When things don't work, the webpage breaks down gracefully. We will later see how to put a default value in the meeting.id, something like "Retrieving ID..". You can also try to put a nice pop-up message in by extending the .then function with a failure function.
Back at the back end, let's make it so 'hello-angular.html' does not break and write a controller that returns a valid id and content at resource/hello:
# HelloController.java
@RestController
public class HelloController {

    @RequestMapping(value = "/resource/hello")
    public Map hello () {
 Map<String, String> map1 = new HashMap<String, String>();
 map1.put("id", "1");
 map1.put("content", "Go swimming on Monday night");
 return map1;
    }
}
Again, we tell Spring that we have a controller that does not use any templating (RestController) and that its first method covers a specific endpoint (RequestMapping). Now in Python or Ruby, this function would have simply been:
return { "id": 1, "content": "Go swimming on Monday night" }
but in Java we have to actually construct a map and run put on it. If you restart the servedr and reload the page, you should see our template page with id and content filled in.
As an experiment, you can remove the comments so that our hello controller (over at the AngularJS side) assigns two placeholder values to $scope.greeting. Observe what happens: The screen flickers as the placeholder values get replaced by the real values. You can make that more obvious by putting a Thread.sleep(5000); (plus java boilerplate, let IntelliJ do the work for you) in the HelloController.java class, simulating a very busy server which takes a while to get back to you. Now you will see 'ID: xxx' for a few seconds, at which point it gets replaced by 'ID: 1' (see the video below if you need help with this).
Just like other templating systems, AngularJS will insert the value of 'greeting.id' into our html when the page gets rendered. Unlike older frameworks, AngularJS will actually monitor the 'greeting' variable and update the page whenever the variable is changed. This is also true for user interactions: If we bind a user input field to a javascript variable, the field will start out displaying the variable's content and the variable's content will immediately reflect any changes the user is making to the input field.
Video AngularJS is constantly updating the page Springdo-2-v1
This doesn't actually solve the user story, as we have created a demo page for this and not modified our main page. But is is a clear milestone for us and we are confident that we can apply these same changes to our list of items, so we move on given that the next story also involves that list of items.

Placeholder items from the server

User Story When I open the site, I want to see a list of two (placeholder) todo items
An empty site was nice, but our user wants more. If we do the most minimal things that works, we would simply add to the html that we hardcoded in the last tutorial. We are going to do something slightly more complicated this time and serve these two placeholder items from the backend (Spring) using the knowledge we just acquired about how AngularJS and Spring can work together via $http.
Specifically,
  • The webpage at / will display the list of todo items (zero or more).
  • The webpage will be very similar to the 'hello-angular' example we wrote above
  • The Spring backend will publish a list of todo items in json format at the endpont /resource/list/.
As we are going to modify the backend, we can use the preferred Pivotal methodology: Writing a test before we write the code. Tests go in a specific place in the hierarchy and are usually called after the controller they test. Here is the full code of 'ListOfItemsControllerTest':
 1: @RunWith(SpringJUnit4ClassRunner.class)
 2: @SpringApplicationConfiguration(classes = SpringdoApplication.class)
 3: @WebAppConfiguration
 4: public class ListOfItemsControllerTest {
 5: 
 6:     private MockMvc mvc;
 7: 
 8:     @Autowired
 9:     private WebApplicationContext context;
10: 
11:     @Before
12:     public void setUp() throws Exception {
13:  /* do not use standAloneSetup, as it is not good for web apps */
14:  mvc = MockMvcBuilders.webAppContextSetup(context).build();
15:     }
16: 
17:     @Test
18:     public void whenDefaultPlaceholdersLoadedTwoTasksShouldShow() throws Exception {
19:  // note that we are only testing spring json output, we are assuming angular shows this 
20:  // nicely on the user's page
21: 
22:  // we assume that our first version always has two tasks:
23:  // id1 / title: Go for a swim  / Content:  Go swimming on Monday night
24:  // id2 / title: Visit farmer's market / Content: Buy dairy and eggs at farmers market on Wednesday
25: 
26:  mvc.perform(get("/resource/list"))
27:   .andExpect(status().isOk())
28:   .andDo(print())
29:   .andExpect(jsonPath("$", hasSize(2)))
30:   .andExpect(jsonPath("$[0].id", is("1")))
31:   .andExpect(jsonPath("$[1].id", is("2")))
32:   .andExpect(jsonPath("$[0].title", containsString("swim")))
33:   .andExpect(jsonPath("$[1].title", containsString("market")))
34:   .andExpect(jsonPath("$[0].content", containsString("swimming on Monday")))
35:   .andExpect(jsonPath("$[1].content", containsString("dairy and eggs")));
36:     }
37: }
This test uses the Spring Test framework, for which we have to adjust our dependencies in a minute. What the framework does is quite clear and this is largely boilerplate that you can copy between tests:
  • (line 1) We state we want to use the standard spring unit test runner
  • (line 2) We tell the test that it should run with the same configuration as our normal application (this may slow things down a bit, but it is the easiest)
  • (line 3) We tell the test framework that this is a web app test
  • (line 6) For the test, we use a mocked web framework (MVC)
  • (line 8) Next, we want to have a WebApplicationContext (which is necessary for Spring to run). Instead of finding it ourselves, we ask Spring to inject it with the @Autowired annotation.
  • (line 11) Before we run any tests, we fill the mvc object with a mocked web app created from the context we were given via dependency injection.
  • You will also see tests against 'standAloneSetup' (which is faster). Do not use that as things will break in weird ways if you are working with a web app.
After all of this, we are ready to run a test. Each test has to be annotated with @Test and in Behavior Driven Development style, the name of the test is a sentence that describes the business value that we are testing. In line 26, we ask the test runner to go to localhost / and retrieve the response. At this point, the test runner will have started the server for us so this should return a page with a list with two items, as in the user story.
We continue to test various aspects of that page, first we ensure it is read and returns status Ok. We also print out the full response with andDo. Then we use the 'jsonPath' library to test various aspects of the json:
  • (line 29): that it is a list with two elements
  • (line 30): that the 'id' of the first item is 1, and the second is 2
  • and that titles and contents are set correctly
Please run this test and see it fail, as we have not implemented this yet (this seems silly but it is a good practice, every now and then you will accidentally write a test that your code already satisfies; there could also be an error in your test).
In fact, running the test reveals that it fails for the wrong reasons: we still have to pull in a dependency and we get an error like java.lang.NoClassDefFoundError: com/jayway/jsonpath/InvalidPathException. You can go to the pom.xml file and use IntelliJ's 'Generate' function to include a new dependency. Make sure the Maven repository has been read by IntelliJ so you can simply search for 'jsonPath' and insert it.
Video Adding the jsonPath dependency in the pom.xml, using IntelliJ Springdo-2-v1

Implementing the item list endpoint

After this successfully failed test, we will actually implement the endpoint. It may be worth it to sketch the solution yourself before reading on, it is actually not that hard and a good test of your understanding of Spring so far. The previous commit has the test in it, so you can run your code against that test.
The function is not hard to write once you look at the 'HelloController' above:
  • again we have a @RestController, as we do not want any templating on the Spring side
  • we can call our method anything, I called it 'simpleminded' because it is not a very sustainable approach to a todo server
  • annotate the method with a endpoint via @RequestMapping.
  • this time, we return a list of dictionaries, one for each todo item. This means our class returns the java monstrosity List<Map<String, String>> but it is otherwise the same as above.
@RestController
public class ListOfItemsController {

    @RequestMapping("/resource/list")
    List simpleminded() {
 List<Map<String, String>> result = new ArrayList<Map<String, String>>();
 Map<String, String> map1 = new HashMap<String, String>();
 map1.put("id", "1");
 map1.put("title", "Go for a swim");
 map1.put("content", "Go swimming on Monday night");
 result.add(0, map1);

 Map<String, String> map2 = new HashMap<String, String>();
 map2.put("id", "2");
 map2.put("title", "Visit farmer's market");
 map2.put("content", "Buy dairy and eggs at farmers market on Wednesday");
 result.add(1, map2);

 return result;
    }
}
Before you run the webserver, run the ListOfItemsControllerTest unit test and check that the test passes. Then try the webserver and all should be broken, because there is not index.html page that matches the hello-angular.html we wrote above. Similarly, we should write a very simple angular controller which will contact the new endpoint for us, like hello.js did above.
The essential part of index.html is listed below. We see the same essentials:
  • a controller 'home' is declared on the app 'index'
  • for Bootstrap we have a class container, with a delimited list inside it (Bootstrap annotation list-group) and individual dd/dt items in it (Bootstrap annotation list-group-item.
  • The items are written out by a ng-repeat loop, which assigns item to each todo list item.
  • For each item, we show the title, its id (a temporary measure) and the content.
<body ng-app="index">
    <div class="container">
 <h1>My TODO list</h1>
 <div ng-controller="home" ng-cloak class="ng-cloak">
     <dl class="list-group">
  <div ng-repeat="item in listofitems">
      <div class="list-group-item">
   <dt>{{item.title}} ({{item.id}})</dt>
   <dd>{{item.content}}</dd>
      </div>
  </div>
     </dl>
 </div>
We have to implement a minimal controller, which simply fetches the data from the endpoint. It is only a few lines of code for 'index.js':
angular.module('index', []).
    controller('home', function($scope, $http) {
 $http.get('resource/list/').then(function(success) {
     $scope.listofitems = success.data;
 })
    });
Here is what the result will should look like. With that we have completed this installment of the tutorial, as we can close the user story.
main+screen+at+springdo-2.png
And you can find the final code on github:
See you next time!