{"id":33990289,"url":"https://github.com/stratadox/restresource","last_synced_at":"2026-04-18T21:34:16.312Z","repository":{"id":57060334,"uuid":"236607222","full_name":"Stratadox/RestResource","owner":"Stratadox","description":"Hateoas rest resource formatting in json and xml","archived":false,"fork":false,"pushed_at":"2020-02-02T21:15:47.000Z","size":61,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-13T15:18:25.210Z","etag":null,"topics":["hateoas","hateoas-hal","json","rest","rest-api","restful","restful-api","xml"],"latest_commit_sha":null,"homepage":"","language":"PHP","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/Stratadox.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":"2020-01-27T22:13:26.000Z","updated_at":"2020-02-02T21:08:30.000Z","dependencies_parsed_at":"2022-08-24T07:30:47.072Z","dependency_job_id":null,"html_url":"https://github.com/Stratadox/RestResource","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/Stratadox/RestResource","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stratadox%2FRestResource","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stratadox%2FRestResource/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stratadox%2FRestResource/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stratadox%2FRestResource/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Stratadox","download_url":"https://codeload.github.com/Stratadox/RestResource/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stratadox%2FRestResource/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27701347,"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-12-13T02:00:09.769Z","response_time":147,"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":["hateoas","hateoas-hal","json","rest","rest-api","restful","restful-api","xml"],"created_at":"2025-12-13T06:05:44.807Z","updated_at":"2025-12-13T06:05:45.975Z","avatar_url":"https://github.com/Stratadox.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Rest Resource\nHATEOAS-compatible Restful Resource descriptions, with formatters to represent \nthe resources in json- or xml format.\n\n[![Build Status](https://travis-ci.org/Stratadox/RestResource.svg?branch=master)](https://travis-ci.org/Stratadox/RestResource)\n[![Coverage Status](https://coveralls.io/repos/github/Stratadox/RestResource/badge.svg?branch=master)](https://coveralls.io/github/Stratadox/RestResource?branch=master)\n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/Stratadox/RestResource/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/Stratadox/RestResource/?branch=master)\n\n## Installation\nInstall with `composer require stratadox/rest-resource`\n\n## Example (json)\nResources formatted as json output:\n```php\n\u003c?php\n\nuse Stratadox\\RestResource\\BasicResource;\nuse Stratadox\\RestResource\\DefaultJsonFormatter;\nuse Stratadox\\RestResource\\Link;\nuse Stratadox\\RestResource\\Links;\nuse Stratadox\\RestResource\\Type;\n\n$json = DefaultJsonFormatter::fromBaseUri('https://a.server.somewhere/');\n\n$resource = new BasicResource(\n    'hateoas-resource',\n    ['foo' =\u003e 'bar'],\n    Links::provide(\n        Link::to('foo/1', Type::get('Foo'))\n    )\n);\n\n$this-\u003eassertJsonStringEqualsJsonString(\n    '{\n        \"hateoas-resource\": {\n            \"foo\": \"bar\",\n            \"links\": [\n                {\n                    \"href\": \"server\\/foo\\/1\",\n                    \"rel\": \"Foo\",\n                    \"type\": \"GET\"\n                }\n            ]\n        }\n    }',\n    $json-\u003efrom($resource)\n);\n```\n\n## Example (xml)\nThe same resource, now formatted as xml output:\n```php\n\u003c?php\n\nuse Stratadox\\RestResource\\BasicResource;\nuse Stratadox\\RestResource\\DefaultXmlFormatter;\nuse Stratadox\\RestResource\\Link;\nuse Stratadox\\RestResource\\Links;\nuse Stratadox\\RestResource\\Type;\n\n$xml = DefaultXmlFormatter::fromBaseUri('https://a.server.somewhere/');\n\n$resource = new BasicResource(\n    'hateoas-resource',\n    ['foo' =\u003e 'bar'],\n    Links::provide(\n        Link::to('foo/1', Type::get('Foo'))\n    )\n);\n\n$this-\u003eassertXmlStringEqualsXmlString(\n    '\u003c?xml version=\"1.0\"?\u003e\n    \u003chateoas-resource\u003e\n      \u003cfoo\u003ebar\u003c/foo\u003e\n      \u003clinks\u003e\n        \u003clink\u003e\n          \u003chref\u003eserver/foo/1\u003c/href\u003e\n          \u003crel\u003eFoo\u003c/rel\u003e\n          \u003ctype\u003eGET\u003c/type\u003e\n        \u003c/link\u003e\n      \u003c/links\u003e\n    \u003c/hateoas-resource\u003e',\n    $xml-\u003efrom($resource)\n);\n```\n\n## Example (condensed xml)\nThe same resource again, now formatted as xml with less verbosity:\n\n```php\n\u003c?php\n\nuse Stratadox\\RestResource\\BasicResource;\nuse Stratadox\\RestResource\\CondensedXmlFormatter;\nuse Stratadox\\RestResource\\Link;\nuse Stratadox\\RestResource\\Links;\nuse Stratadox\\RestResource\\Type;\n\n$xml = CondensedXmlFormatter::fromBaseUri('https://a.server.somewhere/');\n\n$resource = new BasicResource(\n    'hateoas-resource',\n    ['foo' =\u003e 'bar'],\n    Links::provide(\n        Link::to('foo/1', Type::get('Foo'))\n    )\n);\n\n$this-\u003eassertXmlStringEqualsXmlString(\n    '\u003c?xml version=\"1.0\"?\u003e\n    \u003chateoas-resource foo=\"bar\"\u003e\n      \u003clinks\u003e\n        \u003clink href=\"server/foo/1\" rel=\"Foo\" type=\"GET\" /\u003e\n      \u003c/links\u003e\n    \u003c/hateoas-resource\u003e',\n    $xml-\u003efrom($resource)\n);\n```\n\n## Singularisation\nFormatting an xml document based on just an array structure is slightly more \nchallenging than converting to json.\n\nFor example, given the input:\n```php\n[\n    'people' =\u003e [\n        [\n            'id' =\u003e 1,\n            'name' =\u003e 'Alice',\n        ],\n        [\n            'id' =\u003e 2,\n            'name' =\u003e 'Bob',\n        ],\n    ]\n];\n```\n\nIn json, one might have output like this:\n```json\n{\n  \"people\": [\n    {\n      \"id\": 1,\n      \"name\": \"Alice\"\n    },\n    {\n      \"id\": 2,\n      \"name\": \"Bob\"\n    }\n  ]\n}\n```\n\nHowever, we'd expect from xml something in the genre of:\n```xml\n\u003cpeople\u003e\n    \u003cperson\u003e\n        \u003cid\u003e1\u003c/id\u003e\n        \u003cname\u003eAlice\u003c/name\u003e\n    \u003c/person\u003e\n    \u003cperson\u003e\n        \u003cid\u003e2\u003c/id\u003e\n        \u003cname\u003eBob\u003c/name\u003e\n    \u003c/person\u003e\n\u003c/people\u003e\n```\nOr\n```xml\n\u003cpeople\u003e\n    \u003cperson id=\"1\" name=\"Alice\" /\u003e\n    \u003cperson id=\"2\" name=\"Bob\" /\u003e\n\u003c/people\u003e\n```\n\nBy default, the xml formatter uses [inflection](https://github.com/ICanBoogie/Inflector) \nto transform plurals into singular versions. As such, the aforementioned php \narray structure would indeed produce the expected xml.\nAny language supported by the inflector can be used, for example:\n\n```php\n\u003c?php\n\nuse Stratadox\\RestResource\\BasicResource;\nuse Stratadox\\RestResource\\DefaultXmlFormatter;\nuse Stratadox\\RestResource\\Links;\n\n$xml = DefaultXmlFormatter::in('fr', '/');\n\n$resource = new BasicResource(\n    'resource-travaux',\n    ['travaux' =\u003e ['foo', 'bar', 'baz']],\n    Links::none()\n);\n\n$this-\u003eassertXmlStringEqualsXmlString(\n    '\u003c?xml version=\"1.0\"?\u003e\n    \u003cresource-travaux\u003e\n        \u003ctravaux\u003e\n            \u003ctravail\u003efoo\u003c/travail\u003e\n            \u003ctravail\u003ebar\u003c/travail\u003e\n            \u003ctravail\u003ebaz\u003c/travail\u003e\n        \u003c/travaux\u003e\n    \u003c/resource-travaux\u003e',\n    $xml-\u003efrom($resource)\n);\n```\n\nAny singularizer can be used. \nIf you don't wish to run the risk of using terms that cannot be transformed into \nsingular versions, the basic singularizer might be an option, although it would \nproduce xml like the following example:\n\n```php\n\u003c?php\n\nuse Stratadox\\RestResource\\BasicResource;\nuse Stratadox\\RestResource\\BasicSingularizer;\nuse Stratadox\\RestResource\\DefaultXmlFormatter;\nuse Stratadox\\RestResource\\Links;\n\n$xml = DefaultXmlFormatter::withSingularizer('/', new BasicSingularizer());\n\n$resource = new BasicResource(\n    'people-resource',\n    ['people' =\u003e [\n        ['id' =\u003e 1, 'name' =\u003e 'Alice'],\n        ['id' =\u003e 2, 'name' =\u003e 'Bob'],\n    ]],\n    Links::none()\n);\n\n$this-\u003eassertXmlStringEqualsXmlString(\n    '\u003c?xml version=\"1.0\"?\u003e\n    \u003cpeople-resource\u003e\n        \u003cpeople\u003e\n            \u003citem\u003e\n                \u003cid\u003e1\u003c/id\u003e\n                \u003cname\u003eAlice\u003c/name\u003e\n            \u003c/item\u003e\n            \u003citem\u003e\n                \u003cid\u003e2\u003c/id\u003e\n                \u003cname\u003eBob\u003c/name\u003e\n            \u003c/item\u003e\n        \u003c/people\u003e\n    \u003c/people-resource\u003e',\n    $xml-\u003efrom($resource)\n);\n```\nOr, with less verbosity:\n\n```php\n\u003c?php\n\nuse Stratadox\\RestResource\\BasicResource;\nuse Stratadox\\RestResource\\BasicSingularizer;\nuse Stratadox\\RestResource\\CondensedXmlFormatter;\nuse Stratadox\\RestResource\\Links;\n\n$xml = CondensedXmlFormatter::withSingularizer('/', new BasicSingularizer());\n\n$resource = new BasicResource(\n    'people-resource',\n    ['people' =\u003e [\n        ['id' =\u003e 1, 'name' =\u003e 'Alice'],\n        ['id' =\u003e 2, 'name' =\u003e 'Bob'],\n    ]],\n    Links::none()\n);\n\n$this-\u003eassertXmlStringEqualsXmlString(\n    '\u003c?xml version=\"1.0\"?\u003e\n    \u003cpeople-resource\u003e\n        \u003cpeople\u003e\n            \u003citem id=\"1\" name=\"Alice\" /\u003e\n            \u003citem id=\"2\" name=\"Bob\" /\u003e\n        \u003c/people\u003e\n    \u003c/people-resource\u003e',\n    $xml-\u003efrom($resource)\n);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstratadox%2Frestresource","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstratadox%2Frestresource","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstratadox%2Frestresource/lists"}