{"result":{"depiction_url":null,"edges":{"hasreference":{"objects":[{"created":"2026-10-07T11:13:39Z","object_id":{"id":2960,"is_a":["text","documentation","developerguide"],"name":"developer_model_api","title":{"_type":"trans","tr":{"en":"Expose data through a model"}},"uri":"https:\/\/zotonic.com\/id\/2960"},"seq":1}],"predicate":{"id":2774,"is_a":["meta","predicate"],"name":"hasreference","title":{"_type":"trans","tr":{"en":"Documentation reference"}},"uri":"https:\/\/zotonic.com\/id\/hasreference"}},"relation":{"objects":[{"created":"2020-05-30T05:48:14Z","object_id":{"id":1352,"is_a":["text","documentation","developerguide"],"name":"doc_developerguide_templates","title":{"_type":"trans","tr":{"en":"Create a page layout"}},"uri":"https:\/\/zotonic.com\/id\/1352"},"seq":1000000},{"created":"2020-05-30T05:48:14Z","object_id":{"id":322,"is_a":["meta","category"],"name":"model","title":"Models","uri":"https:\/\/test.zotonic.com\/id\/322"},"seq":1000000}],"predicate":{"id":303,"is_a":["meta","predicate"],"name":"relation","title":{"_type":"trans","tr":{"nl":"Relatie","en":"Relation"}},"uri":"http:\/\/purl.org\/dc\/terms\/relation"}},"subject":{"objects":[{"created":"2026-10-07T11:13:39Z","object_id":{"id":2557,"is_a":["categorization","keyword","keyword_information_type"],"name":"zotonic_topic_cookbook_recipe","title":"Cookbook recipe","uri":"https:\/\/zotonic.com\/id\/2557"},"seq":1},{"created":"2026-10-07T11:13:39Z","object_id":{"id":2564,"is_a":["categorization","keyword","keyword_audience"],"name":"zotonic_topic_backend_developer","title":"Backend developer","uri":"https:\/\/zotonic.com\/id\/2564"},"seq":2},{"created":"2026-10-07T11:13:39Z","object_id":{"id":2625,"is_a":["categorization","keyword","keyword_architecture"],"name":"zotonic_topic_model","title":"Model","uri":"https:\/\/zotonic.com\/id\/2625"},"seq":3},{"created":"2026-10-07T11:13:39Z","object_id":{"id":2599,"is_a":["categorization","keyword","keyword_domain"],"name":"zotonic_topic_api_and_integration","title":"API and integration","uri":"https:\/\/zotonic.com\/id\/2599"},"seq":4}],"predicate":{"id":308,"is_a":["meta","predicate"],"name":"subject","title":{"_type":"trans","tr":{"en":"Keyword"}},"uri":"http:\/\/purl.org\/dc\/elements\/1.1\/subject"}}},"id":1573,"is_a":["text","documentation","cookbook"],"links":[{"rel":"self","target":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/1573"},{"rel":"hub","target":"https:\/\/zotonic.com\/.zotonic\/websub"}],"medium":null,"medium_url":null,"name":"doc_cookbook_custom_model","page_url":{"en":"https:\/\/zotonic.com\/cookbook\/1573\/expose-data-through-a-model","x-default":"https:\/\/zotonic.com\/cookbook\/1573\/expose-data-through-a-model"},"preview_url":null,"resource":{"version":35,"pivot_location_lat":null,"title":{"_type":"trans","tr":{"en":"Expose data through a model"}},"is_authoritative":true,"body":{"_type":"trans","tr":{"en":"<p>Create <code>src\/models\/m_garden.erl<\/code> in the Garden module. This complete example exposes a public greeting:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-erlang\">-module(m_garden).\n-behaviour(zotonic_model).\n-export([m_get\/3]).\n\n-spec m_get(Path, Msg, Context) -&gt; Result\n    when\n        Path :: list(),\n        Msg :: zotonic_model:opt_msg(),\n        Context :: z:context(),\n        Result :: zotonic_model:return().\nm_get([&lt;&lt;&quot;greeting&quot;&gt;&gt; | Rest], _Msg, _Context) -&gt;\n    {ok, {&lt;&lt;&quot;Welcome to the garden&quot;&gt;&gt;, Rest}};\nm_get(_Path, _Msg, _Context) -&gt;\n    {error, unknown_path}.\n<\/code><\/pre>\n<p>Compile the application and confirm that Garden is active on the site. Read the value in a template:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-django\">&lt;p&gt;{{ m.garden.greeting|escape }}&lt;\/p&gt;\n<\/code><\/pre>\n<p>Expect the greeting in the rendered page. The callback matches binary path segments and returns the unused path for further lookup. Add explicit permission checks before returning private data, and validate input before an operation changes anything.<\/p>"}},"slug":"expose-data-through-a-model","is_protected":false,"visible_for":0,"tz":"UTC","language":["en"],"is_featured":false,"content_group_id":{"id":339,"is_a":["meta","content_group"],"name":"default_content_group","title":{"_type":"trans","tr":{"en":"Default Content Group"}},"uri":"https:\/\/zotonic.com\/id\/default_content_group"},"category_id":{"id":318,"is_a":["meta","category"],"name":"cookbook","title":{"_type":"trans","tr":{"en":"Cookbook"}},"uri":"https:\/\/test.zotonic.com\/id\/318"},"publication_start":"2022-02-15T10:01:00Z","is_website_redirect":false,"github_url":"https:\/\/github.com\/zotonic\/zotonic\/tree\/master\/doc\/cookbook\/custom-model.rst","pivot_location_lng":null,"name":"doc_cookbook_custom_model","is_unfindable":false,"is_published":true,"doc_editorial_edges":{"hasreference":[2960],"subject":[2557,2564,2599,2625]},"summary":{"_type":"trans","tr":{"en":"Create src\/models\/m_garden.erl in the Garden module. This complete example exposes a public greeting:"}},"pivot_geocode":null,"custom_slug":false,"created":"2020-05-30T05:47:26Z","uri":null,"date_is_all_day":false,"is_dependent":false,"is_page_path_multiple":false,"publication_end":"9999-08-17T12:00:00Z","modifier_id":{"id":1,"is_a":["person"],"name":"administrator","title":"Site Administrator","uri":"https:\/\/zotonic.com\/id\/1"},"privacy":0,"doc_editorial_bundle":true,"creator_id":{"id":336,"is_a":["person","robot"],"name":"gitbot","title":"Git","uri":"https:\/\/zotonic.com\/id\/336"},"seo_noindex":false,"modified":"2026-10-07T11:13:48Z","title_slug":{"_type":"trans","tr":{"en":"expose-data-through-a-model"}}},"uri":"https:\/\/zotonic.com\/id\/1573","uri_template":"https:\/\/zotonic.com\/id\/:id","websub":{"hub":"https:\/\/zotonic.com\/.zotonic\/websub","topic":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/1573"}},"status":"ok"}