--- layout: default title: Bindings ---

# Bindings

If you don't want to invoke the `jsonnet` commandline utility to evaluate Jsonnet, there are also official libraries for Python, Go, and C. The C library wraps the C++ implementation, hiding all the C++ to make it easy to use Jsonnet from C. In turn, there is a C++ wrapper around the C library to make it easy to use from client C++ code (surprisingly enough, this actually makes sense)! There are also various unofficial bindings built on the C API.

## A Warning On Server-Side Evaluation

### Data exfiltration risk

The normal behaviour of the `import`, `importstr`, and `importbin` keywords is to import files from the filesystem. These accesses are unrestricted; any file accessible to the Jsonnet process can be read this way, including potentially sensitive files such as `/etc/passwd`, `/proc/self/environ`, etc. If you evaluate untrusted Jsonnet code and expose the output of that in any way (for example by reporting error messages back to the user), then you may be exposed to this data exfiltration risk.

Mitigation: Using Jsonnet as a library allows you to replace the import lookup logic entirely, in which case you can restrict imports to files (or other data sources) to mitigate data exfiltration risk. As a broader mitigation, executing Jsonnet inside a strong sandbox (for example, gvisor container, firecracker VM, etc) can limit access to sensitive data as long as the sandbox is properly configured.

### Denial of Service risk

If you are creating an API server that will evaluate untrusted Jsonnet code in the same process that handles other requests, be aware of your exposure to denial of service attacks. Since Jsonnet allows expressing programs that take unreasonable amounts of CPU time and RAM, it is possible for a malicious request to cause its host API server to exceed its OS resources and crash. Such a crash would affect concurrently running handlers for other users, and decrease your capacity until the server is restarted. A simple remedy for this situation is to `exec` the Jsonnet commandline binary in a `ulimit` child process where the CPU and RAM can be tightly bounded for the specific request. Communication to and from the commandline binary could be via temporary files or pipes. Thus, only the malicious request fails.

Linking Jsonnet as a library is more appropriate for client-side applications or situations where the input configuration can be trusted.

## C API

The C API simply wraps the C++ implementation to hide C++ language features like templates, classes, overloading, etc. This makes it easier to bind to other languages, as C is typically the lowest common denominator across all systems.

The API is documented in libjsonnet.h. It is built with 'make libjsonnet.so'. It is used by the python bindings, the Jsonnet commandline tool, as well as a couple of simpler tests. Search for #include "libjsonnet.h".

To use the API, create a JsonnetVM object, set various options, then tell it to evaluate a filename or snippet. To avoid leaking memory, the result of execution (JSON or error message) and the JsonnetVM object itself must be cleaned up using the provided `jsonnet_realloc` and the `jsonnet_destroy` functions, respectively.

## Python API

The Python API wraps the C API in a straightforward way. It can be installed with `pip install jsonnet` or built directly with `setup.py`. It supports Python 2.7 and Python 3.

The Python module provides two functions, `evaluate_file(filename)` and `evaluate_snippet(filename, expr)`. In the latter case, the parameter `filename` is used in stack traces, because all errors are given with the "filename" containing the code.

Keyword arguments to these functions are used to control the virtual machine. They are:

- `jpathdir` (string or list of strings)
- `max_stack` (number)
- `gc_min_objects` (number)
- `gc_growth_trigger` (number)
- `ext_vars` (dict: string to string)
- `ext_codes` (dict string to string)
- `tla_vars` (dict string to string)
- `tla_codes` (dict string to string)
- `max_trace` (number)
- `import_callback` (see example in python/)
- `native_callbacks` (see example in python/)

The argument `import_callback` can be used to pass a callable, to trap the Jsonnet `import`, `importstr`, and `importbin` constructs. This allows, e.g., reading files out of archives or implementing library search paths. The argument `native_callback` is used to allow execution of arbitrary Python code via `std.native(...)`. This is useful so Jsonnet code can access pure functions in the Python ecosystem, such as compression, encryption, encoding, etc.

If an error is raised during the evaluation of the Jsonnet code, it is formed into a stack trace and thrown as a python RuntimeError. Otherwise, the JSON string is returned. To convert this into objects for easy interpretation in Python, use the json module. An example:

    import json
    import _jsonnet

    jsonnet_str = '''
    {
      person1: {
        name: "Alice",
        welcome: "Hello " + self.name + "!",
      },
      person2: self.person1 {
        name: std.extVar("OTHER_NAME"),
      },
    }
    '''

    json_str = _jsonnet.evaluate_snippet(
        "snippet", jsonnet_str,
        ext_vars={'OTHER_NAME': 'Bob'})

    json_obj = json.loads(json_str)
    for person_id, person in json_obj.items():
      print('%s is %s, greeted by "%s"' % (
          person_id,
          person['name'],
          person['welcome']))

## Unofficial Third Party APIs

There are unofficial bindings available for other languages. These are not supported by Google and may be some versions behind the latest release.

- Go but please first consider the native port
- LuaJIT (FFI)
- Node.js node-jsonnet: C++ version compiled to JS code
- Node.js tplfa-jsonnet: Golang version compiled to WASM code
- PHP
- Ruby
- Rust but please first consider one of the native ports (jrsonnet or rsjsonnet)
- Haskell native port