{"id":16442650,"url":"https://github.com/fwbrasil/zoot","last_synced_at":"2025-06-17T03:38:47.493Z","repository":{"id":15080946,"uuid":"17807374","full_name":"fwbrasil/zoot","owner":"fwbrasil","description":"Thin reactive framework to provide and consume REST services","archived":false,"fork":false,"pushed_at":"2015-02-22T17:40:37.000Z","size":506,"stargazers_count":48,"open_issues_count":1,"forks_count":5,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-05-29T13:26:54.017Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"SirTony/Pastebin.cs","license":"lgpl-2.1","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fwbrasil.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-LGPL","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-03-16T19:36:02.000Z","updated_at":"2024-05-14T06:50:00.000Z","dependencies_parsed_at":"2022-08-24T13:48:45.649Z","dependency_job_id":null,"html_url":"https://github.com/fwbrasil/zoot","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/fwbrasil/zoot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fwbrasil%2Fzoot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fwbrasil%2Fzoot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fwbrasil%2Fzoot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fwbrasil%2Fzoot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fwbrasil","download_url":"https://codeload.github.com/fwbrasil/zoot/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fwbrasil%2Fzoot/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260286626,"owners_count":22986623,"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":[],"created_at":"2024-10-11T09:18:07.914Z","updated_at":"2025-06-17T03:38:47.469Z","avatar_url":"https://github.com/fwbrasil.png","language":"Scala","funding_links":[],"categories":["开发框架"],"sub_categories":["Web框架"],"readme":"# Zoot\n\n[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fwbrasil/zoot?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n[![Build Status](https://secure.travis-ci.org/fwbrasil/zoot.png)](http://travis-ci.org/fwbrasil/zoot)\n[![Coverage Status](https://coveralls.io/repos/fwbrasil/zoot/badge.png)](https://coveralls.io/r/fwbrasil/zoot)\n\n### Thin reactive framework to provide and consume REST services\n\n#### Google Group - [http://groups.google.com/group/zoot-framework](http://groups.google.com/group/zoot-framework)\n\n#### Artifacts are published on maven central:\n\n[http://search.maven.org/#search%7Cga%7C1%7Czoot](http://search.maven.org/#search%7Cga%7C1%7Czoot)\n\n# Using zoot\n\n## Example\n\nServer and client sample implementation:\n\n[https://github.com/fwbrasil/zoot/tree/master/zoot-sample/src/main/scala/net/fwbrasil/zoot/sample/counter](https://github.com/fwbrasil/zoot/tree/master/zoot-sample/src/main/scala/net/fwbrasil/zoot/sample/counter)\n\n## Contract\n\nZoot uses Api traits to define the services 'contract':\n\n``` scala\ntrait SomeApi extends Api {\n\t\n\t@endpoint(\n        method = RequestMethod.PUT,\n        path = \"/simple\")\n    def simpleMethod(someInt: Int): Future[Int]\n}\n```\n\nNotes:\n\n1. It is possible to use primitive and non-primitive classes as parameters and return.\n2. Api methods must return Future, otherwise an exception will be thrown.\n4. Apis should always be traits, not classes or abstract classes.\n5. To aggregate Apis, just use common trait inheritance.\n\n\n### Optional parameters\n\nBy default all parameters are required and 'BadRequest' is returned if there is a missing parameter.\n\nTo define parameters as optional, just use the Option type:\n\n``` scala\ntrait SomeApi extends Api {\n\t\n\t@endpoint(\n        method = RequestMethod.PUT,\n        path = \"/simple\")\n    def simpleMethod(someInt: Int, optionalString: Option[String]): Future[Int]\n}\n```\n\nIn this example, the method will be invoked using 'None' for 'optionalString' if the parameter is missing.\n\n\n### Default parameters\n\nIt is possible to define default values for parameters:\n\n``` scala\ntrait SomeApi extends Api {\n\t\n\t@endpoint(\n        method = RequestMethod.PUT,\n        path = \"/simple\")\n    def simpleMethod(someInt: Int = 11): Future[Int]\n}\n```\n\nIf the 'someInt' is not specified in the request parameters, the default value '11' is used.\n\n\n### Parameterized paths\n\nUse parameterized paths to extract parameters from the path:\n\n``` scala\ntrait SomeApi extends Api {\n\t\n\t@endpoint(\n        method = RequestMethod.GET,\n        path = \"/users/:user/name\")\n    def userName(user: Int): Future[String]\n}\n```\n\nThe request for '/users/111/name' will invoke 'userName' using '111' for the 'user' parameter\n\n### Response\n\nBy default, the response body is the value returned by the method and the http status is '200 Ok'. If the method throws an exception, '500 Internal Server Error' is returned.\n\nIt is possible to modify this behavior:\n\n1. By throwing an [ExceptionResponse](https://github.com/fwbrasil/zoot/blob/master/zoot-core/src/main/scala/net/fwbrasil/zoot/core/response/Response.scala#L21) during the method execution.\n2. By returning a [Future[Response]](https://github.com/fwbrasil/zoot/blob/master/zoot-core/src/main/scala/net/fwbrasil/zoot/core/response/Response.scala#L10).\n\n\n## Client\n\nThe Client object provides Api instances for remote services:\n\n``` scala\nval dispatcher: Request =\u003e Future[Response[String]] = ???\nval client: SomeApi = Client[SomeApi](dispatcher)\n```\n\nYou need to provide a 'real' dispatcher instance. Zoot provides implementations for Spray and Finagle.\n\nOnce you have the client instance, use Api methods as common method invocations:\n\n``` scala\nval future: Future[Int] = client.simpleMethod(11)\nval otherFuture: Future[String] = client.userName(22)\n```\n\nPlease refer to the [Scala Documentation](http://docs.scala-lang.org/overviews/core/futures.html) for more details about Futures.\n\n## Server\n\nThe Server object allows to create a server using an Api instance.\n\n``` scala\nclass SomeService extends SomeApi {\n\tdef simpleMethod(someInt: Int) = Future.success(someInt + 1)\n}\n\nval server: Request =\u003e Future[Response[String]] = Server[SomeApi](new SomeService)\n```\n\nThe server is a function that can be used with the Spray or Finagle bindings.\n\n\n## Mappers\n\nThe request and response values are serialized using a [StringMapper](https://github.com/fwbrasil/zoot/blob/master/zoot-core/src/main/scala/net/fwbrasil/zoot/core/mapper/StringMapper.scala#L6).\n\nZoot provides the [JacksonStringMapper](https://github.com/fwbrasil/zoot/blob/master/zoot-core/src/main/scala/net/fwbrasil/zoot/core/mapper/JacksonStringMapper.scala#L15) implementation for json.\n\n\n## Bindings\n\nPlease refer to the [Spray](http://github.com/spray/spray) or [Finagle](http://github.com/twitter/finagle) documentation for more details on how to create servers and clients.\n\n### Spray\n\n#### Client\n\n``` scala\nimplicit val mirror = scala.reflect.runtime.currentMirror\nimplicit val mapper = new JacksonStringMapper\n\nval dispatcher = SprayClient(host = \"localhost\", port = 8080)\nval client: SomeApi = Client[SomeApi](dispatcher)\n```\n\n#### Server\n\n``` scala\nimplicit val mirror = scala.reflect.runtime.currentMirror\nimplicit val mapper = new JacksonStringMapper\nimplicit val system = ActorSystem(\"SomeSystem\")\nimplicit val timeout = Timeout(1000 millis)\n\nval server = Server[SomeApi](new SomeService)\nval sprayActor = system.actorOf(Props(new SprayServer(server)))\n\nIO(Http) ! Http.Bind(sprayActor, interface = \"localhost\", port = 8080)\n```\n\n### Finagle\n\n#### Client\n\n``` scala\nimplicit val mirror = scala.reflect.runtime.currentMirror\nimplicit val mapper = new JacksonStringMapper\n\nval builder = ClientBuilder()\n    .codec(RichHttp[Request](Http()))\n    .hosts(s\"$host:$port\")\n    .hostConnectionLimit(10)\n    .requestTimeout(1000 millis)\n\nval dispatcher = FinagleClient(builder.build())\nval client: SomeApi = Client[SomeApi](dispatcher)\n```\n\n#### Server\n\n``` scala\nimplicit val mirror = scala.reflect.runtime.currentMirror\nimplicit val mapper = new JacksonStringMapper\n\nval address = new InetSocketAddress(port)\nval builder =\n    ServerBuilder()\n        .codec(RichHttp[Request](Http()))\n        .bindTo(address)\n        .keepAlive(true)\n        .name(\"SomeServer\")\n\nval server = Server[SomeApi](new SomeService)\nval finagleServer = FinagleServer(server, builder.build)\n```\n\n## Filters\n\nIt is possible to define filters for zoot clients and servers. Example:\n\n``` scala\nval requestLogFilter =\n\tnew Filter {\n        override def apply(request: Request, next: Service) = {\n            log(s\"request $request\")\n            next(request)\n        }\n```\n\nUse the filters when creating a server or client:\n\n``` scala\nval server = requestLogFilter andThen Server[SomeApi](new SomeService)\n\nval client = Client[SomeApi](requestLogFilter andThen dispatcher)\n```\n\n# FAQ\n\n## Why 'zoot'?\n\nThe name is a reference to the [Zoot](http://muppet.wikia.com/wiki/Zoot) character from The Muppets Show, inspired by the jazz saxophonist [Zoot Sims](http://de.wikipedia.org/wiki/Zoot_Sims).\n\nhttps://www.youtube.com/watch?v=CgfZVNv6w2E\n\n\"Forgive me [Roy Fielding](http://en.wikipedia.org/wiki/Roy_Fielding) wherever you are!\"\n\n## Why 'reactive'?\n\nThis is the buzzword of the moment and zoot uses non-blocking asynchronous IO.\n\n## Should Api files rule the world?\n\nProbably not. :)\n\nIf the client and server are using scala and zoot, it is a big win to reuse the Api traits to communicate. If not, just write them by your own. Anyway you need to specify how to invoke services.\n\n## Is zoot compatible with Scala.js?\n\nNo, since it uses runtime proxy generation. It is possible to remove this limitation using macros. Please [open an issue](https://github.com/fwbrasil/zoot/issues/new) if you would like have Scala.js compatibility.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffwbrasil%2Fzoot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffwbrasil%2Fzoot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffwbrasil%2Fzoot/lists"}