A good way to stay flexible is to write less code. --Pragmatic Programmer

June 8, 2011

Development, Scala

Comments Off

As our website grows and people can log in, add books to their own collection, a need to access this collection on their mobile arises.

When starting the mobile application and entered the correct login information, a request is being made to get the list of authors.
Clicking on an author will get a list of books from that author that the user owns, clicking on a book shows the details.

So the first query that needs implementing is: Give me a list of Authors for which the current user owned books

Given the Following Mapper Data Model:
Author <- (1) -> Book <- (2) -> User
(1) An Author can have more books while books can be written by multiple authors (N-N)
(2) A user can own multiple books, while a book can have multiple owners (N-N)

note: When successfully authenticating in a user his API key is returned which is used in all other requests

Below we will see the code that executes this query
what happens line by line is this:

  • Line4: we get a list of books for the current user
  • Line5: we map the colllection to one that contains the authors for each book, the result is a list of lists of authors List[List[Author]]
  • Line6: foldLeft applies the method to each element in the list, from left to right, as the method ++ means adding two list’s together, we’ll end up with one list containing all authors
  • Line7: distinct removes any duplicates in there
  • Line8: We sort the list on the author’s lastName property
  • Line9: we map it to a List of Xml fragments

Scala’s inline XML support allows us to simple put the Authors tag around it.
The second case does the same but gives a JSON response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
serve {
  case "api" :: key :: "user" :: "authors" :: "all" :: _ XmlGet _ => {
    <Authors> {
      Book.findAll(In(Book.id ,BookUser.book, By(BookUser.user, getUserIdFromKey(key))))
        .map(book => { book.authors.get })
        .foldLeft(List[Author]())(_ ++ _)
        .distinct
        .sortWith((a1:Author, a2:Author) => a1.lastName.is < a2.lastName.is)
        .map(author => author.toXml)
      }
    </Authors>
  }
  case "api" :: key :: "user" :: "authors" :: "all" :: _ JsonGet _ => {
    JsonWrapper ("Authors", {
      Book.findAll(In(Book.id ,BookUser.book, By(BookUser.user, getUserIdFromKey(key))))
        .map(book => { book.authors.get })
        .foldLeft(List[Author]())(_ ++ _)
        .distinct
        .sortWith((a1:Author, a2:Author) => a1.lastName.is < a2.lastName.is)
        .map(author => author.toJson)
      })
  }
}
 
//helper method
def getUserIdFromKey(key:String):Long = {
  User.find(By(User.key, key) match {
    case Full(user) => user.id
    case (_) => 0 
  }
}

December 17, 2009

Development, Java

Comments Off

I’ve been playing around with REST (REpresentational State Transfer) for a bit and decided to write a small tutorial to show how easy it is to create a rest interface to your business objects

Advantages of rest

  • Works over HTTP, known protocol with known data formats (mime types), no weird ports open in your firewall
  • Every resource is uniquely identified by a URI
  • Can do CRUD on those resources (they are just called POST, GET, PUT, DELETE)
  • used by all the major players for cloud applications (SUN’s cloudApi, Microsoft’s Azure services platform)
  • we might finally get rid of webdav

I’ll be using the Jersey Framework for this.
As i’ve been working on a backend that will allow you to manage agile development processes (Scrum, Kanban etc) I thought I use that.

In this application every object is represented by a Card for instance a Story, Task, Bug, work Item, etc.
Cards have a hierarchical structure and can each have custom properties
The class looks something like this (removed methods for clarity):

public abstract class Card {
	private long id;
	private List children = new ArrayList();
	private List properties = new ArrayList()
}

and then for instance the Story class with some default values set in the constructor:

public class Story extends Card {
	public Story() {
		addProperty("Title", "A new story");
		addProperty("Description", "as a .. I want .. for the benefit of ..");
		addProperty("Storypoints", "0");
	}
}

To be able to return these objects through REST they need to be in a format that can be distributed over HTTP, in this case we will be using XML and JSON.
The Java XML Bindings are perfectly suited to create xml representations of our classes

@XmlRootElement(name="card")
public abstract class Card {
	private long id;
 
	@XmlAttribute(name="type")
	protected String instance = this.getClass().getSimpleName();
 
	@XmlElement(name="card")
	private List children = new ArrayList();
 
	@XmlElement(name="property")
	private List properties = new ArrayList();
 
	@XmlAttribute
	public long getId() {}
}

* the Entry class is a simple class with a name and value property, I choose this approach as JAXB has an issue in representing HashMaps() in XML
this will produce the following xml

 

for JSON we don’t need to do anything special then include the jersey-json.jar to the project.

Now to configure and hookup the rest servlet
I added the jersey servlet to my web.xml

    	Rest Web Service
    	com.sun.jersey.spi.container.servlet.ServletContainer
    	1
 
    	Rest Web Service
    	/services/*

And create the service provider class

@PerRequest
@Path("/agileassistant")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public class AgileAssistantService {
 ...
}

This will tell Jersey that this is a provider that will respond to requests to /rest/agileassistant, accept JSON and XML and can output JSON or XML depending on the accept headers sent by the client

Now if we for instance want to return the first card (rootCard) and all its children we add this method

	public static Card rootCard = Card.createCard(Root.class);
 
	@GET
	public Card getRoot() {
		return rootCard;
	}

(in my data model the rootCard is always present and functions as a starting point to add the rest of the cards in a hierarchical structure)
So requesting this card will effectively return the entire structure for my test data:

 

Doing a parameterized query is almost as easy

	@GET
	@Path("/card/{id}")
	public Card getCard(@PathParam("id") long id) {
		return getCardById(rootCard, id);
	}

here the id that you specify will be injected into the parameter
giving the following output

 

To conclude enabling rest for your applications is pretty easy, writing this blog took longer than writing the code.
In a next post I will add POST/PUT/DELETE requests to store data in your application