diff --git a/docs/recipes/api-rendering.md b/docs/recipes/api-rendering.md new file mode 100644 index 00000000..9617f96e --- /dev/null +++ b/docs/recipes/api-rendering.md @@ -0,0 +1,25 @@ +# API rendering + +For additional flexibility, django-pattern-library supports rendering patterns via an API endpoint. +This can be useful when implementing a custom UI while still using the pattern library’s Django rendering features. + +The API endpoint is available at `api/v1/render-pattern`. It accepts POST requests with a JSON payload containing the following fields: + +- `template_name` – the path of the template to render +- `config` – the configuration for the template, with the same data structure as the configuration files (`context` and `tags`). + +Here is an example, with curl: + +```bash +echo '{"template_name": "patterns/molecules/button/button.html", "config": {"context": {"target_page": {"title": "API"}}, "tags": {"pageurl":{"target_page":{"raw": "/hello-api"}}}}}' | curl -d @- http://localhost:8000/api/v1/render-pattern +``` + +The response will be the pattern’s rendered HTML: + +```html + + API + +``` + +Note compared to iframe rendering, this API always renders the pattern’s HTML standalone, never within a base template. diff --git a/mkdocs.yml b/mkdocs.yml index b5b06784..381b9992 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -50,6 +50,7 @@ nav: - 'Inclusion tags': 'recipes/inclusion-tags.md' - 'Looping for tags': 'recipes/looping-for-tags.md' - 'Pagination': 'recipes/pagination.md' + - 'API rendering': 'recipes/api-rendering.md' - 'Reference': - 'API and settings': 'reference/api.md' - 'Concepts': 'reference/concepts.md' diff --git a/pattern_library/monkey_utils.py b/pattern_library/monkey_utils.py index f893a27a..b7c8f9b1 100644 --- a/pattern_library/monkey_utils.py +++ b/pattern_library/monkey_utils.py @@ -30,8 +30,7 @@ def node_render(context): tag_overridden = False result = "" - # Load pattern's config - current_template_name = parser.origin.template_name + # Get overriden tag config. tag_overrides = context.get("__pattern_library_tag_overrides", {}) # Extract values for lookup from the token @@ -87,7 +86,7 @@ def node_render(context): logger.warning( 'No default or stub data defined for the "%s" tag in the "%s" template', tag_name, - current_template_name, + parser.origin.template_name, ) return original_node_render(context) diff --git a/tests/tests/test_views.py b/tests/tests/test_views.py index abd5ddb4..92c3469d 100644 --- a/tests/tests/test_views.py +++ b/tests/tests/test_views.py @@ -116,3 +116,32 @@ def test_fragment_extended_from_variable(self): ), "base content - extended content", ) + + +class APIViewsTestCase(SimpleTestCase): + def test_renders_with_tag_overrides(self): + api_endpoint = reverse("pattern_library:render_pattern_api") + response = self.client.post( + api_endpoint, + content_type="application/json", + data={ + "template_name": "patterns/molecules/button/button.html", + "config": { + "context": {"target_page": {"title": "API"}}, + "tags": {"pageurl": {"target_page": {"raw": "/hello-api"}}}, + }, + }, + ) + self.assertContains(response, '/hello-api') + + def test_404(self): + api_endpoint = reverse("pattern_library:render_pattern_api") + response = self.client.post( + api_endpoint, + content_type="application/json", + data={ + "template_name": "doesnotexist.html", + "config": {}, + }, + ) + self.assertEqual(response.status_code, 404)