playframework/playframework

Injection parameters to methods of controllers

オープン

#10,873 opened on 2021/05/25

 (4 件のコメント) (3 件のリアクション) (0 人の担当者)Scala (4,032 件のフォーク)batch import
help wanted

Repository metrics

Stars
 (12,623 個のスター)
PR merge metrics
 (平均マージ 10d 17h) (30d で 69 merged PRs)

説明

Maybe it relates to #2983 (in some way). We use multi-tenant data isolation. Our main entity is AcHost. We need to transfer it in many controllers without copy/paste. We use action composition .

Our current solution works like that:

  1. Our Action (play.mvc.Action) put some params to request like that:
public OurAction extends Action<OurCustomAnnotation> {
 // constructor and dependencies 

   @Override
  public CompletionStage<Result> call(Request request) {
           
        String clientKey = // receive client key from jwt
        ACHost acHost = ourService.getACHost(clientKey).orElseThrow(() -> new RuntimeException("Not found " + clientKey));
            
        Request newly = request.addAttr(AC_HOST_PARAM, acHost);
        return delegate.call(newly);
   }
}
  1. Then we use it in controllers
public OurController {
  public CompletionStage<Result> updateCreationRestrictions(Request request) {   
     ACHost acHost = request.attrs().getOptional(AC_HOST_PARAM).get(); // for example call Optional.get()
    
      // our busines logic
  }   
}

And it looks really bad.

It will be cool to inject our entity directly in controller like that:

public class OurController {
 
   public CompletionStage<Result> creationRestrictionsPage(ACHost acHost) {
	//  our business  logic
   }
}

Is it possible to implement?

We have some idea about API for the feature (maybe it will be useful)

  1. Play Framework provides some interface (PlayInjector for example).
interface PlayInjector {
	CompletionStage<Http.Request> fillRequest(Http.Request request);
}
  1. We implement the interface like that (spring bean for example):
@Singleton
public class AcHostInjector implements PlayInjector {

	// constructor and dependencies

    @Override
    public Http.Request fillRequest(Http.Request request) {
    	String clientKey = // receive client key from jwt
        ACHost acHost = ac.getACHost(clientKey).orElseThrow(() -> new RuntimeException("Not found " + clientKey));
            
        // part from  #2983
        Request newly = request.addAttr(SOME_PARAM_NAME, acHost);
        return delegate.call(newly);
    }

}

  1. Play detects our PlayInjector-implementation, does some "magic" actions and we can inject our AcHost in controller like that:
public class OurController {
   
    public CompletionStage<Result> creationRestrictionsPage(ACHost acHost) {
	//  our business  logic
   }
}

  1. Declare in routes-file GET /some/url controllers.CreationRestrictionsController.creationRestrictionsPage(acHost: AcHost)

  2. Use in jsRoutes jsRoutes.controllers.CreationRestrictionsController.creationRestrictionsPage() // without additional params

It would be really useful for our team.

Kind regards

コントリビューターガイド