Renderer

Renderer Service

const { Job } = require('renderer'),
      job = new Job(apiKey)

Renderer is a service that converts templates (HTML and CSS) into export formats (PDF, CSV, and HTML). It can then send these exported files to various targets (FileObject, SFTP, FTP, or base64 result).

Tip: To enable Renderer for your environment, please contact support.

module Renderer

constructor(apiKey)

Creates an instance of Renderer.

Arguments

  • apiKey { String } API key of an existing app.

  • options { Object } Defines request options.

    • encodeBase64 { Boolean = false } Enable base64 encoding.

Returns

  • { renderer.Job } A new render job instance.

addObject(name, data)

Adds a single object array or plain JavaScript object. A template can reference an object directly.

Arguments

  • name { String } Top-level template data object key.

  • data { Object|Array } Data to be referenced in the template.

Returns

  • { renderer.Job } this.

const { Job } = require('renderer'),
      job = new Job(apiKey)

return job
  .addObject('values', [{val: 'one'}, {val: 'two'}])
  .addTemplate('tpl', `   
    {{#each values}}
      <h1>{{val}}</h1>           
    {{/each}}
  `)  

addCursor(name, cursor)

Adds a QueryCursor or AggregationCursor. JSON Web Tokens (JWTs) are created from the current principal and cursor options.

Arguments

  • name { String } The input name for use in referencing the data in templates.

  • cursor { QueryCursor|AggregationCursor } The cursor, for example, org.objects.c_studies.find().paths('c_name).

Returns

  • { renderer.Job } this.

addApiRequest(name, path, environment, credentials, options, [requestOptions={}])

Adds a request object that will be used from Renderer. It can be a custom route or any other API request. You can use the result in the templates.

Arguments

  • name { String } Used to reference this data in the templates.

  • path { String } Path to request, for example, /c_patients/234523423423.

  • environment { Object } Environment object.

    • endpoint: { String } Environment URL to use, for example, https://api.dev.medable.com.

    • env: { String } Environment code, for example, dev, prod, or qa.

  • credentials { Object } Credentials object.

    • type { String } Token or signature types are allowed.

    • token { String } Token data if type is set to token.

    • signature { String } Signature data if type is set to signature.

    • apiKey { String } If not set, default job apiKey is used.

  • options { Object } Describes request options such as method, body, and query.

  • requestOptions { Object } Describes extra options like json and strictSSL.

Returns

  • { renderer.Job } this.

addTemplate(name, [content, partial=false])

Adds an already saved HTML or CSS template, or can define an inline template. If you set the content argument, it behaves as an inline template.

Arguments

  • name { String } Defines the name that is used in the template.

  • content { String } Inline content. You can reference objects, requests, and so on.

  • partial { Boolean } Defines whether the template behaves as a partial template. You can exclude partial templates from other templates.

Returns

  • { renderer.Job } this.

addOutput(name, type, templates, options)

Defines the output format of the entire process.

Arguments

  • name { String } Defines name. You can use this in the templates.

  • type { String } Defines the output format type: PDF, CSV, or HTML.

  • templates { String[] } Defines the templates to be used in the output. Templates are processed sequentially.

  • options { Object | Array } Defines output options for CSV and PDF format types. There are no HTML output options. See the Output options section below for the full list of options. You can refer to the Prince command-line documentation for more details on the options listed below.

Output options

CSV output options

  • column delimiters

    • , - comma

    • ; - semicolon

    • | - vertical line

  • line delimiters

    • \r - carriage return

    • \n- new line

    • \n\r - both

PDF output options

  • input

  • media

  • page-size

  • page-margin

  • pdf-profile

  • pdf-lang

  • tagged-pdf

  • no-artificial-fonts

  • no-embed-fonts

  • no-subset-fonts

  • force-identity-encoding

  • no-compress

  • no-object-streams

  • pdf-title

  • pdf-subject

  • pdf-author

  • pdf-keywords

  • pdf-creator

  • encrypt

  • key-bits

  • user-password

  • owner-password

  • disallow-print

  • disallow-copy

  • disallow-annotate

  • disallow-modify

Returns

  • { renderer.Job } this.

addSftpTarget(outputs, credentials, options)

Specifies an SFTP target.

Arguments

  • outputs { Object } Defines a key or value object, where key is the name of an output and value is the filename representing that output into the remote location.

  • credentials { Object } Defines the credentials to connect to the remote server.

    • host { String } Server domain name or IP address.

    • port { Number = 22 } SFTP server port.

    • username { String } Username for authentication.

    • password { String } Password for authentication.

    • privateKey { String } String containing a private key for key-based or host-based user authentication.

    • passphrase { String } The passphrase to decrypt an encrypted private key.

    • localHostname { String } Along with localUsername and privateKey, set this to a non-empty string for host-based user authentication.

    • localUsername { String } Along with localHostname and privateKey, set this value to a non-empty string for host-based user authentication.

    • hostHash { String = md5 } A valid hash algorithm to check against the host fingerprint.

    • hostFingerprint { String } Use together with hostHash to verify the host fingerprint.

  • options { Object } Defines options for the target.

    • compress: { Object } Defines the compression options for the target.

      • filename: { String } Filename specifying the remote location, for example, /documents/my_document.zip.

      • outputs: { String[] } Defines the outputs to include in the bundle.

Returns

  • { renderer.Job } this.

addFtpTarget(outputs, credentials)

Specifies an FTP target.

Note: You must have access to an FTP server and know the following values: host, port, username, and password.

Tip: If you set the host with an IP address, you should also set the secureOption rejectUnauthorized to false to avoid potential conflicts with the domain name on the server certificate, as provided by the TLS Server Name Indication (SNI) extension.

Arguments

  • outputs { Object } Defines a key or value object, where key is the name of an output and value is the filename representing that output into the remote location.

  • credentials { Object } Defines the credentials to connect to the remote server.

    • host { String = localhost } FTP server domain name or IP address.

    • port { Number = 21 } FTP server port.

    • username { String = anonymous } Username for authentication.

    • password { String = anonymous@ } Password for authentication.

    • connTimeout { Number = 10000 } Wait time in milliseconds to establish a control connection.

    • pasvTimeout { Number = 10000 } Wait time in milliseconds to establish a PASV data connection.

    • keepalive { Number = 10000 } Wait time in milliseconds to send a dummy (NOOP) command to keep the connection alive.

    • secure { Mixed = true } Always set to true for control and data encryption.

    • secureOptions { Object } Additional options to be passed to tls.connect(), as listed below. For more details, view the Node.js TLS module reference.

      • ca { String, String[], Buffer, Buffer[] } Overrides default Certificate Authority (CA) certificates.

      • cert { String, String[], Buffer, Buffer[] } Defines certification chains in Privacy-Enhanced Mail (PEM) format.

      • sigalgs { String } Defines a list of supported signature algorithms.

      • ciphers { String } Replaces the cipher suite specification.

      • crl { String, String[], Buffer, Buffer[] } Defines PEM-formatted Certificate Revocation Lists (CRLs).

      • dhparam { String, Buffer } Defines Diffie–Hellman parameters.

      • ecdhCurve { String } Describes a named curve or a colon-separated list of curve NIDs or names to use for Elliptic-curve Diffie–Hellman (ECDH) key agreement. Default: tls.DEFAULT_ECDH_CURVE.

      • honorCipherOrder { Boolean } Attempts to use the cipher suite preferences of the server instead of the client.

      • key { String, String[], Buffer, Buffer[], Object[] } Sets private keys in PEM format.

      • minVersion { String } Allows you to choose the minimum allowable TLS version from the following: 'TLSv1.3', 'TLSv1.2', 'TLSv1.1', or 'TLSv1'. Default: tls.DEFAULT_MIN_VERSION.

      • maxVersion { String } Allows you to choose the maximum allowable TLS version from the following: 'TLSv1.3', 'TLSv1.2', 'TLSv1.1', or 'TLSv1'. This option cannot be used in conjunction with secureProtocol; you can only use one or the other. Default: tls.DEFAULT_MAX_VERSION.

      • passphrase { String } Shared passphrase used for a single private key or a PFX.

      • pfx { String, String[], Buffer, Buffer[], Object[] } Defines the PFX or PKCS12 encoded private key and certificate chain.

      • secureProtocol { String } Provides a legacy mechanism to select the TLS protocol version to use. It does not support independent control of the minimum and maximum versions. It also does not support limiting the protocol to TLSv1.3. If you wish to do so, use minVersion and maxVersion instead. Default: none, see minVersion.

      • rejectUnauthorized { Boolean = true } If true, the server certificate is verified against the supplied list of CAs.

Returns

  • { renderer.Job } this.

addFileTarget(path, data, options)

Specifies a File Object target in which to put the resultant file.

Arguments

  • path { String } Path to access the FileProperty used to put the resultant file, for example, path/to/234523423423/file.

  • data { Object } Specifies the facets to put the file in, where key is the facet name and value is the output format type defined, for example, { facets: { content: 'my_pdf' } }.

  • options { Object } Defines options for the target.

    • compress: { Object } Defines the compression options for the target.

      • facet: { String } Name of the facet that will contain the compressed bundle.

      • outputs: { String[] } Defines the outputs to include in the bundle.

Returns

  • { renderer.Job } this.

addCallback(name, path, environment, credentials, options, [requestOptions={}])

Similar to addApiRequest but used when the process ends successfully or with error.

Returns

  • { renderer.Job } this.

start()

Initiates the rendering process.

Returns

  • { Object } A result object.

    • object { String } Type of result.

    • data { Object } Data result object.

      • jobId { String } Universally unique identifier (UUID) representing the current job.

      • status { String } Job status text.

{
    "object": "result",
    "data": {
        "jobId": "d8c1f89b-b0e2-4453-8235-dbf9a4dd889c",
        "status": "Process Initiated"
    }
}

If you do not define a target, the response will contain the output process in base64 encoding.

Important! If you do not define a target and the process takes too long, you might receive a timeout error.

{
    "object": "result",
    "data": {
        "my_output": "CiAgICAgICAgICAgIDxoMT5UYW5uZXIgSGVhdGhjb3RlPC9oMT4KICAgICAgICAgICAgPHNwYW4+PT09PT09PT09PT09PT09PT09PC9zcGFuPgogICAgICAgICAgICA8dWw+CiAgICAgICAgICAgICAgICA8bGk+RW1haWw6IE1hcmllLldpbGtpbnNvbkBnbWFpbC5jb208L2xpPgogICAgICAgICAgICAgICAgPGxpPlBob25lOiAxLTUzMS02NjctMTI4NTwvbGk+CiAgICAgICAgICAgICAgICA8bGk+Q29tcGFueTogUmV5bm9sZHMsIENoYW1wbGluIGFuZCBLZXJ0em1hbm48L2xpPgogICAgICAgICAgICA8L3VsPgogICAgICAgICAgICAKICAgICAgICAgICAgPGgxPkNvbGJ5IE8mI3gyNztDb25uZWxsPC9oMT4KICAgICAgICAgICAgPHNwYW4+PT09PT09PT09PT09PT09PT09PC9zcGFuPgogICAgICAgICAgICA8dWw+CiAgICAgICAgICAgICAgICA8bGk+RW1haWw6IFJheW11bmRvODlAZ21haWwuY29tPC9saT4KICAgICAgICAgICAgICAgIDxsaT5QaG9uZTogMS0wMTUtNzQyLTk5Nzk8L2xpPgogICAgICAgICAgICAgICAgPGxpPkNvbXBhbnk6IFpib25jYWssIFNtaXRoIGFuZCBXaXNva3k8L2xpPgogICAgICAgICAgICA8L3VsPgogICAgICAgICAgICAKICAgICAgICAgICAgPGgxPkphbnkgQm95bGUgRERTPC9oMT4KICAgICAgICAgICAgPHNwYW4+PT09PT09PT09PT09PT09PT09PC9zcGFuPgogICAgICAgICAgICA8dWw+CiAgICAgICAgICAgICAgICA8bGk+RW1haWw6IEthcmluYV9PQ29ubmVsbEBob3RtYWlsLmNvbTwvbGk+CiAgICAgICAgICAgICAgICA8bGk+UGhvbmU6ICg4MjIpIDc3My00NzUwIHg2NDY2OTwvbGk+CiAgICAgICAgICAgICAgICA8bGk+Q29tcGFueTogU2NodWxpc3QgLSBMdWVpbHdpdHo8L2xpPgogICAgICAgICAgICA8L3VsPgogICAgICAgICAgICAKICAgICAgICAgICAgPGgxPk1pc3MgRmVybmFuZG8gQ3VtbWVyYXRhPC9oMT4KICAgICAgICAgICAgPHNwYW4+PT09PT09PT09PT09PT09PT09PC9zcGFuPgogICAgICAgICAgICA8dWw+CiAgICAgICAgICAgICAgICA8bGk+RW1haWw6IEpvc3VlX1N3YW5pYXdza2lAeWFob28uY29tPC9saT4KICAgICAgICAgICAgICAgIDxsaT5QaG9uZTogKDM1NykgMjE1LTU3ODkgeDgzMzQwPC9saT4KICAgICAgICAgICAgICAgIDxsaT5Db21wYW55OiBLZW1tZXIgLSBXYXRlcnM8L2xpPgogICAgICAgICAgICA8L3VsPgogICAgICAgICAgICAKICAgICAgICAgICAgPGgxPklsYSBTY2hvZW48L2gxPgogICAgICAgICAgICA8c3Bhbj49PT09PT09PT09PT09PT09PT08L3NwYW4+CiAgICAgICAgICAgIDx1bD4KICAgICAgICAgICAgICAgIDxsaT5FbWFpbDogQmVsbDMwQGdtYWlsLmNvbTwvbGk+CiAgICAgICAgICAgICAgICA8bGk+UGhvbmU6ICgzOTUpIDA0OC0wNzk3PC9saT4KICAgICAgICAgICAgICAgIDxsaT5Db21wYW55OiBKYWNvYnMgSW5jPC9saT4KICAgICAgICAgICAgPC91bD4KICAgICAgICAgICAgCiAgICAgICAg"
    }
}

status(jobId)

Returns the status of an already initiated process.

Returns

  • { Object } A result object.

    • object { String } Type of result.

    • data { Object } Data result object.

      • [cluster_name].jobId { String } UUID representing the current job.

      • [cluster_name].status { String } Job status text.

{
    "object": "result",
    "data": {
        "cortex-renderer-management-service.default.svc.cluster.local": {
            "id": "d8c1f89b-b0e2-4453-8235-dbf9a4dd889c",
            "status": "Processing"
        }
    }
}

cancel(jobId)

Cancels an already initiated process.

Returns

  • { Object } A result object.

    • object { String } Type of result.

    • data { Object } Data result object.

      • [cluster_name].result { String } Text containing the UUID of the canceled job.

{
    "object": "result",
    "data": {
        "cortex-renderer-management-service.default.svc.cluster.local": {
            "result": "Job d8c1f89b-b0e2-4453-8235-dbf9a4dd889c cancelled",        
        }
    }
}

Examples

Example using an FTP target:

import { Job } from 'renderer'
const pdfJob = new Job('<apiKey>')

return pdfJob
    .addCursor('scripts', org.objects.myObject.find())
    .addTemplate('my_awesome_pdf_template') // this will look for that template into the already saved templates.
    .addOutput('my_pdf', 'pdf', ['my_awesome_pdf_template']) // only non partials templates can go here.
    .addFtpTarget({
        my_pdf: '/my_pdf.pdf' //the key is the output name, and the value is the remote filename location.
    }, {
        username: '<username>',
        password: '<password>',
        host: '<hostname>',
        port: '<port>',
        secureOptions: {
            rejectUnauthorized: false,
        },
    }).start();

Example using an FTP target with more secureOptions:

import { Job } from 'renderer'
const pdfJob = new Job('<apiKey>')

return pdfJob
    .addCursor('scripts', org.objects.scripts.find())
    .addTemplate('my_template', `
        <div class="scripts">
            {{#each (cursor scripts)}}
            <div>
                <h1>{{name}}</h1>
            </div>
            {{/each}}
        </div>`)
    .addOutput('my_pdf', 'pdf', ['my_template'])
    .addFtpTarget({
        my_pdf: '/scripts.pdf'
    }, {
        username: '<username>',
        password: '<password>',
        host: '<hostname>',
        port: '<port>',
        secureOptions: {
            rejectUnauthorized: true,
            ciphers: 'TLS_AES_256_GCM_SHA384',
            minVersion: 'TLSv1.3'
        }
    }).start()

Example using an SFTP target:

import { Job } from 'renderer'
const pdfJob = new Job('<apiKey>')

return pdfJob
    .addCursor('scripts', org.objects.myObject.find())
    .addTemplate('my_awesome_pdf_template') // this will look for that template into the already saved templates.
    .addOutput('my_pdf', 'pdf', ['my_awesome_pdf_template']) // only non partials templates can go here.
    .addSftpTarget({
        my_pdf: '/my_pdf.pdf' //the key is the output name, and the value is the remote filename location.
    }, {
        username: '<username>',
        password: '<password>',
        host: '<hostname>',
    }).start()

Example using a file target:

import { Job } from 'renderer'
const pdfJob = new Job('<apiKey>')

return pdfJob
    .addCursor('patients', org.objects.myObject.find())
    .addTemplate('my_awesome_pdf_template') // this will look for that template into the already saved templates.
    .addOutput('my_pdf', 'pdf', ['my_awesome_pdf_template'])  // only non partials templates can go here.
    .addFileTarget('/path/to/234523423423/file', {
        facets: {
            content: "my_pdf" //content is the name of the facet in where the output will be stored with the content-type defined on that facet.
        }
    }).start()

Example with multiple outputs:

import { Job } from 'renderer'
const pdfJob = new Job('<apiKey>')

return pdfJob
    .addCursor('patients', org.objects.myObject.find())
    .addTemplate('my_awesome_pdf_template') // this will look for that template into the already saved templates.
    .addOutput('my_pdf', 'pdf', ['my_awesome_pdf_template']) // only non partials templates can go here.
    .addOutput('my_html', 'html', ['my_awesome_pdf_template']) // only non partials templates can go here.
    .addFileTarget('/path/to/234523423423/file', {
        facets: {
            content: "my_pdf", //content is the name of the facet in where the output will be stored with the content-type defined on that facet.
            html: "my_html"
        }
    }).start()

Example with multiple templates in a single output:

import { Job } from 'renderer'
const pdfJob = new Job('<apiKey>')

return pdfJob
    .addCursor('patients', org.objects.myObject.find())
    .addTemplate('my_awesome_pdf_template') // this will look for that template into the already saved templates.
    .addTemplate('my_other_template', `
        <div class="my_patients">
            {{#each (cursor patients)}}
            <div>
                <h1>{{c_name}}</h1>
                <p>{{c_additional_information}}</p>
            </div>
            {{/each}}
        </div>`) // this will use the content of the template even if this exists
    .addOutput('my_pdf', 'pdf', ['my_awesome_pdf_template', 'my_other_template']) // this process will append second template at the end of first one
    .addFileTarget('/path/to/234523423423/file', {
        facets: {
            content: "my_pdf" //content is the name of the facet in where the output will be stored with the content-type defined on that facet.
        }
    }).start()

Example with multiple templates in multiple outputs or targets:

import { Job } from 'renderer'
const pdfJob = new Job('<apiKey>')

return pdfJob
    .addCursor('patients', org.objects.myObject.find())
    .addTemplate('my_awesome_pdf_template') // this will look for that template into the already saved templates.
    .addTemplate('my_other_template', `
        <div class="my_patients">
            {{#each (cursor patients)}}
            <div>
                <h1>{{c_name}}</h1>
                <p>{{c_additional_information}}</p>
            </div>
            {{/each}}
        </div>`) // this will use the content of the template even if this exists
    .addOutput('my_pdf', 'pdf', ['my_awesome_pdf_template'])
    .addOutput('my_html', 'html', ['my_other_template'])
    .addFileTarget('/path/to/234523423423/file', {
        facets: {
            content: "my_pdf" //content is the name of the facet in where the output will be stored with the content-type defined on that facet.
        }
    })
    .addSftpTarget({
        my_html: '/my_patients.html' // my_html is the name of the output, it should match the outputs added. 
    }, {
        username: '<username>',
        password: '<password>',
        host: '<hostname>',
    }).start()

Template helpers

Below is a list of helpers you can use in a template.

  • extend: Allows you to extend a partial template.

  • block: Defines a content block that you can use with append, replace, and prepend.

  • replace: Replaces the content of a block.

  • append: Appends content into a block.

  • prepend: Prepends content into a block.

  • each

  • if

  • with

  • unless

  • cursor: Resolve a stream, cursor, or request returned from the Cortex API.

  • log

  • lookup

Examples

A cursor helper can receive a CursorOperation, Array, or Stream to help you iterate the results of cursor data.

Tip: If you use a cursor inside another helper, you must call it using a parenthesis, for example,(cursor parameter) to resolve this first before you can iterate.

<div class="my_patients">
    {{#each (cursor patients)}}
    <div>
        <h1>{{c_name}}</h1>
        <p>{{c_additional_information}}</p>
    </div>
    {{/each}}
</div>

Example of a compiled template:

<div class="my_patients">
    <div>
        <h1>Patient 1</h1>
        <p>Age: 36, Height: 180</p>
    </div>
    <div>
        <h1>Patient 2</h1>
        <p>Age: 36, Height: 175</p>
    </div>
    <div>
        <h1>Patient 3</h1>
        <p>Age: 28, Height: 178</p>
    </div>
</div>

Example of defining a template as the master template (layout as name):

<div id="master">
    <div class="header>
        {{#block "header"}}
        <h1>This is the header</div>
        {{/block}}
    </div>
    <div class="content>
        {{#block "content"}}{{/block}}
    </div>
    <div class="footer>
        {{#block "footer"}}
            <p>This should be last</p>
        {{/block}}
    </div>
</div>

Example of a template that extends the master template:

{{#extend "layout"}}
    {{#append "header"}}
        <p>This content will be appended to the header</p>
    {{/append}}
    {{#replace "content"}} //All the conent in the block "content" will be replaced
        {{#each (cursor patients)}}
            <div>
                <h1>{{c_name}}</h1>
                <p>{{c_additional_information}}</p>
            </div>
        {{/each}}
    {{/replace}}
    {{#prepend "footer"}}
        <p>This line goes before the sentence</p>
    {{/prepend}}
{{/extend}}

Example of a compiled template:

<div id="master">
    <div class="header">
        <h1>This is the header</div>
        <p>This content will be appended to the header</p>
    </div>
    <div class="content">
        <div>
            <h1>James</h1>
            <p>Age: 36, Height: 180</p>
        </div>
        <div>
            <h1>Gaston</h1>
            <p>Age: 36, Height: 175</p>
        </div>
        <div>
            <h1>Joaquin</h1>
            <p>Age: 28, Height: 178</p>
        </div>
    </div>
    <div class="footer">
        <p>This line goes before the sentence</p>
        <p>This should be last</p>
    </div>
</div>

Last updated