{"id":20984112,"url":"https://github.com/tlazaro/play-monad","last_synced_at":"2025-09-03T15:42:50.439Z","repository":{"id":53089255,"uuid":"354463082","full_name":"tlazaro/play-monad","owner":"tlazaro","description":"Play Monad","archived":false,"fork":false,"pushed_at":"2022-03-19T00:37:54.000Z","size":54,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-13T10:43:20.481Z","etag":null,"topics":["fp","monad","monad-transformers","monadic","monadic-interface","play-framework","scala"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tlazaro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-04-04T05:24:31.000Z","updated_at":"2022-03-19T00:28:40.000Z","dependencies_parsed_at":"2022-09-12T11:21:16.108Z","dependency_job_id":null,"html_url":"https://github.com/tlazaro/play-monad","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/tlazaro/play-monad","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tlazaro%2Fplay-monad","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tlazaro%2Fplay-monad/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tlazaro%2Fplay-monad/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tlazaro%2Fplay-monad/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tlazaro","download_url":"https://codeload.github.com/tlazaro/play-monad/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tlazaro%2Fplay-monad/sbom","scorecard":{"id":889259,"data":{"date":"2025-08-11","repo":{"name":"github.com/tlazaro/play-monad","commit":"c64ee07c5e42d9418e3398c453eb4967e9a9ac25"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.8,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/23 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:10: update your workflow using https://app.stepsecurity.io/secureworkflow/tlazaro/play-monad/release.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/tlazaro/play-monad/release.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/tlazaro/play-monad/release.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:9: update your workflow using https://app.stepsecurity.io/secureworkflow/tlazaro/play-monad/test.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/test.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/tlazaro/play-monad/test.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/tlazaro/play-monad/test.yml/main?enable=pin","Info:   0 out of   3 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   3 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/release.yml:1","Warn: no topLevel permission defined: .github/workflows/test.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 3 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-24T11:09:35.087Z","repository_id":53089255,"created_at":"2025-08-24T11:09:35.087Z","updated_at":"2025-08-24T11:09:35.087Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273467612,"owners_count":25111130,"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","status":"online","status_checked_at":"2025-09-03T02:00:09.631Z","response_time":76,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["fp","monad","monad-transformers","monadic","monadic-interface","play-framework","scala"],"created_at":"2024-11-19T05:51:26.980Z","updated_at":"2025-09-03T15:42:50.400Z","avatar_url":"https://github.com/tlazaro.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"# play-monad\n\nThis play module provides a simpler alternative to play Actions using for-comprehensions.\n\nNOTE: We just started work on this repository, expect many changes.\n\n## Versions\n\n|            | Scala 2.10 | Scala 2.11 | Scala 2.12 | Scala 2.13 |\n|------------|------------|------------|------------|------------|\n| Play 2.3   |[![Maven Central](https://img.shields.io/maven-central/v/dev.playmonad/play23-monad_2.10.svg)](https://maven-badges.herokuapp.com/maven-central/dev.playmonad/play23-monad_2.10)|[![Maven Central](https://img.shields.io/maven-central/v/dev.playmonad/play23-monad_2.11.svg)](https://maven-badges.herokuapp.com/maven-central/dev.playmonad/play23-monad_2.11)|||\n| Play 2.4   |[![Maven Central](https://img.shields.io/maven-central/v/dev.playmonad/play24-monad_2.10.svg)](https://maven-badges.herokuapp.com/maven-central/dev.playmonad/play24-monad_2.10)|[![Maven Central](https://img.shields.io/maven-central/v/dev.playmonad/play24-monad_2.11.svg)](https://maven-badges.herokuapp.com/maven-central/dev.playmonad/play24-monad_2.11)|||\n| Play 2.5   ||[![Maven Central](https://img.shields.io/maven-central/v/dev.playmonad/play25-monad_2.11.svg)](https://maven-badges.herokuapp.com/maven-central/dev.playmonad/play25-monad_2.11)|||\n| Play 2.6   ||[![Maven Central](https://img.shields.io/maven-central/v/dev.playmonad/play26-monad_2.11.svg)](https://maven-badges.herokuapp.com/maven-central/dev.playmonad/play26-monad_2.11)|[![Maven Central](https://img.shields.io/maven-central/v/dev.playmonad/play26-monad_2.12.svg)](https://maven-badges.herokuapp.com/maven-central/dev.playmonad/play26-monad_2.12)||\n| Play 2.7   ||[![Maven Central](https://img.shields.io/maven-central/v/dev.playmonad/play27-monad_2.11.svg)](https://maven-badges.herokuapp.com/maven-central/dev.playmonad/play27-monad_2.11)|[![Maven Central](https://img.shields.io/maven-central/v/dev.playmonad/play27-monad_2.12.svg)](https://maven-badges.herokuapp.com/maven-central/dev.playmonad/play27-monad_2.12)|[![Maven Central](https://img.shields.io/maven-central/v/dev.playmonad/play27-monad_2.13.svg)](https://maven-badges.herokuapp.com/maven-central/dev.playmonad/play27-monad_2.13)|\n| Play 2.8   |||[![Maven Central](https://img.shields.io/maven-central/v/dev.playmonad/play28-monad_2.12.svg)](https://maven-badges.herokuapp.com/maven-central/dev.playmonad/play28-monad_2.12)|[![Maven Central](https://img.shields.io/maven-central/v/dev.playmonad/play28-monad_2.13.svg)](https://maven-badges.herokuapp.com/maven-central/dev.playmonad/play28-monad_2.13)|\n\nTo add to your project, include this depedency in the `build.sbt` file:\n\n|            | SBT Dependency |\n|------------|----------------|\n| Play 2.3   |`libraryDependencies += \"dev.playmonad\" %% \"play23-monad\" % VERSION`|\n| Play 2.4   |`libraryDependencies += \"dev.playmonad\" %% \"play24-monad\" % VERSION`|\n| Play 2.5   |`libraryDependencies += \"dev.playmonad\" %% \"play25-monad\" % VERSION`|\n| Play 2.6   |`libraryDependencies += \"dev.playmonad\" %% \"play26-monad\" % VERSION`|\n| Play 2.7   |`libraryDependencies += \"dev.playmonad\" %% \"play27-monad\" % VERSION`|\n| Play 2.8   |`libraryDependencies += \"dev.playmonad\" %% \"play28-monad\" % VERSION`|\n\n## Preview\n\nWrite simple and reusable Play Action's using for-comprehensions.\n\n```scala\ndef saveAction = MonadicAction {\n  for {\n    auth \u003c- header(\"Authorization\")\n    user \u003c- authService.authorize(auth)\n    jsonBody \u003c- body(BodyParsers.parse.tolerantJson)\n  } yield {\n    // your business logic here\n  }\n}\n```\n\nEach step in the for-comprehension might fail. Just as a `Future` carries the concept of a hidden `Throwable`, this Monad carries a hidde failure `Result` response from Play. If the header is missing a `BadRequest` will be returned, if the authService doesn't authorize the request, a `Forbidden` will be returned and errors processing the body would return other error codes as well.\n\n## Motivation\n\n### Simpler and more composable request processing\n\n### Validating headers before processing the body\n\nThe original spark for the idea came to be when using Play Framework for a project where requests included huge file uploads.\nThese uploads could be in the hundreds of MB or even a few GBs. Uploading took a long time. It was possible headers were\ninvalid, user was not authenticated and other validations could go wrong. This could lead to a lot of wasted time when headers\nwhere invalid. HTTP supports the `100-continue` feature. It allows users to send the headers first, wait for confirmation\nthese are accepted and that it may continue to send the body.\n\nPlay supports the `100-continue` feature in principle but when using Play's Actions with body parsers, the body is\nprocessed fully before the headers. To leverage this feature a different way of constructing Actions is needed.\n\nFinally, to make sure every endpoint supports this, it is imperative all header processing happens before using the body.\nTo enable that it was needed to make the Monad stateful. Headers cannot be accessed after processing the body and this\nis enforced by the compiler.\n\n## Acknowledgements\n\nThe idea for this library was conceived by @rcano around 2012-2014 and was implemented in a closed project.\nSince then, this pattern has been re-implemented in other places by Tomás Lázaro (@tlazaro) in a different shape but same\nspirit. After many years seeing Play Actions has not changed and no implementation exists in the wild we decided to\ndo this work in open-source and share it.\n\nThe [play-monadic-actions](https://github.com/Kanaka-io/play-monadic-actions) shares the same core idea and has a variety\nof conversions that are very useful. However, it does not include the concept of a stateful Monad and does not enable\nusage of the 100-continue HTTP feature.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftlazaro%2Fplay-monad","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftlazaro%2Fplay-monad","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftlazaro%2Fplay-monad/lists"}