{"id":13726113,"url":"https://github.com/lemaetech/wtr","last_synced_at":"2025-05-07T21:31:21.416Z","repository":{"id":47150097,"uuid":"352616630","full_name":"lemaetech/wtr","owner":"lemaetech","description":"HTTP request routing library for OCaml web applications.","archived":false,"fork":false,"pushed_at":"2023-04-28T09:59:31.000Z","size":269,"stargazers_count":40,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-08-04T01:28:30.007Z","etag":null,"topics":["ocaml","router","webapp"],"latest_commit_sha":null,"homepage":"https://lemaetech.co.uk/wtr/","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lemaetech.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2021-03-29T11:19:51.000Z","updated_at":"2024-04-11T11:07:19.000Z","dependencies_parsed_at":"2024-01-06T02:03:04.420Z","dependency_job_id":"9b2502e8-21c9-4480-8e1a-8cfc33b2ea63","html_url":"https://github.com/lemaetech/wtr","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemaetech%2Fwtr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemaetech%2Fwtr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemaetech%2Fwtr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemaetech%2Fwtr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lemaetech","download_url":"https://codeload.github.com/lemaetech/wtr/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224654134,"owners_count":17347676,"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":["ocaml","router","webapp"],"created_at":"2024-08-03T01:02:52.921Z","updated_at":"2024-11-14T16:33:19.522Z","avatar_url":"https://github.com/lemaetech.png","language":"OCaml","funding_links":[],"categories":["OCaml"],"sub_categories":[],"readme":"# Wtr - Well Typed Router \n\nWtr - A HTTP request routing library for OCaml web applications.\n\n[Documentation](https://lemaetech.co.uk/wtr/)\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; [Examples](https://github.com/lemaetech/wtr/tree/main/examples) \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; [Summer Demo](https://github.com/lemaetech/summer/blob/main/examples/echo_server.ml)\n\n## Overview \n\n`wtr` is a HTTP request router for OCaml web applications.\n\n- It is trie based so route matching is efficient and fast.\n- Route handlers are type-checked during compilation.\n- Supports matching and capturing URI path components, eg `/home/about/:int`.\n- Supports matching and capturing URI query parameters, eg `/home/about?q=:int\u0026q1=hello`.\n- Supports matching HTTP methods, eg `GET, POST, PUT, HEAD, DELETE` etc.\n- Supports converting captured URI components to OCaml and custom user defined data types.\n- `%routes` ppx implements a DSL to allow you to easily specify HTTP uri. \n- combinatros based approach to specifying routes.\n\n## Wtr Demo\n\n```ocaml\n# #require \"wtr, wtr-ppx\";;\n```\n\n```ocaml\nmodule Fruit = struct\n  type t = Apple | Orange | Pineapple\n\n  let t : t Wtr.arg =\n    Wtr.arg \"fruit\" (function\n      | \"apple\" -\u003e Some Apple\n      | \"orange\" -\u003e Some Orange\n      | \"pineapple\" -\u003e Some Pineapple\n      | _ -\u003e None )\nend\n\nlet about_page = \"about page\"\nlet prod_page i = \"Int page. number : \" ^ string_of_int i\nlet float_page f = \"Float page. number : \" ^ string_of_float f\nlet contact_page nm num = \"Contact. Hi, \" ^ nm ^ \". Num \" ^ string_of_int num\nlet product1 name id q = Format.sprintf \"Product1 %s. Id: %d. q = %b\" name id q\nlet product2 name id = Format.sprintf \"Product2 %s. Id: %d.\" name id\n;;\nlet fruit_page = function\n  | Fruit.Apple -\u003e \"Apples are juicy!\"\n  | Orange -\u003e \"Orange is a citrus fruit.\"\n  | Pineapple -\u003e \"Pineapple has scaly skin\"\n\nlet faq category_id _ =\n  let category_name =\n    match category_id with\n    | 1 -\u003e \"products\"\n    | 2 -\u003e \"insurance\"\n    | 3 -\u003e \"returns\"\n    | _ -\u003e \"unknown\"\n  in\n  \"FAQ page for category : \" ^ category_name\n\nlet router =\n  Wtr.router      \n      [ {%routes| get,post,head,delete  ; /home/about/            |} about_page\n      ; {%routes| head,delete           ; /home/:int/             |} prod_page\n      ; {%routes| get,post              ; /home/:float/           |} float_page\n      ; {%routes| get; /contact/*/:int                            |} contact_page\n      ; {%routes| get; /product/:string?section=:int\u0026q=:bool      |} product1\n      ; {%routes| get; /product/:string?section=:int\u0026q1=yes       |} product2\n      ; {%routes| get; /fruit/:Fruit                              |} fruit_page\n      ; {%routes| GET; /faq/:int/**                               |} faq ]\n\nlet p () = \n  Printf.printf \"\\n====Router Match Results====\\n\" ;\n  [ Wtr.match' `GET \"/home/100001.1/\" router\n  ; Wtr.match' `DELETE \"/home/100001/\" router\n  ; Wtr.match' `GET \"/home/about/\" router\n  ; Wtr.match' `GET \"/product/dyson350?section=233\u0026q=true\" router\n  ; Wtr.match' `GET \"/product/dyson350?section=2\u0026q=false\" router\n  ; Wtr.match' `GET \"/product/dyson350?section=2\u0026q1=yes\" router\n  ; Wtr.match' `GET \"/product/dyson350?section=2\u0026q1=no\" router\n  ; Wtr.match' `GET \"/fruit/apple\" router\n  ; Wtr.match' `GET \"/fruit/orange\" router\n  ; Wtr.match' `GET \"/fruit/pineapple\" router\n  ; Wtr.match' `GET \"/fruit/guava\" router\n  ; Wtr.match' `GET \"/faq/1/\" router\n  ; Wtr.match' `GET \"/faq/1/whatever\" router\n  ; Wtr.match' `GET \"/faq/2/whateasdfasdfasdf\" router ]\n  |\u003e List.iteri (fun i -\u003e function\n       | Some s -\u003e Printf.printf \"%3d: %s\\n\" (i + 1) s\n       | None -\u003e Printf.printf \"%3d: None\\n\" (i + 1) );;\n```\n\n## Demo Output\n\n```ocaml\n# p () ;;\n====Router Match Results====\n  1: Float page. number : 100001.1\n  2: Int page. number : 100001\n  3: about page\n  4: Product1 dyson350. Id: 233. q = true\n  5: Product1 dyson350. Id: 2. q = false\n  6: Product2 dyson350. Id: 2.\n  7: None\n  8: Apples are juicy!\n  9: Orange is a citrus fruit.\n 10: Pineapple has scaly skin\n 11: None\n 12: FAQ page for category : products\n 13: FAQ page for category : products\n 14: FAQ page for category : insurance\n- : unit = ()\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flemaetech%2Fwtr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flemaetech%2Fwtr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flemaetech%2Fwtr/lists"}