Copyright | (c) Alexey Radkov 2020 |
---|---|
License | BSD-style |
Maintainer | alexey.radkov@gmail.com |
Stability | experimental |
Portability | non-portable (requires Template Haskell) |
Safe Haskell | None |
Language | Haskell98 |
EDE templates for parsing JSON objects from the more extra tools collection for nginx-haskell-module.
Synopsis
- renderEDETemplate :: ByteString -> ByteString -> IO ByteString
Rendering JSON objects using EDE templates
This module allows for complex parsing of JSON objects with EDE templating language. In terms of module NgxExport.Tools, it exports a single-shot service compileEDETemplates to configure the list of templates parameterized by a simple key, and an asynchronous variable handler renderEDETemplate for parsing POSTed JSON objects and substitution of extracted data in the provided EDE template.
Below is a simple example.
File test_tools_extra_ede.hs
{-# OPTIONS_GHC -Wno-unused-imports #-} module TestToolsExtraEDE where import NgxExport.Tools.EDE
This file does not contain any significant declarations as soon as we do not require anything besides the two exporters. As soon as imported entities are not used, option -Wno-unused-imports was added on the top of the file.
File nginx.conf
user nobody; worker_processes 2; events { worker_connections 1024; } http { default_type application/octet-stream; sendfile on; haskell load /var/lib/nginx/test_tools_extra_ede.so; haskell_run_service simpleService_compileEDETemplates $hs_EDETemplates '("/var/lib/nginx/EDE", [("user", "{{user.id}}/{{user.ops|b64}}/{{resources.path|uenc}}")])'; server { listen 8010; server_name main; error_log /tmp/nginx-test-haskell-error.log; access_log /tmp/nginx-test-haskell-access.log; location / { haskell_run_async_on_request_body renderEDETemplate $hs_user user; rewrite ^ /internal/user/$hs_user last; } location ~ ^/internal/user/(EDE\ ERROR:.*) { internal; echo_status 404; echo "Bad input: $1"; } location ~ ^/internal/user/([^/]+)/([^/]+)/([^/]+)$ { internal; echo "User id: $1, options: $2, path: $3"; } location ~ ^/internal/user/(.*) { internal; echo_status 404; echo "Unexpected input: $1"; } } }
There is an EDE template declared by the argument of the service simpleService_compileEDETemplates. The template will be accessed later in the asynchronous body handler renderEDETemplate with the key user. The path /var/lib/nginx/EDE can be used in the templates to include more rules from files located inside it, but we do not actually use this here.
The rule inside template user says: with given JSON object,
- print object id inside a top object user,
- print slash,
- print object ops inside the top object user filtered by function b64,
- print slash,
- print object path inside a top object resources filtered by function uenc.
Functions b64 and uenc are polymorphic filters in terms of EDE language. There are many filters shipped with EDE, but b64 and uenc were defined in this module.
- b64 encodes a JSON object using base64url encoding
- uenc encodes a JSON object using URL encoding rules
So, basically, we used renderEDETemplate to decompose POSTed JSON objects and then rewrite requests to other locations where extracted fields were encoded inside the location's URL path.
A simple test
$ curl -d '{"user": {"id" : "user1", "ops": ["op1", "op2"]}, "resources": {"path": "/opt/users"}}' 'http://localhost:8010/' User id: user1, options: WyJvcDEiLCJvcDIiXQ==, path: %2Fopt%2Fusers
Let's try to send a broken (in any meaning) input value.
$ curl -d '{"user": {"id" : "user1", "ops": ["op1", "op2"]}, "resources": {"p": "/opt/users"}}' 'http://localhost:8010/' Bad input: EDE ERROR: Text.EDE.parse:1:32 error: variable resources.path doesn't exist.
Now we got response with HTTP status 404 and a comprehensive description of what went wrong. To not mess rewrite logic and error responses, variable $hs_user can be listed inside directive haskell_var_empty_on_error in the Nginx configuration.
haskell_var_empty_on_error $hs_user;
Now the variable will always be empty on errors, while the errors will still be logged by Nginx in the error log.
:: ByteString | JSON object |
-> ByteString | Key to find the EDE template |
-> IO ByteString |
The core function of the renderEDETemplate exporter.
Accepts a JSON object written in a ByteString
and a key to find the EDE
template declared by the compileEDETemplates exporter. The function is
exported because it can be useful not only in asynchronous body handlers but
anywhere else.