Working with JSON
Depending on your use case, you can use JSON anywhere in Kdeps. There are primary resources where you can use JSON, including the API Response Resource (which requires the APIServerMode
to be enabled), the HTTP client resource, and the LLM resource.
Kdeps includes JSON helpers to parse and generate JSON documents that you can use in your resources.
API Server Response
When you create a route in the workflow, the resulting response is always a JSON document.
{
"success": true,
"response": {
"data": []
},
"errors": [{
"code": 0,
"message": ""
}]
}
Here, the most important part of this response is the data
array. In the API Server Response resource, the data { ... }
block is where you populate your JSON response. This block accepts all native PKL types.
Creating a JSON Response
There are various ways to create a JSON document for your response. Since the data
array can accept all types, using Mapping
is the most recommended way to create a JSON response. Below, we highlight other several options for creating a JSON document and response.
Using Mapping
or Dynamic
Types for JSON Responses
The native Mapping
type in PKL is the most recommended approach for creating JSON responses due to its simplicity and clarity. This method allows you to define key-value pairs and incorporate them directly into the data
array, making the process straightforward and efficient.
local JSONResponse = new Mapping {
["currentWeather"] = "@(llm.response("llmWeatherReport"))"
}
...
data {
JSONResponse
}
...
Key Considerations for Dynamic
and Nested Mappings
When working with Dynamic
types or nested (including deeply nested) mappings, it's important to understand the resulting structure. The output will be represented as an OPENAPI schema template, where:
- Dynamic types are treated as properties.
- Nested keys are translated into elements within the schema.
This distinction ensures compatibility with schema-driven systems while maintaining flexibility in how you define and structure your JSON responses.
Creating and Parsing JSON Documents
If you need to preprocess or consume a JSON document prior to a response, Kdeps offers several helper functions in order to create or parse JSON documents.
Using the JSONRenderDocument
Function
The document
function JSONRenderDocument
takes a native PKL object and converts it into JSON. You may want to use this if you have consumers of the JSON object in other resource, then send this back to the api response resource.
For example, if a local
variable is declared to contain the JSON structure and content in native PKL types, you can pass it into the JSONRenderDocument
function, and it will be converted into a JSON document as a String
.
local localWeather = new Mapping {
["currentWeather"] = "@(llm.response("llmWeatherReport"))"
}
local JSONResponse = """
@(document.JSONRenderDocument(localWeather))
"""
Directly Using a String
You can create a JSON document response directly from a string. However, unlike using JSONRenderDocument
, you are responsible for ensuring that the string is a valid JSON document.
Here’s an example of defining a JSON string:
local localWeather = """
{
"currentWeather": "@(llm.response("llmWeatherReport"))"
}
"""
This approach is particularly useful when working with static or semi-dynamic JSON strings. However, it requires careful validation to avoid issues with malformed JSON.
To further process the JSON response, you can:
- Use
JSONParserMapping
to convert it into aMapping
PKL object, which allows you to leverage theMapping
API for interacting with the JSON content. - Use
JSONParser
to convert the string into aDynamic
PKL object.
After parsing, you can pass the resulting object into JSONRenderDocument
to produce a valid JSON document as a String
.
Here’s an example of parsing and re-rendering the JSON:
local parsedJsonMapping = "@(document.JSONParserMapping(localWeather))"
local parsedJsonString = """
@(document.JSONRenderDocument(parsedJsonMapping))
"""
This method enables you to validate, manipulate, and reformat the JSON as needed while maintaining control over its structure and content.
Using a Resource Output file
Certain resources, such as the LLM Resource, can directly output JSON using the JSONResponseKeys
configuration. For other resources, you must ensure that their output is properly formatted as JSON.
To retrieve the execution results, you can use the file
function, which is available across all resource types. This function provides the path to the generated output file. The following file
functions are available for each resource type:
llm.file("id")
- Retrieves the file path for the LLM response output.python.file("id")
- Retrieves the file path for the Python stdout output.client.file("id")
- Retrieves the file path for the HTTP client response body.exec.file("id")
- Retrieves the file path for the Shell execution stdout output.
Once you have obtained the file path, you can use the read#text
function to read its content.
Here’s an example:
local llmOutputFilepath = "@(llm.file("llmWeatherReport"))"
local llmOutputJson = """
@(read("\(llmOutputFilepath)")?.text)
"""
In this example:
- The
llm.file
function retrieves the file path of the generated output from the LLM resource. - The
read#text
function reads the content of the file, making it available for further processing.
LLM Structured Output
When JSONResponse
is enabled, the LLM can produce a structured output in JSON format. To define the keys for the structured JSON response, list them in the JSONResponseKeys
configuration.
You can specify the expected data type for each key by including a type hint in the key name. Examples include:
first_name_string
for a string value.famous_quotes_array
for an array.age_integer
for an integer value.
To ensure the output remains valid JSON, consider the following:
Minimize Formatting Issues: LLM output may occasionally include newlines or special characters that disrupt the JSON structure. Tailor your prompt to encourage clean and consistent formatting.
Optimize for Structured Output: Add a hint to your prompt such as, "Use plain text with no line breaks." to improve the quality and reliability of the structured JSON response.
By combining type hints and prompt optimization, you can ensure the LLM produces well-structured and valid JSON outputs.
Parsing JSON Strings
To parse a JSON string, use the JSONParser
function. This converts the string into a Dynamic
PKL object. Alternatively, you can use JSONParserMapping
to output a Mapping
PKL object.
Here’s an example:
local localWeatherJson = """
{
"currentWeather": "@(llm.response("llmWeatherReport"))"
}
"""
local localWeather = "@(JSONParser(localWeatherJson))"
local currentWeather = "@(localWeather?.currentWeather)"
In this example:
JSONParser
processes thelocalWeatherJson
string and converts it into aDynamic
PKL object.- The
currentWeather
value is then extracted from the parsed object usinglocalWeather?.currentWeather
.
Similarly, if you use JSONParserMapping
, the JSON string is converted into a Mapping
PKL object, allowing you to leverage the Mapping
API for more structured and type-safe access to the data.
Here’s an example:
local localWeatherJson = """
{
"currentWeather": "@(llm.response("llmWeatherReport"))"
}
"""
local localWeather = "@(JSONParserMapping(localWeatherJson))"
local currentWeather = "@(localWeather.getOrNull("currentWeather"))"
In this example:
JSONParserMapping
transforms thelocalWeatherJson
string into aMapping
PKL object.- The
Mapping
API'sgetOrNull
method is used to access thecurrentWeather
value.