Custom querystring parameters in Play

Usually, actions in Play does not receive complex parameters. If you take a look in your project, probably you will see just simple parameters. Integers, Longs etc. Yesterday, trying to find questions to answer in the Play forum, I found one about receiving a java.util.Date parameter in the controller’s action.

    public static Result findByDate(Date date){
    	System.out.println(date);
    	return ok();
    }

When you configure this action in your routes file, an error will be printed in your console.

    No QueryString binder found for type java.util.Date. Try to implement an implicit     QueryStringBindable for this type

By default, Play does not know how to transform a querystring parameter into a Date object. That’s why we have the QueryStringBindable interface. This is like a formatter, but to querystring parameters. The first thing we need to do is to implement our converter.

	public class DateParameter implements QueryStringBindable<DateParameter>{

		private SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
		private Date value;

		@Override
		public Option<DateParameter> bind(String key,
				Map<String, String[]> parameters) {
			if(parameters.containsKey(key)){
				String date = parameters.get(key)[0];
				try {
					this.value = formatter.parse(date);
				} catch (ParseException e) {
					throw new IllegalArgumentException(e);
				}
				return Option.<DateParameter>Some(this);
			}
			return Option.<DateParameter>None();
		}

		public Date getValue() {
			return value;
		}

		@Override
		public String javascriptUnbind() {			
			return null;
		}

		@Override
		public String unbind(String key) {
			return "key="+formatter.format(value);
		}

	}

Now you need to receive this object as a parameter in your action and change your routes file as well.

    public static Result findByDate(DateParameter date){
    	System.out.println(date.getValue());
    	return ok();
    }

 GET /findByDate	controllers.NewsController.findByDate(date:binders.DateParameter)

A last thing here. In our action, we invoke the getValue method to recover the parsed date. This is why you should keep state in your QueryStringBindable object. Every time a request is made to a method receiving a DateParameter, Play will instantiate this object.

If you have or had this necessity, you can use this interface or the PathBindable, for the cases when the parameter is mixed in the url.

Advertisements

Playframework, how to protect against Mass Assignment

Form data handling is one of the most used feature in every MVC framework, in Play is not different. Documentation on website is very good, but leaves outside a couple of important situations. Let’s see a first case to better understanding about this feature.

Imagine a simple html form to register a user. Here is the user class and template which contains html form:

      public class User {

      	private String id;
      	private String email;
      	private String password;
      	private RoleType roleType = RoleType.CUSTOMER;

      	public void setRoleType(RoleType roleType) {
      		this.roleType = roleType;
      	}

      	public RoleType getRoleType() {
      		return roleType;
      	}

        //getters and setters for other fields
      }

Now we have to write a controller to handle the client submission. Here is an example:

    public class UsersController extends Controller{
	
    	private static Form<User> newUserForm = Form.form(User.class); 

    	public static Result form(){
    		return ok(views.html.new_user_form.render(newUserForm));
    	}
	
    	public static Result create(){
    		Form<User> filledForm = newUserForm.bindFromRequest();
    		if(filledForm.hasErrors()){
    			return badRequest(views.html.new_user_form.render(filledForm));
    		}
    		User user = filledForm.get();
    		Logger.info("RoleType {}",user.getRoleType());
    		Ebean.save(user);
    		return TODO;
    	}
    }

The problem is that we are believing that our user will simply fill the inputs in form and submit the information. What if an extra parameter appear in our Form object? For example, “user.roleType“. There are all kinds of user in this world, and maybe one of them likes to test your application trying to submit extra parameters, using chrome tools for example :).

editiing_html_chrome

When you invoke form.bindFromRequest().get, Play’s underlying binder will get all parameters and try to set in your User object. Every field that has a setter can be set with a form parameter. So the first solution would be drop setRoleType() method from your class. But in our case that is impossible, we need this setter there to allow admin changes roleTypes of other users.

One other solution is configure Form object to accept only some fields, and this feature is implemented already in Play Framework.

    public static Result create(){
    	Form<User> filledForm = newUserForm.bindFromRequest("email","password");
    	if(filledForm.hasErrors()){
    	    return badRequest(views.html.new_user_form.render(filledForm));
    	}
    	User user = filledForm.get();
    	Logger.info("RoleType {}",user.getRoleType());
    	Ebean.save(user);
    	return TODO;
    }

Usage of this technique is a nice way to protect your system against Mass Assignment attack. For instance, Github already suffered with this kind of attack. Stay connected, next week I will write how to handle different types of validations from the same model!

Strategies for testing static calls in Play projects

Play forum is a place with a lot of healthy doubts. Other day, an interesting topic popped there: How to test static methods. So, let’s talk about a little bit about this subject.

For example, if you have this piece of code:

    public void save(final RecentPhotosURL photosURL,
    		final Function2<String, Integer, Void> callback) {
    	WSRequestHolder holder = WS.url(photosURL.getEndpoint());
    	photosURL.fill(holder);
    	Promise promise = holder.get();
    	promise.map(savePhotosFunction);
    }

How can you test it? You are using WS class and making a static call. Libs like Mockito, only can test instance methods. One way to workaround things here is the usage of a lib which instruments your code and is able to mock some static calls :). This powerful tool is PowerMock. So, to test your method you could use something like this.

    @RunWith(PowerMockRunner.class)
    @PrepareForTest({ WS.class })
    public class NewPhotosSaverTest {

    	@Test
    	public void shouldGetJsonResponseAndSaveIt() {
    		mockStatic(WS.class);
    		Mockito.when(WS.url(url).thenReturn(new MyRequestHolder(url));
    		new NewPhotosSaver(...).save(photosURL,callback)
    	}

    	static class MyRequestHolder extends WSRequestHolder{

    		public MyRequestHolder(String url) {
    			super(url);
    		}

    		public  Promise get(){...}

    	}

    }

Voilà, you can unit test a lot of methods that use static approach. This could be used to test legacy system too :). I have no doubts that use static methods are easier than use a lot of instance methods. The main reason is that you can invoke these methods from everywhere. But oops, this can be your big problem too :(.

Now, if someone has to add some logic in this method, there is a big chance that a new class with some static methods be created. The complexity of this method would be increased because it would be responsible for creating and using objects instead of just use them and, even worst, static calls can be made from every piece of your code. I am not sure if you have seen something like this, but imagine a code inside a template:

    for(photo       code here
    }

So you have to know really well your team before start using static methods everywhere. Another strategy can be used to prevent maintainability problems like this. Instead of using Play API’s directly, you could wrap some of them and force your code to instantiate some objects.

    public class ServiceRequester {
      private String endpoint;

      public ServiceRequester(String enpoint){
        ...
      }

      public Promise get(Map<String,String> params){
        WSRequestHolder holder = WS.url(endpoint);
    		Set<Entry<String, String>> entries = params.entrySet();
    		for (Entry<String, String> entry : entries) {
    			holder.setQueryParameter(entry.getKey(),entry.getValue());
    		}
    		return holder.get();

      }
    }

    //using this code

    public class NewPhotosSaver {
        public void save(final RecentPhotosURL photosURL,
        		final Function2<String, Integer, Void> callback) {
        	ServiceRequester requester = new ServiceRequester(photosURL.getEndpoint());
        	Promise promise = requester.get(photosURL.getParams());
        	promise.map(savePhotosFunction);
        }
    }

Now you can refactor a little more and receive these dependencies as constructor args.

    public class NewPhotosSaver {

        public NewPhotosSaver(ServiceRequester requester){
          ...
        }

        public void save(final RecentPhotosURL photosURL,
        		final Function2<String, Integer, Void> callback) {
        	Promise promise = requester.get(photosURL.getParams());
        	promise.map(savePhotosFunction);
        }
    }

It is easy to test now! Just mock this parameter and test your code without problems.

    @Test
    public void shouldGetJsonResponseAndSaveIt() {
      ServiceRequester requester = mock(ServiceRequester.class);
      when(requester.get(params)).thenReturn(somePromiseHere)
      new NewPhotosSaver(requester).save(photosURL,callback);
      //asserts here
    }

Now you have, at least, two options of approach to your code. You can use this same strategy with your DAO. Instead of create static methods that use JPA.em() or Ebean.something, create instance methods and pass DAO’s instances as arguments to other classes.

Of course you have to think about what kind of approach you prefer, it is possible to mix them too. Your tests send signals about your code, pay attention :). Thanks to Rafael Ponte who talked about this situation with me and inspired me to write this post :).

Take advantage of assets conventions in Play

It is usual when you are working with Play use this kind of code to refer public assets.

   <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/style.css")"/>
   <script src="@routes.Assets.at("javascripts/jquery-1.4.4.min.js")" type="text/javascript">
   <img src="@routes.Assets.at("images/someimage.png"/>

But, Why do you have to write the name of css, javascript and images folder all the time if they are the convention? When you are using a framework is important to take advantage of all things, in order to avoid silly mistakes, like write the wrong name of the folder. For example, at least to me, it would be better if we could write something like this:

   <link rel="stylesheet" href="@Css("bootstrap.min.css")">
   <script type="text/javascript" src="@Js("main.js")"></script>
   <img src="@Image("someimage.png"/>

To achieve this we just have to use the built in controller named Assets. Let’s see the implementation:

  package helpers

  import controllers.routes

  object AssetsHelper {

    object Css {
	  def apply(file:String) = routes.Assets.at("stylesheets/"+file)
    }

    object Js {
	  def apply(file:String) = routes.Assets.at("javascripts/"+file)
    }

    object Image {
	  def apply(file:String) = routes.Assets.at("images/"+file)
    }

}

Now, you just have to import this class to all templates. Change your build.sbt and add this line.

   templatesImport ++= Seq("helpers.AssetsHelper._")

If you want to keep update with a lot of Play tips, follow me here and in my twitter :). Also I have my book available in Leanpub, still only in Portuguese and ASAP in English.