{"action":"created","issue":{"url":"https://api.github.com/repos/finagle/finch/issues/263","labels_url":"https://api.github.com/repos/finagle/finch/issues/263/labels{/name}","comments_url":"https://api.github.com/repos/finagle/finch/issues/263/comments","events_url":"https://api.github.com/repos/finagle/finch/issues/263/events","html_url":"https://github.com/finagle/finch/issues/263","id":73624376,"number":263,"title":"Best practices and abstractions","user":{"login":"ImLiar","id":2317121,"avatar_url":"https://avatars.githubusercontent.com/u/2317121?v=3","gravatar_id":"","url":"https://api.github.com/users/ImLiar","html_url":"https://github.com/ImLiar","followers_url":"https://api.github.com/users/ImLiar/followers","following_url":"https://api.github.com/users/ImLiar/following{/other_user}","gists_url":"https://api.github.com/users/ImLiar/gists{/gist_id}","starred_url":"https://api.github.com/users/ImLiar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ImLiar/subscriptions","organizations_url":"https://api.github.com/users/ImLiar/orgs","repos_url":"https://api.github.com/users/ImLiar/repos","events_url":"https://api.github.com/users/ImLiar/events{/privacy}","received_events_url":"https://api.github.com/users/ImLiar/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/finagle/finch/labels/question","name":"question","color":"cc317c"}],"state":"open","locked":false,"assignee":null,"milestone":{"url":"https://api.github.com/repos/finagle/finch/milestones/8","html_url":"https://github.com/finagle/finch/milestones/Finch%200.8.0","labels_url":"https://api.github.com/repos/finagle/finch/milestones/8/labels","id":1042527,"number":8,"title":"Finch 0.8.0","description":"","creator":{"login":"vkostyukov","id":1098539,"avatar_url":"https://avatars.githubusercontent.com/u/1098539?v=3","gravatar_id":"","url":"https://api.github.com/users/vkostyukov","html_url":"https://github.com/vkostyukov","followers_url":"https://api.github.com/users/vkostyukov/followers","following_url":"https://api.github.com/users/vkostyukov/following{/other_user}","gists_url":"https://api.github.com/users/vkostyukov/gists{/gist_id}","starred_url":"https://api.github.com/users/vkostyukov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vkostyukov/subscriptions","organizations_url":"https://api.github.com/users/vkostyukov/orgs","repos_url":"https://api.github.com/users/vkostyukov/repos","events_url":"https://api.github.com/users/vkostyukov/events{/privacy}","received_events_url":"https://api.github.com/users/vkostyukov/received_events","type":"User","site_admin":false},"open_issues":18,"closed_issues":6,"state":"open","created_at":"2015-03-27T23:29:28Z","updated_at":"2015-06-21T23:09:09Z","due_on":null,"closed_at":null},"comments":6,"created_at":"2015-05-06T13:40:51Z","updated_at":"2015-06-22T07:29:00Z","closed_at":null,"body":"When we've started to use finch (from v0.5) as a basis for our REST/HTTP API we've struggled with a lack of some practices, guidelines and how-to about abstractions on top of underlying `Service[HttpRequest, HttpResponse]`.\r\n\r\nFinch by itself is a pretty low level layer which responds to work with HTTP requests/responses with some neat monadic extensions/ways to do. And nothing more. Finatra, for example, was built around `Filter/Controller` and its composition.\r\n\r\nSo we decided to abstract it on our own.\r\n\r\nNow our simple CRUD controller looks like that:\r\n\r\n```scala\r\nclass ItemsApiController(implicit val injector: Injector) extends Controller {\r\n\r\n  private val itemsService = inject[ItemsService] //We use scaldi as DI\r\n  private val itemReader = body.as[Item]\r\n\r\n  def findItemById(itemId: Long): Action = securedAction { reqContext =>\r\n    itemsService findItemById itemId\r\n  }\r\n\r\n  def userItems: Action = securedAction(pageReader) { page => implicit reqContext =>\r\n    itemsService.userItems(user.id.get, PageRequest(page))\r\n  }\r\n\r\n  def newItem: Action = securedAction(itemReader){ item => implicit reqContext =>\r\n    itemsService.newItem(user.id.get, item)\r\n  }\r\n\r\n  def updateItem(itemId: Long): Action = securedAction(itemReader) { item => implicit reqContext =>\r\n    itemsService.updateItem(user.id.get, itemId, item)\r\n  }\r\n\r\n  def removeItem(itemId: Long): Action = securedAction { implicit reqContext =>\r\n    itemsService.removeItem(user.id.get, itemId)\r\n  }\r\n\r\n  override def routes: Endpoint[HttpRequest, HttpResponse] = {\r\n    (Get    / \"api\" / \"items\"        /> userItems)    |\r\n    (Get    / \"api\" / \"items\" / long /> findItemById) |\r\n    (Post   / \"api\" / \"items\"        /> newItem)      |\r\n    (Put    / \"api\" / \"items\" / long /> updateItem)   |\r\n    (Delete / \"api\" / \"items\" / long /> removeItem)\r\n  }\r\n\r\n}\r\n```\r\n\r\nLooks pretty intuitive and simple as for me.\r\n\r\nYou may ask why do we ever need a controller layer when it's just a kind of proxy to services? \r\nWell, it's a good place to do lazy authentication, check user permissions, validate input and many other things which are not welcome in a _real business_ logic. \r\nYet it provides a simple way to compose all controllers together and bind it to HTTP port.\r\n\r\nSo here is a question.\r\nDo we ever need this bicycle-boilerplate as a part of some finch ecosystem, some simple example & bootstrap for newbies?\r\n\r\nI completely understand that this abstraction level should not be a part of finch core just because of its nature. I just wanna know if someone interested in that experience and how should I present it in that case - some article or even `finch-subproject`."},"comment":{"url":"https://api.github.com/repos/finagle/finch/issues/comments/114027326","html_url":"https://github.com/finagle/finch/issues/263#issuecomment-114027326","issue_url":"https://api.github.com/repos/finagle/finch/issues/263","id":114027326,"user":{"login":"ImLiar","id":2317121,"avatar_url":"https://avatars.githubusercontent.com/u/2317121?v=3","gravatar_id":"","url":"https://api.github.com/users/ImLiar","html_url":"https://github.com/ImLiar","followers_url":"https://api.github.com/users/ImLiar/followers","following_url":"https://api.github.com/users/ImLiar/following{/other_user}","gists_url":"https://api.github.com/users/ImLiar/gists{/gist_id}","starred_url":"https://api.github.com/users/ImLiar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ImLiar/subscriptions","organizations_url":"https://api.github.com/users/ImLiar/orgs","repos_url":"https://api.github.com/users/ImLiar/repos","events_url":"https://api.github.com/users/ImLiar/events{/privacy}","received_events_url":"https://api.github.com/users/ImLiar/received_events","type":"User","site_admin":false},"created_at":"2015-06-22T07:29:00Z","updated_at":"2015-06-22T07:29:00Z","body":"@vkostyukov OH NOES, 404."}}