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
JSONParserMappingto convert it into aMappingPKL object, which allows you to leverage theMappingAPI for interacting with the JSON content. - Use
JSONParserto convert the string into aDynamicPKL 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.filefunction retrieves the file path of the generated output from the LLM resource. - The
read#textfunction 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_stringfor a string value.famous_quotes_arrayfor an array.age_integerfor 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:
JSONParserprocesses thelocalWeatherJsonstring and converts it into aDynamicPKL object.- The
currentWeathervalue 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:
JSONParserMappingtransforms thelocalWeatherJsonstring into aMappingPKL object.- The
MappingAPI'sgetOrNullmethod is used to access thecurrentWeathervalue.