Yaak Logo
Yaak
Feedback/Json response filtering using `jq`

Json response filtering using `jq`

Sahand Johansen·a month ago
Needs TriageFeature RequestImprovement

Hello. I’m wondering if it’s possible to implement response-filtering using jq. I’ve tried to develop the plugin myself, but it looks like the rust-backend is hardcoded to filter all json-data using the jsonpath plugin (in yaak/crates/yaak-plugins/src/manager.rs)

Here is the plugin source I tried to build, maybe this could be the starting point for a potential jq-filtering.

import type { PluginDefinition } from "@yaakapp/api";
import { jq } from "node-jq"


export const plugin: PluginDefinition = {
  filter: {
    name: "jq",
    description: "Filter jq",
    onFilter(_ctx, args) {
      try {
        const filtered = jq.run(args.filter, args.payload, {input: 'string'});
        return { content: JSON.stringify(filtered, null, 2) };
      } catch (err) {
        return {
          content: "",
          error: `Invalid filter: ${err instanceof Error ? err.message : String(err)}`,
        };
      }
    },
  },
};
macOS2026.4.0

Comments (1)

Sign in to leave a comment.

Sahand JohansenOP

I would be happy to update the Rust code by adding something like this:

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum FilterLang {
    #[serde(rename = "jq")]
    Jq,
    #[serde(rename = "jsonpath")]
    JsonPath,
    #[serde(rename = "xpath")]
    XPath,
}

impl FilterLang {
    fn plugin_name(self) -> &'static str {
        match self {
            FilterLang::Jq => "@yaak/filter-jq", // <- whatever YOUR plugin is installed as
            FilterLang::JsonPath => "@yaak/filter-jsonpath",
            FilterLang::XPath => "@yaak/filter-xpath",
        }
    }

    fn from_content_type(content_type: &str) -> Self {
        let ct = content_type.to_lowercase();
        if ct.contains("xml") || ct.contains("html") {
            FilterLang::XPath
        } else {
            FilterLang::JsonPath
        }
    }
}

And updating the filter_data function to:

pub async fn filter_data(
    &self,
    plugin_context: &PluginContext,
    filter: &str,
    content: &str,
    content_type: &str,
    lang: Option<FilterLang>,
) -> Result<FilterResponse> {
    let plugin_name = lang
        .unwrap_or_else(|| FilterLang::from_content_type(content_type))
        .plugin_name();

    let plugin = self
        .get_plugin_by_name(plugin_name)
        .await
        .ok_or(PluginNotFoundErr(plugin_name.to_string()))?;

    // ...
}```

Further, `cmd_http_response_body`:

```rust
#[tauri::command]
async fn cmd_http_response_body<R: Runtime>(
    window: WebviewWindow<R>,
    plugin_manager: State<'_, PluginManager>,
    response: HttpResponse,
    filter: Option<&str>,
    filter_lang: Option<FilterLang>,  // <<<----- Adding this option
) -> YaakResult<FilterResponse> {
    // ... 
    match filter {
        Some(filter) if !filter.is_empty() => Ok(plugin_manager
            .filter_data(&window.plugin_context(), filter, &body, content_type, filter_lang)
            .await?),
        _ => Ok(FilterResponse { content: body, error: None }),
    }
}

And lastly getResponseBodyText:

export async function getResponseBodyText({
  response,
  filter,
  filterLang,
}: {
  response: HttpResponse;
  filter: string | null;
  filterLang?: "jq" | "jsonpath" | "xpath" | null;
}): Promise<string | null> {
  const result = await invokeCmd<FilterResponse>("cmd_http_response_body", {
    response,
    filter,
    filterLang,
  });
  if (result.error) throw new Error(result.error);
  return result.content;
}

If I forgot something please do let me know.

Type to search feedback...