{"id":16337639,"url":"https://github.com/gvolpe/light-play-rest-api","last_synced_at":"2025-03-22T23:32:28.352Z","repository":{"id":35564566,"uuid":"39836527","full_name":"gvolpe/light-play-rest-api","owner":"gvolpe","description":"This project aims to be the reference to create a Light Weight REST API using Play Framework 2.4.x.","archived":false,"fork":false,"pushed_at":"2015-08-11T09:35:40.000Z","size":1188,"stargazers_count":34,"open_issues_count":0,"forks_count":3,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-03-17T18:13:04.291Z","etag":null,"topics":["playframework","rest-api"],"latest_commit_sha":null,"homepage":null,"language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gvolpe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-07-28T13:48:18.000Z","updated_at":"2023-11-11T17:12:41.000Z","dependencies_parsed_at":"2022-09-18T00:22:19.270Z","dependency_job_id":null,"html_url":"https://github.com/gvolpe/light-play-rest-api","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gvolpe%2Flight-play-rest-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gvolpe%2Flight-play-rest-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gvolpe%2Flight-play-rest-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gvolpe%2Flight-play-rest-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gvolpe","download_url":"https://codeload.github.com/gvolpe/light-play-rest-api/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245036127,"owners_count":20550662,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["playframework","rest-api"],"created_at":"2024-10-10T23:47:36.366Z","updated_at":"2025-03-22T23:32:27.959Z","avatar_url":"https://github.com/gvolpe.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"light-play-rest-api\n===================\n\n[![Codeship Status for gvolpe/light-play-rest-api](https://codeship.com/projects/d01bfc40-1767-0133-8ea3-06c83ac03245/status?branch=master)](https://codeship.com/projects/93580)\n[![Coverage Status](https://coveralls.io/repos/gvolpe/light-play-rest-api/badge.svg?branch=master\u0026service=github)](https://coveralls.io/github/gvolpe/light-play-rest-api?branch=master)\n[![Codacy Badge](https://www.codacy.com/project/badge/2a966c471ffd466ca91bd175d292c9d9)](https://www.codacy.com/app/volpegabriel/light-play-rest-api)\n\nThis project aims to be the reference to create a Light Weight REST API using [Play Framework 2.4.x](https://www.playframework.com/).\n\n## About\n\nWe are using customized routers, easy to re-use them and fully testables. Every router represents a funcionality (separation of concerns). No more single 'Routes' file that becomes huge with the time.\n\n## How it works?\n\nThe entry point is a custom class that extends [ApplicationLoader](https://www.playframework.com/documentation/tr/2.4.x/api/scala/index.html#play.api.ApplicationLoader) which defines the 'load' method.\n\n```scala\nclass Boot extends ApplicationLoader {\n\n  def load(context: Context): Application = ???\n\n}\n```\nTo indicate that we want to use this custom loader, we have to specify it in the **application.conf** file.\n\n```\nplay.application.loader = Boot\n```\n\nAfter that we have to create the customized routers. This project has 3 sample routers for Users, Products and Orders. This is how it looks:\n\n```scala\nobject UsersRouter extends DefaultUsersRepository with UsersRouter {\n  def apply(): Router.Routes = routes\n}\n\ntrait UsersRouter {\n\n  self: UsersRepository =\u003e\n\n  def routes: Router.Routes = {\n\n    case GET(p\"/users/${long(id)}\") =\u003e Action.async {\n      find(id) map {\n        case Some(user) =\u003e Ok(Json.toJson(user))\n        case None =\u003e NotFound\n      }\n    }\n\n    case POST(p\"/users\") =\u003e Action.async(parse.json[User]) { implicit request =\u003e\n      val user = request.body\n      save(user) map (_ =\u003e Created)\n    }\n\n  }\n\n}\n```\n\nSince the type [Router.Routes](https://www.playframework.com/documentation/tr/2.4.x/api/scala/index.html#play.api.routing.Router$@Routes=PartialFunction[play.api.mvc.RequestHeader,play.api.mvc.Handler]) is a **PartialFunction[RequestHeader, Handler]**, we can define the cases in our 'routes' method. We created a companion object with an apply() method to make things easier.\n\n### Putting the pieces together\n\nAfter all, we are able to combine our Routes in a defined Router as shown in the code below:\n\n```scala\ndef router: Router = Router.from {\n  UsersRouter() orElse\n  ProductsRouter() orElse\n  OrdersRouter()\n}\n```\n\nThere are different ways to combine PartialFunctions to get only one. We choose the first one but we can, for instance, define the Router by reducing a List of PartialFunctions, as we do in the [BaseRouterSpecification](https://github.com/gvolpe/light-play-rest-api/blob/master/test/routers/BaseRouterSpecification.scala) class:\n```scala\ndef router: Router = Router.from {\n  val routers = List(UsersRouter(), ProductsRouter(), OrdersRouter())\n  routers reduceLeft (_ orElse _)\n}\n```\n\nYou can find more information about the new Routing system in the [Official Documentation](https://www.playframework.com/documentation/2.4.x/ScalaSirdRouter).\n\nThat's enough to start a Light REST API from the scratch ***thinking seriously in clean coding***.\n\n## Testing\n\nWe choose **Specs2** to test Play's applications. As it's explained in the documentation, we are able to [test the Routers](https://www.playframework.com/documentation/2.4.x/ScalaFunctionalTestingWithSpecs2#Testing-the-router) instead of call directly to an Action.\n\nSo we start creating a Specification for the UsersRouterSpec as shown below:\n\n```scala\nclass UsersRouterSpec extends PlaySpecification {\n   ......\n}\n```\n\nThen we create a FakeUsersRouter to replace the Real Users Repository for an InMemoryRepository (Default). In the application we are using the same repository, but that will be changed for a repository accessing a real database.\n\n```scala\nobject FakeUsersRouter extends DefaultUsersRepository with UsersRouter {\n  def apply(): Router.Routes = routes\n}\n```\n\nFinally we create a fakeApplicationLoader to start testing the Routers.\n\n```scala\nval fakeRouter = Router.from(FakeUsersRouter())\n  \nval fakeAppLoader = new ApplicationLoader() {\n  def load(context: Context): Application = new BuiltInComponentsFromContext(context) {\n    def router = fakeRouter\n  }.application\n}\n```\n\nNow we are able to write our tests, using our Fake Application Loader.\n\n```scala\n\"Users Router\" should {\n\n  \"Not find the user\" in new WithApplicationLoader(fakeAppLoader) {\n    val fakeRequest = FakeRequest(GET, \"/users/123\")\n    val Some(result) = route(fakeRequest)\n\n    status(result) must equalTo(NOT_FOUND)\n  }\n\n  ... More cases ...\n}\n```\n\nTo learn more see the [completed test specification](https://github.com/gvolpe/light-play-rest-api/blob/master/test/routers/UsersRouterSpec.scala).\n\n## License\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use this project except in compliance with\nthe License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.\n\nUnless required by applicable law or agreed to in writing, software distributed under the License is distributed on an\n\"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific\nlanguage governing permissions and limitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgvolpe%2Flight-play-rest-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgvolpe%2Flight-play-rest-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgvolpe%2Flight-play-rest-api/lists"}