{"id":17597325,"url":"https://github.com/battermann/fsharp-hypermedia","last_synced_at":"2025-03-29T20:26:26.477Z","repository":{"id":86688915,"uuid":"79247357","full_name":"battermann/fsharp-hypermedia","owner":"battermann","description":"F# JSON support for hypermedia types (HAL, Siren)","archived":false,"fork":false,"pushed_at":"2017-02-17T21:42:49.000Z","size":77,"stargazers_count":0,"open_issues_count":1,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-04T21:20:29.709Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"F#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/battermann.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-01-17T16:28:48.000Z","updated_at":"2017-01-27T19:24:40.000Z","dependencies_parsed_at":null,"dependency_job_id":"d8c918e8-32ec-421f-9167-3f6cc0955d6e","html_url":"https://github.com/battermann/fsharp-hypermedia","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/battermann%2Ffsharp-hypermedia","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/battermann%2Ffsharp-hypermedia/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/battermann%2Ffsharp-hypermedia/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/battermann%2Ffsharp-hypermedia/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/battermann","download_url":"https://codeload.github.com/battermann/fsharp-hypermedia/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246239830,"owners_count":20745775,"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-22T09:24:49.692Z","updated_at":"2025-03-29T20:26:26.448Z","avatar_url":"https://github.com/battermann.png","language":"F#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# F# JSON support for HAL and Siren hypermedia types\n\nThis is a first, raw version.\n\nDefine [HAL resource](http://stateless.co/hal_specification.html) or [Siren](https://github.com/kevinswiber/siren) representations in F# and convert them to JSON.\n\n* Idiomatic support for F#\n* Supports multiple serializers / formats (e.g. Newtonsoft.Json (obj), Chiron.Json, FSharp.Data.JsonValue)\n* Extendable with other formats\n* Mediatypes\n  * `application/hal+json` ([spec](http://stateless.co/hal_specification.html))\n  * `application/vnd.siren+json` ([spec](https://github.com/kevinswiber/siren))\n* Framework agnostic\n* Mostly single file module - easy to use with Paket\n\n## TOC\n\n* [Using fsharp-hypermedia with Paket](http://github.com/battermann/fsharp-hypermedia#using-fsharp-hypermedia-with-paket)\n* [HAL Example with Newtonsoft.Json](http://github.com/battermann/fsharp-hypermedia#hal-example-with-newtonsoftjson)\n* [Siren Example with FSharp.Data](http://github.com/battermann/fsharp-hypermedia#siren-example-with-fsharpdata)\n\n## Using fsharp-hypermedia with Paket\n\nIt is convienient to get fsharp-hypermedia with Paket GitHub dependencies. To do so, just add following line to your `paket.dependencies` file:\n\n    github battermann/fsharp-hypermedia src/Hypermedia/Hypermedia.fs\n\nand the following line to your `paket.references` file for the desired project:\n\n    File:Hypermedia.fs .\n    \nThis includes the object intepreter, needed to use the Newtonsoft.Json serializer.\n\nThe FSharp.Data.JsonValue or the Chiron interpreter have to be referenced explicitly. For example like this:\n\n    github battermann/fsharp-hypermedia /src/Hypermedia/FsharpDataInterpreter.fs\n    \nand in the `paket.references` file for the desired project accordingly:\n\n    File:FsharpDataInterpreter.fs .\n \nIn `.fsx` scripts the dependent libraries have to be loaded before.\n\n## HAL Example with Newtonsoft.Json\n\n[Complete source script](http://github.com/battermann/fsharp-hypermedia/blob/master/HalExamples.fsx)\n\nCreate instances of the response body models:\n\n```fsharp\nlet payment = {\n    subtotal = 49m\n    tax = 0m\n    freight = 5m\n    total = 44m\n}\n\nlet coupon = {\n    ``type`` = \"dollarOff\"\n    amount = 10m\n    code = \"A0318A97\"\n}\n\nlet shipping = {\n    firstName = \"Heman\"\n    lastName = \"Radtke\"\n    address = \"1234 Day St.\"\n    city = \"Los Angeles\"\n    state = \"CA\"\n    zipcode = \"90015\"\n    countryIso = \"US\"\n}\n\nlet billing = {\n    firstName = \"Heman\"\n    lastName = \"Radtke\"\n    address = \"1234 Day St.\"\n    city = \"Los Angeles\"\n    state = \"CA\"\n    zipcode = \"90015\"\n    countryIso = \"US\"\n    cardNumber = \"1111\"\n    cardType = \"mastercard\"\n    cardExpYear = \"2015\"\n    cardExpMonth = \"01\"\n}\n```\n\n### Create embedded resources\n\nCreate empty resources and:\n\n* add the record type instances as payload\n* add links\n\n```fsharp\nlet couponResource =\n    Resource.empty\n    |\u003e Resource.withPayload coupon\n    |\u003e Resource.addLink \"self\" (Link.create (relUri \"/api/members/109087/coupons/654\"))\n\nlet shippingResource =\n    Resource.empty\n    |\u003e Resource.withPayload shipping\n    |\u003e Resource.addLink \"self\" (Link.create (relUri \"/api/members/109087/shippings/135451\"))\n\nlet billingResource =\n    Resource.empty\n    |\u003e Resource.withPayload billing\n    |\u003e Resource.addLink \"self\" (Link.create (relUri \"/api/members/109087/billings/135451\"))\n```\n\n### Create the main resource\n\nNow the main resource can be created by adding the\n\n* payload\n* links\n* embedded resources\n* curies\n\n```fsharp\nlet resource =\n    Resource.empty\n    |\u003e Resource.withPayload payment\n    |\u003e Resource.addLink \"self\" (Link.create (relUri \"/api/member/109087/payments/8888\"))\n    |\u003e Resource.addLink \"http://example.com/docs/rels/billing\" (Link.create (relUri \"/api/member/109087/billings/135451\"))\n    |\u003e Resource.addLink \"http://example.com/docs/rels/shipping\" (Link.create (relUri \"/api/member/109087/shipping/135451\"))\n    |\u003e Resource.addLink \"http://example.com/docs/rels/coupon\" (Link.create (relUri \"/api/member/109087/coupons/654\"))\n    |\u003e Resource.addEmbedded \"http://www.example.com/docs/rels/coupon\" couponResource\n    |\u003e Resource.addEmbedded \"http://www.example.com/docs/rels/shipping\" shippingResource\n    |\u003e Resource.addEmbedded \"http://www.example.com/docs/rels/billing\" billingResource\n    |\u003e Resource.withCuries [ \"ns\", Uri \"http://www.example.com/docs/rels/{rel}\" ]\n```\n\n### Serialization\n\nSerialize the resource with Newtonsoft.Json:\n\n```fsharp\nlet serialize x = JsonConvert.SerializeObject(x, Formatting.Indented)\n\nresource\n|\u003e ObjectInterpreter.Hal.toJson // returns obj\n|\u003e serialize\n|\u003e printfn \"%A\"\n```\n\n### Output\n\n```json\n{\n  \"_embedded\": {\n    \"ns:billing\": {\n      \"_links\": {\n        \"self\": {\n          \"href\": \"/api/members/109087/billings/135451\"\n        }\n      },\n      \"address\": \"1234 Day St.\",\n      \"cardExpMonth\": \"01\",\n      \"cardExpYear\": \"2015\",\n      \"cardNumber\": \"1111\",\n      \"cardType\": \"mastercard\",\n      \"city\": \"Los Angeles\",\n      \"countryIso\": \"US\",\n      \"firstName\": \"Heman\",\n      \"lastName\": \"Radtke\",\n      \"state\": \"CA\",\n      \"zipcode\": \"90015\"\n    },\n    \"ns:coupon\": {\n      \"_links\": {\n        \"self\": {\n          \"href\": \"/api/members/109087/coupons/654\"\n        }\n      },\n      \"amount\": 10.0,\n      \"code\": \"A0318A97\",\n      \"type\": \"dollarOff\"\n    },\n    \"ns:shipping\": {\n      \"_links\": {\n        \"self\": {\n          \"href\": \"/api/members/109087/shippings/135451\"\n        }\n      },\n      \"address\": \"1234 Day St.\",\n      \"city\": \"Los Angeles\",\n      \"countryIso\": \"US\",\n      \"firstName\": \"Heman\",\n      \"lastName\": \"Radtke\",\n      \"state\": \"CA\",\n      \"zipcode\": \"90015\"\n    }\n  },\n  \"_links\": {\n    \"curies\": [\n      {\n        \"href\": \"http://www.example.com/docs/rels/{rel}\",\n        \"name\": \"ns\",\n        \"templated\": true\n      }\n    ],\n    \"ns:billing\": {\n      \"href\": \"/api/member/109087/billings/135451\"\n    },\n    \"ns:coupon\": {\n      \"href\": \"/api/member/109087/coupons/654\"\n    },\n    \"ns:shipping\": {\n      \"href\": \"/api/member/109087/shipping/135451\"\n    },\n    \"self\": {\n      \"href\": \"/api/member/109087/payments/8888\"\n    }\n  },\n  \"freight\": 5.0,\n  \"subtotal\": 49.0,\n  \"tax\": 0.0,\n  \"total\": 44.0\n}\n```\n\n## Siren Example with FSharp.Data\n\n[Complete source script](https://github.com/battermann/fsharp-hypermedia/blob/master/SirenExamples.fsx)\n\nDefine embedded link:\n\n```fsharp\nlet itemsLink = \n    Link.create (Rel \"http://x.io/rels/order-items\") (Href (Uri \"http://api.x.io/orders/42/items\"))\n    |\u003e Link.withClasses [ \"collection\"; \"items\" ]\n```\n\nDefine an embedded entity:\n\n```fsharp\nlet customer =\n    Entity.empty\n    |\u003e Entity.withClasses [ \"customer\"; \"info\" ]\n    |\u003e Entity.addProperty \"customerId\" (JsonValue.String \"pj123\")\n    |\u003e Entity.addProperty \"name\" (JsonValue.String \"Peter Joseph\")\n    |\u003e Entity.withLinks [ Link.create (Rel \"self\") (Href (Uri \"http://api.x.io/customers/pj123\")) ]\n```\n\nDefine an action:\n\n```fsharp\nlet addItemAction = {\n    Action.create (Href (Uri \"http://api.x.io/orders/42/items\")) with\n        title = Some (Title \"Add Item\")\n        httpMethod = Some HttpMethod.POST\n        mediaType = Some (MediaType \"application/x-www-form-urlencoded\")\n        fields = Map.ofList [ Name \"orderNumber\", { Field.empty with inputType = Some InputType.Hidden; value = Some (Value \"42\") }\n                              Name \"productCode\", { Field.empty with inputType = Some InputType.Text }\n                              Name \"quantity\", { Field.empty with inputType = Some InputType.Number } ]\n}\n```\n\nBuild the main entity:\n\n```fsharp\nlet entity =\n    Entity.empty\n    |\u003e Entity.addProperty \"orderNumber\" (JsonValue.Number 42m)\n    |\u003e Entity.addProperty \"itemCount\" (JsonValue.Number 3m)\n    |\u003e Entity.addProperty \"status\" (JsonValue.String \"pending\")\n    |\u003e Entity.withClasses [ \"order\" ]       \n    |\u003e Entity.addEmbeddedLink itemsLink\n    |\u003e Entity.addEmbeddedEntity customer \"http://x.io/rels/customer\"\n    |\u003e Entity.withActions [ \"add-item\", addItemAction ] \n    |\u003e Entity.withLinks [ Link.create (Rel \"self\") (Href (Uri \"http://api.x.io/orders/42\"))\n                          Link.create (Rel \"previous\") (Href (Uri \"http://api.x.io/orders/41\"))\n                          Link.create (Rel \"next\") (Href (Uri \"http://api.x.io/orders/43\")) ]\n```\n\nSerialization:\n\n```fsharp\nFSharpDataIntepreter.Siren.toJSon entity\n|\u003e fun x -\u003e x.ToString()\n|\u003e printfn \"%A\"\n```\n\nOutput:\n\n```json\n{\n  \"actions\": [\n    {\n      \"fields\": [\n        {\n          \"name\": \"orderNumber\",\n          \"type\": \"hidden\",\n          \"value\": \"42\"\n        },\n        {\n          \"name\": \"productCode\",\n          \"type\": \"text\"\n        },\n        {\n          \"name\": \"quantity\",\n          \"type\": \"number\"\n        }\n      ],\n      \"href\": \"http://api.x.io/orders/42/items\",\n      \"method\": \"POST\",\n      \"name\": \"add-item\",\n      \"title\": \"Add Item\",\n      \"type\": \"application/x-www-form-urlencoded\"\n    }\n  ],\n  \"class\": [\n    \"order\"\n  ],\n  \"entities\": [\n    {\n      \"class\": [\n        \"customer\",\n        \"info\"\n      ],\n      \"links\": [\n        {\n          \"href\": \"http://api.x.io/customers/pj123\",\n          \"rel\": [\n            \"self\"\n          ]\n        }\n      ],\n      \"properties\": {\n        \"customerId\": \"pj123\",\n        \"name\": \"Peter Joseph\"\n      },\n      \"rel\": [\n        \"http://x.io/rels/customer\"\n      ]\n    },\n    {\n      \"class\": [\n        \"collection\",\n        \"items\"\n      ],\n      \"href\": \"http://api.x.io/orders/42/items\",\n      \"rel\": [\n        \"http://x.io/rels/order-items\"\n      ]\n    }\n  ],\n  \"links\": [\n    {\n      \"href\": \"http://api.x.io/orders/42\",\n      \"rel\": [\n        \"self\"\n      ]\n    },\n    {\n      \"href\": \"http://api.x.io/orders/41\",\n      \"rel\": [\n        \"previous\"\n      ]\n    },\n    {\n      \"href\": \"http://api.x.io/orders/43\",\n      \"rel\": [\n        \"next\"\n      ]\n    }\n  ],\n  \"properties\": {\n    \"itemCount\": 3,\n    \"orderNumber\": 42,\n    \"status\": \"pending\"\n  }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbattermann%2Ffsharp-hypermedia","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbattermann%2Ffsharp-hypermedia","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbattermann%2Ffsharp-hypermedia/lists"}