mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-23 09:18:30 +02:00
Apply Request path parameters during render (#120)
This commit is contained in:
96
plugin-runtime-types/src/bindings/events.ts
Normal file
96
plugin-runtime-types/src/bindings/events.ts
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
import type { Environment } from "./models";
|
||||||
|
import type { Folder } from "./models";
|
||||||
|
import type { GrpcRequest } from "./models";
|
||||||
|
import type { HttpRequest } from "./models";
|
||||||
|
import type { HttpResponse } from "./models";
|
||||||
|
import type { JsonValue } from "./serde_json/JsonValue";
|
||||||
|
import type { Workspace } from "./models";
|
||||||
|
|
||||||
|
export type BootRequest = { dir: string, watch: boolean, };
|
||||||
|
|
||||||
|
export type BootResponse = { name: string, version: string, capabilities: Array<string>, };
|
||||||
|
|
||||||
|
export type CallHttpRequestActionArgs = { httpRequest: HttpRequest, };
|
||||||
|
|
||||||
|
export type CallHttpRequestActionRequest = { key: string, pluginRefId: string, args: CallHttpRequestActionArgs, };
|
||||||
|
|
||||||
|
export type CallTemplateFunctionArgs = { purpose: RenderPurpose, values: { [key in string]?: string }, };
|
||||||
|
|
||||||
|
export type CallTemplateFunctionRequest = { name: string, args: CallTemplateFunctionArgs, };
|
||||||
|
|
||||||
|
export type CallTemplateFunctionResponse = { value: string | null, };
|
||||||
|
|
||||||
|
export type Color = "custom" | "default" | "primary" | "secondary" | "info" | "success" | "notice" | "warning" | "danger";
|
||||||
|
|
||||||
|
export type CopyTextRequest = { text: string, };
|
||||||
|
|
||||||
|
export type ExportHttpRequestRequest = { httpRequest: HttpRequest, };
|
||||||
|
|
||||||
|
export type ExportHttpRequestResponse = { content: string, };
|
||||||
|
|
||||||
|
export type FilterRequest = { content: string, filter: string, };
|
||||||
|
|
||||||
|
export type FilterResponse = { content: string, };
|
||||||
|
|
||||||
|
export type FindHttpResponsesRequest = { requestId: string, limit: number | null, };
|
||||||
|
|
||||||
|
export type FindHttpResponsesResponse = { httpResponses: Array<HttpResponse>, };
|
||||||
|
|
||||||
|
export type GetHttpRequestActionsRequest = Record<string, never>;
|
||||||
|
|
||||||
|
export type GetHttpRequestActionsResponse = { actions: Array<HttpRequestAction>, pluginRefId: string, };
|
||||||
|
|
||||||
|
export type GetHttpRequestByIdRequest = { id: string, };
|
||||||
|
|
||||||
|
export type GetHttpRequestByIdResponse = { httpRequest: HttpRequest | null, };
|
||||||
|
|
||||||
|
export type GetTemplateFunctionsResponse = { functions: Array<TemplateFunction>, pluginRefId: string, };
|
||||||
|
|
||||||
|
export type HttpRequestAction = { key: string, label: string, icon: string | null, };
|
||||||
|
|
||||||
|
export type Icon = "copy" | "info" | "check_circle" | "alert_triangle";
|
||||||
|
|
||||||
|
export type ImportRequest = { content: string, };
|
||||||
|
|
||||||
|
export type ImportResources = { workspaces: Array<Workspace>, environments: Array<Environment>, folders: Array<Folder>, httpRequests: Array<HttpRequest>, grpcRequests: Array<GrpcRequest>, };
|
||||||
|
|
||||||
|
export type ImportResponse = { resources: ImportResources, };
|
||||||
|
|
||||||
|
export type InternalEvent = { id: string, pluginRefId: string, replyId: string | null, payload: InternalEventPayload, windowContext: WindowContext, };
|
||||||
|
|
||||||
|
export type InternalEventPayload = { "type": "boot_request" } & BootRequest | { "type": "boot_response" } & BootResponse | { "type": "reload_request" } | { "type": "reload_response" } | { "type": "terminate_request" } | { "type": "terminate_response" } | { "type": "import_request" } & ImportRequest | { "type": "import_response" } & ImportResponse | { "type": "filter_request" } & FilterRequest | { "type": "filter_response" } & FilterResponse | { "type": "export_http_request_request" } & ExportHttpRequestRequest | { "type": "export_http_request_response" } & ExportHttpRequestResponse | { "type": "send_http_request_request" } & SendHttpRequestRequest | { "type": "send_http_request_response" } & SendHttpRequestResponse | { "type": "get_http_request_actions_request" } & GetHttpRequestActionsRequest | { "type": "get_http_request_actions_response" } & GetHttpRequestActionsResponse | { "type": "call_http_request_action_request" } & CallHttpRequestActionRequest | { "type": "get_template_functions_request" } | { "type": "get_template_functions_response" } & GetTemplateFunctionsResponse | { "type": "call_template_function_request" } & CallTemplateFunctionRequest | { "type": "call_template_function_response" } & CallTemplateFunctionResponse | { "type": "copy_text_request" } & CopyTextRequest | { "type": "render_http_request_request" } & RenderHttpRequestRequest | { "type": "render_http_request_response" } & RenderHttpRequestResponse | { "type": "template_render_request" } & TemplateRenderRequest | { "type": "template_render_response" } & TemplateRenderResponse | { "type": "show_toast_request" } & ShowToastRequest | { "type": "get_http_request_by_id_request" } & GetHttpRequestByIdRequest | { "type": "get_http_request_by_id_response" } & GetHttpRequestByIdResponse | { "type": "find_http_responses_request" } & FindHttpResponsesRequest | { "type": "find_http_responses_response" } & FindHttpResponsesResponse | { "type": "empty_response" };
|
||||||
|
|
||||||
|
export type RenderHttpRequestRequest = { httpRequest: HttpRequest, purpose: RenderPurpose, };
|
||||||
|
|
||||||
|
export type RenderHttpRequestResponse = { httpRequest: HttpRequest, };
|
||||||
|
|
||||||
|
export type RenderPurpose = "send" | "preview";
|
||||||
|
|
||||||
|
export type SendHttpRequestRequest = { httpRequest: HttpRequest, };
|
||||||
|
|
||||||
|
export type SendHttpRequestResponse = { httpResponse: HttpResponse, };
|
||||||
|
|
||||||
|
export type ShowToastRequest = { message: string, color?: Color | null, icon?: Icon | null, };
|
||||||
|
|
||||||
|
export type TemplateFunction = { name: string, aliases: Array<string>, args: Array<TemplateFunctionArg>, };
|
||||||
|
|
||||||
|
export type TemplateFunctionArg = { "type": "text" } & TemplateFunctionTextArg | { "type": "select" } & TemplateFunctionSelectArg | { "type": "checkbox" } & TemplateFunctionCheckboxArg | { "type": "http_request" } & TemplateFunctionHttpRequestArg;
|
||||||
|
|
||||||
|
export type TemplateFunctionBaseArg = { name: string, optional?: boolean | null, label?: string | null, defaultValue?: string | null, };
|
||||||
|
|
||||||
|
export type TemplateFunctionCheckboxArg = { name: string, optional?: boolean | null, label?: string | null, defaultValue?: string | null, };
|
||||||
|
|
||||||
|
export type TemplateFunctionHttpRequestArg = { name: string, optional?: boolean | null, label?: string | null, defaultValue?: string | null, };
|
||||||
|
|
||||||
|
export type TemplateFunctionSelectArg = { options: Array<TemplateFunctionSelectOption>, name: string, optional?: boolean | null, label?: string | null, defaultValue?: string | null, };
|
||||||
|
|
||||||
|
export type TemplateFunctionSelectOption = { name: string, value: string, };
|
||||||
|
|
||||||
|
export type TemplateFunctionTextArg = { placeholder?: string | null, name: string, optional?: boolean | null, label?: string | null, defaultValue?: string | null, };
|
||||||
|
|
||||||
|
export type TemplateRenderRequest = { data: JsonValue, purpose: RenderPurpose, };
|
||||||
|
|
||||||
|
export type TemplateRenderResponse = { data: JsonValue, };
|
||||||
|
|
||||||
|
export type WindowContext = { "type": "none" } | { "type": "label", label: string, };
|
||||||
23
plugin-runtime-types/src/bindings/models.ts
Normal file
23
plugin-runtime-types/src/bindings/models.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
export type Environment = { model: "environment", id: string, workspaceId: string, createdAt: string, updatedAt: string, name: string, variables: Array<EnvironmentVariable>, };
|
||||||
|
|
||||||
|
export type EnvironmentVariable = { enabled?: boolean, name: string, value: string, };
|
||||||
|
|
||||||
|
export type Folder = { model: "folder", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, name: string, sortPriority: number, };
|
||||||
|
|
||||||
|
export type GrpcMetadataEntry = { enabled?: boolean, name: string, value: string, };
|
||||||
|
|
||||||
|
export type GrpcRequest = { model: "grpc_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authenticationType: string | null, authentication: Record<string, any>, message: string, metadata: Array<GrpcMetadataEntry>, method: string | null, name: string, service: string | null, sortPriority: number, url: string, };
|
||||||
|
|
||||||
|
export type HttpRequest = { model: "http_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authentication: Record<string, any>, authenticationType: string | null, body: Record<string, any>, bodyType: string | null, headers: Array<HttpRequestHeader>, method: string, name: string, sortPriority: number, url: string, urlParameters: Array<HttpUrlParameter>, };
|
||||||
|
|
||||||
|
export type HttpRequestHeader = { enabled?: boolean, name: string, value: string, };
|
||||||
|
|
||||||
|
export type HttpResponse = { model: "http_response", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, bodyPath: string | null, contentLength: number | null, elapsed: number, elapsedHeaders: number, error: string | null, headers: Array<HttpResponseHeader>, remoteAddr: string | null, status: number, statusReason: string | null, url: string, version: string | null, };
|
||||||
|
|
||||||
|
export type HttpResponseHeader = { name: string, value: string, };
|
||||||
|
|
||||||
|
export type HttpUrlParameter = { enabled?: boolean, name: string, value: string, };
|
||||||
|
|
||||||
|
export type Workspace = { model: "workspace", id: string, createdAt: string, updatedAt: string, name: string, description: string, variables: Array<EnvironmentVariable>, settingValidateCertificates: boolean, settingFollowRedirects: boolean, settingRequestTimeout: number, };
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
export type JsonValue = number | string | Array<JsonValue> | { [key in string]?: JsonValue };
|
||||||
3187
plugin-runtime/package-lock.json
generated
3187
plugin-runtime/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,13 @@
|
|||||||
import { TemplateRenderResponse, WindowContext } from '@yaakapp-internal/plugin';
|
import {
|
||||||
|
RenderHttpRequestResponse,
|
||||||
|
TemplateRenderResponse,
|
||||||
|
WindowContext,
|
||||||
|
} from '@yaakapp-internal/plugin';
|
||||||
import {
|
import {
|
||||||
BootRequest,
|
BootRequest,
|
||||||
Context,
|
Context,
|
||||||
FindHttpResponsesResponse,
|
FindHttpResponsesResponse,
|
||||||
GetHttpRequestByIdResponse,
|
GetHttpRequestByIdResponse,
|
||||||
HttpRequest,
|
|
||||||
HttpRequestAction,
|
HttpRequestAction,
|
||||||
ImportResponse,
|
ImportResponse,
|
||||||
InternalEvent,
|
InternalEvent,
|
||||||
@@ -162,18 +165,13 @@ async function initialize() {
|
|||||||
);
|
);
|
||||||
return httpResponse;
|
return httpResponse;
|
||||||
},
|
},
|
||||||
/** @deprecated: please use ctx.templates.render */
|
|
||||||
async render(args) {
|
async render(args) {
|
||||||
const payload: InternalEventPayload = {
|
const payload = { type: 'render_http_request_request', ...args } as const;
|
||||||
type: 'template_render_request',
|
const { httpRequest } = await sendAndWaitForReply<RenderHttpRequestResponse>(
|
||||||
data: args.httpRequest as any,
|
|
||||||
purpose: args.purpose,
|
|
||||||
};
|
|
||||||
const result = await sendAndWaitForReply<TemplateRenderResponse>(
|
|
||||||
event.windowContext,
|
event.windowContext,
|
||||||
payload,
|
payload,
|
||||||
);
|
);
|
||||||
return result.data as unknown as HttpRequest;
|
return httpRequest;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
templates: {
|
templates: {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ use tauri::{Manager, Runtime, WebviewWindow};
|
|||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
use tokio::sync::watch::Receiver;
|
use tokio::sync::watch::Receiver;
|
||||||
use yaak_models::models::{
|
use yaak_models::models::{
|
||||||
Cookie, CookieJar, Environment, HttpRequest, HttpResponse, HttpResponseHeader, HttpUrlParameter,
|
Cookie, CookieJar, Environment, HttpRequest, HttpResponse, HttpResponseHeader,
|
||||||
};
|
};
|
||||||
use yaak_models::queries::{get_workspace, update_response_if_id, upsert_cookie_jar};
|
use yaak_models::queries::{get_workspace, update_response_if_id, upsert_cookie_jar};
|
||||||
use yaak_plugin_runtime::events::{RenderPurpose, WindowContext};
|
use yaak_plugin_runtime::events::{RenderPurpose, WindowContext};
|
||||||
@@ -107,15 +107,7 @@ pub async fn send_http_request<R: Runtime>(
|
|||||||
if !p.enabled || p.name.is_empty() {
|
if !p.enabled || p.name.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
query_params.push((p.name, p.value));
|
||||||
// Replace path parameters with values from URL parameters
|
|
||||||
let old_url_string = url_string.clone();
|
|
||||||
url_string = replace_path_placeholder(&p, url_string.as_str());
|
|
||||||
|
|
||||||
// Treat as regular param if wasn't used as path param
|
|
||||||
if old_url_string == url_string {
|
|
||||||
query_params.push((p.name, p.value));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let uri = match http::Uri::from_str(url_string.as_str()) {
|
let uri = match http::Uri::from_str(url_string.as_str()) {
|
||||||
@@ -512,123 +504,3 @@ fn get_str_h<'a>(v: &'a BTreeMap<String, Value>, key: &str) -> &'a str {
|
|||||||
Some(v) => v.as_str().unwrap_or_default(),
|
Some(v) => v.as_str().unwrap_or_default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_path_placeholder(p: &HttpUrlParameter, url: &str) -> String {
|
|
||||||
if !p.enabled {
|
|
||||||
return url.to_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
if !p.name.starts_with(":") {
|
|
||||||
return url.to_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
let re = regex::Regex::new(format!("(/){}([/?#]|$)", p.name).as_str()).unwrap();
|
|
||||||
let result = re
|
|
||||||
.replace_all(url, |cap: ®ex::Captures| {
|
|
||||||
format!(
|
|
||||||
"{}{}{}",
|
|
||||||
cap[1].to_string(),
|
|
||||||
urlencoding::encode(p.value.as_str()),
|
|
||||||
cap[2].to_string()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.into_owned();
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::http_request::replace_path_placeholder;
|
|
||||||
use yaak_models::models::HttpUrlParameter;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn placeholder_middle() {
|
|
||||||
let p = HttpUrlParameter {
|
|
||||||
name: ":foo".into(),
|
|
||||||
value: "xxx".into(),
|
|
||||||
enabled: true,
|
|
||||||
};
|
|
||||||
assert_eq!(
|
|
||||||
replace_path_placeholder(&p, "https://example.com/:foo/bar"),
|
|
||||||
"https://example.com/xxx/bar",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn placeholder_end() {
|
|
||||||
let p = HttpUrlParameter {
|
|
||||||
name: ":foo".into(),
|
|
||||||
value: "xxx".into(),
|
|
||||||
enabled: true,
|
|
||||||
};
|
|
||||||
assert_eq!(
|
|
||||||
replace_path_placeholder(&p, "https://example.com/:foo"),
|
|
||||||
"https://example.com/xxx",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn placeholder_query() {
|
|
||||||
let p = HttpUrlParameter {
|
|
||||||
name: ":foo".into(),
|
|
||||||
value: "xxx".into(),
|
|
||||||
enabled: true,
|
|
||||||
};
|
|
||||||
assert_eq!(
|
|
||||||
replace_path_placeholder(&p, "https://example.com/:foo?:foo"),
|
|
||||||
"https://example.com/xxx?:foo",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn placeholder_missing() {
|
|
||||||
let p = HttpUrlParameter {
|
|
||||||
enabled: true,
|
|
||||||
name: "".to_string(),
|
|
||||||
value: "".to_string(),
|
|
||||||
};
|
|
||||||
assert_eq!(
|
|
||||||
replace_path_placeholder(&p, "https://example.com/:missing"),
|
|
||||||
"https://example.com/:missing",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn placeholder_disabled() {
|
|
||||||
let p = HttpUrlParameter {
|
|
||||||
enabled: false,
|
|
||||||
name: ":foo".to_string(),
|
|
||||||
value: "xxx".to_string(),
|
|
||||||
};
|
|
||||||
assert_eq!(
|
|
||||||
replace_path_placeholder(&p, "https://example.com/:foo"),
|
|
||||||
"https://example.com/:foo",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn placeholder_prefix() {
|
|
||||||
let p = HttpUrlParameter {
|
|
||||||
name: ":foo".into(),
|
|
||||||
value: "xxx".into(),
|
|
||||||
enabled: true,
|
|
||||||
};
|
|
||||||
assert_eq!(
|
|
||||||
replace_path_placeholder(&p, "https://example.com/:foooo"),
|
|
||||||
"https://example.com/:foooo",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn placeholder_encode() {
|
|
||||||
let p = HttpUrlParameter {
|
|
||||||
name: ":foo".into(),
|
|
||||||
value: "Hello World".into(),
|
|
||||||
enabled: true,
|
|
||||||
};
|
|
||||||
assert_eq!(
|
|
||||||
replace_path_placeholder(&p, "https://example.com/:foo"),
|
|
||||||
"https://example.com/Hello%20World",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ use crate::export_resources::{get_workspace_export_resources, WorkspaceExportRes
|
|||||||
use crate::grpc::metadata_to_map;
|
use crate::grpc::metadata_to_map;
|
||||||
use crate::http_request::send_http_request;
|
use crate::http_request::send_http_request;
|
||||||
use crate::notifications::YaakNotifier;
|
use crate::notifications::YaakNotifier;
|
||||||
use crate::render::{render_grpc_request, render_json_value, render_template};
|
use crate::render::{render_grpc_request, render_http_request, render_json_value, render_template};
|
||||||
use crate::template_callback::PluginTemplateCallback;
|
use crate::template_callback::PluginTemplateCallback;
|
||||||
use crate::updates::{UpdateMode, YaakUpdater};
|
use crate::updates::{UpdateMode, YaakUpdater};
|
||||||
use crate::window_menu::app_menu;
|
use crate::window_menu::app_menu;
|
||||||
@@ -61,8 +61,8 @@ use yaak_models::queries::{
|
|||||||
use yaak_plugin_runtime::events::{
|
use yaak_plugin_runtime::events::{
|
||||||
BootResponse, CallHttpRequestActionRequest, FilterResponse, FindHttpResponsesResponse,
|
BootResponse, CallHttpRequestActionRequest, FilterResponse, FindHttpResponsesResponse,
|
||||||
GetHttpRequestActionsResponse, GetHttpRequestByIdResponse, GetTemplateFunctionsResponse, Icon,
|
GetHttpRequestActionsResponse, GetHttpRequestByIdResponse, GetTemplateFunctionsResponse, Icon,
|
||||||
InternalEvent, InternalEventPayload, RenderPurpose, SendHttpRequestResponse, ShowToastRequest,
|
InternalEvent, InternalEventPayload, RenderHttpRequestResponse, RenderPurpose,
|
||||||
TemplateRenderResponse, WindowContext,
|
SendHttpRequestResponse, ShowToastRequest, TemplateRenderResponse, WindowContext,
|
||||||
};
|
};
|
||||||
use yaak_plugin_runtime::plugin_handle::PluginHandle;
|
use yaak_plugin_runtime::plugin_handle::PluginHandle;
|
||||||
use yaak_templates::{Parser, Tokens};
|
use yaak_templates::{Parser, Tokens};
|
||||||
@@ -2202,6 +2202,21 @@ async fn handle_plugin_event<R: Runtime>(
|
|||||||
GetHttpRequestByIdResponse { http_request },
|
GetHttpRequestByIdResponse { http_request },
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
InternalEventPayload::RenderHttpRequestRequest(req) => {
|
||||||
|
let window = get_window_from_window_context(app_handle, &window_context)
|
||||||
|
.expect("Failed to find window for render http request");
|
||||||
|
|
||||||
|
let workspace = workspace_from_window(&window)
|
||||||
|
.await
|
||||||
|
.expect("Failed to get workspace_id from window URL");
|
||||||
|
let environment = environment_from_window(&window).await;
|
||||||
|
let cb = PluginTemplateCallback::new(app_handle, &window_context, req.purpose);
|
||||||
|
let http_request =
|
||||||
|
render_http_request(&req.http_request, &workspace, environment.as_ref(), &cb).await;
|
||||||
|
Some(InternalEventPayload::RenderHttpRequestResponse(
|
||||||
|
RenderHttpRequestResponse { http_request },
|
||||||
|
))
|
||||||
|
}
|
||||||
InternalEventPayload::TemplateRenderRequest(req) => {
|
InternalEventPayload::TemplateRenderRequest(req) => {
|
||||||
let window = get_window_from_window_context(app_handle, &window_context)
|
let window = get_window_from_window_context(app_handle, &window_context)
|
||||||
.expect("Failed to find window for render");
|
.expect("Failed to find window for render");
|
||||||
|
|||||||
@@ -96,14 +96,17 @@ pub async fn render_http_request(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let url = render(r.url.clone().as_str(), vars, cb).await;
|
let url = render(r.url.clone().as_str(), vars, cb).await;
|
||||||
HttpRequest {
|
let req = HttpRequest {
|
||||||
url,
|
url,
|
||||||
url_parameters,
|
url_parameters,
|
||||||
headers,
|
headers,
|
||||||
body,
|
body,
|
||||||
authentication,
|
authentication,
|
||||||
..r.to_owned()
|
..r.to_owned()
|
||||||
}
|
};
|
||||||
|
|
||||||
|
// This doesn't fit perfectly with the concept of "rendering" but it kind of does
|
||||||
|
apply_path_placeholders(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_vars_hashmap(
|
pub fn make_vars_hashmap(
|
||||||
@@ -173,7 +176,7 @@ async fn render_json_value_raw<T: TemplateCallback>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod render_tests {
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use yaak_templates::TemplateCallback;
|
use yaak_templates::TemplateCallback;
|
||||||
@@ -247,3 +250,173 @@ mod tests {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn replace_path_placeholder(p: &HttpUrlParameter, url: &str) -> String {
|
||||||
|
if !p.enabled {
|
||||||
|
return url.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
if !p.name.starts_with(":") {
|
||||||
|
return url.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
let re = regex::Regex::new(format!("(/){}([/?#]|$)", p.name).as_str()).unwrap();
|
||||||
|
let result = re
|
||||||
|
.replace_all(url, |cap: ®ex::Captures| {
|
||||||
|
format!(
|
||||||
|
"{}{}{}",
|
||||||
|
cap[1].to_string(),
|
||||||
|
urlencoding::encode(p.value.as_str()),
|
||||||
|
cap[2].to_string()
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.into_owned();
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_path_placeholders(rendered_request: HttpRequest) -> HttpRequest {
|
||||||
|
let mut url = rendered_request.url.to_owned();
|
||||||
|
let mut url_parameters = Vec::new();
|
||||||
|
for p in rendered_request.url_parameters.clone() {
|
||||||
|
if !p.enabled || p.name.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace path parameters with values from URL parameters
|
||||||
|
let old_url_string = url.clone();
|
||||||
|
url = replace_path_placeholder(&p, url.as_str());
|
||||||
|
|
||||||
|
// Remove as param if it modified the URL
|
||||||
|
if old_url_string == url {
|
||||||
|
url_parameters.push(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut request = rendered_request.clone();
|
||||||
|
request.url_parameters = url_parameters;
|
||||||
|
request.url = url;
|
||||||
|
request
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod placeholder_tests {
|
||||||
|
use crate::render::{apply_path_placeholders, replace_path_placeholder};
|
||||||
|
use yaak_models::models::{HttpRequest, HttpUrlParameter};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn placeholder_middle() {
|
||||||
|
let p = HttpUrlParameter {
|
||||||
|
name: ":foo".into(),
|
||||||
|
value: "xxx".into(),
|
||||||
|
enabled: true,
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
replace_path_placeholder(&p, "https://example.com/:foo/bar"),
|
||||||
|
"https://example.com/xxx/bar",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn placeholder_end() {
|
||||||
|
let p = HttpUrlParameter {
|
||||||
|
name: ":foo".into(),
|
||||||
|
value: "xxx".into(),
|
||||||
|
enabled: true,
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
replace_path_placeholder(&p, "https://example.com/:foo"),
|
||||||
|
"https://example.com/xxx",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn placeholder_query() {
|
||||||
|
let p = HttpUrlParameter {
|
||||||
|
name: ":foo".into(),
|
||||||
|
value: "xxx".into(),
|
||||||
|
enabled: true,
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
replace_path_placeholder(&p, "https://example.com/:foo?:foo"),
|
||||||
|
"https://example.com/xxx?:foo",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn placeholder_missing() {
|
||||||
|
let p = HttpUrlParameter {
|
||||||
|
enabled: true,
|
||||||
|
name: "".to_string(),
|
||||||
|
value: "".to_string(),
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
replace_path_placeholder(&p, "https://example.com/:missing"),
|
||||||
|
"https://example.com/:missing",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn placeholder_disabled() {
|
||||||
|
let p = HttpUrlParameter {
|
||||||
|
enabled: false,
|
||||||
|
name: ":foo".to_string(),
|
||||||
|
value: "xxx".to_string(),
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
replace_path_placeholder(&p, "https://example.com/:foo"),
|
||||||
|
"https://example.com/:foo",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn placeholder_prefix() {
|
||||||
|
let p = HttpUrlParameter {
|
||||||
|
name: ":foo".into(),
|
||||||
|
value: "xxx".into(),
|
||||||
|
enabled: true,
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
replace_path_placeholder(&p, "https://example.com/:foooo"),
|
||||||
|
"https://example.com/:foooo",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn placeholder_encode() {
|
||||||
|
let p = HttpUrlParameter {
|
||||||
|
name: ":foo".into(),
|
||||||
|
value: "Hello World".into(),
|
||||||
|
enabled: true,
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
replace_path_placeholder(&p, "https://example.com/:foo"),
|
||||||
|
"https://example.com/Hello%20World",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn apply_placeholder() {
|
||||||
|
let result = apply_path_placeholders(HttpRequest {
|
||||||
|
url: "example.com/:a/bar".to_string(),
|
||||||
|
url_parameters: vec![
|
||||||
|
HttpUrlParameter {
|
||||||
|
name: "b".to_string(),
|
||||||
|
value: "bbb".to_string(),
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
HttpUrlParameter {
|
||||||
|
name: ":a".to_string(),
|
||||||
|
value: "aaa".to_string(),
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
println!("HELLO?: {result:?}");
|
||||||
|
|
||||||
|
assert_eq!(result.url, "example.com/aaa/bar");
|
||||||
|
assert_eq!(result.url_parameters.len(), 1);
|
||||||
|
assert_eq!(result.url_parameters[0].name, "b");
|
||||||
|
assert_eq!(result.url_parameters[0].value, "bbb");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export type ImportResponse = { resources: ImportResources, };
|
|||||||
|
|
||||||
export type InternalEvent = { id: string, pluginRefId: string, replyId: string | null, payload: InternalEventPayload, windowContext: WindowContext, };
|
export type InternalEvent = { id: string, pluginRefId: string, replyId: string | null, payload: InternalEventPayload, windowContext: WindowContext, };
|
||||||
|
|
||||||
export type InternalEventPayload = { "type": "boot_request" } & BootRequest | { "type": "boot_response" } & BootResponse | { "type": "reload_request" } | { "type": "reload_response" } | { "type": "terminate_request" } | { "type": "terminate_response" } | { "type": "import_request" } & ImportRequest | { "type": "import_response" } & ImportResponse | { "type": "filter_request" } & FilterRequest | { "type": "filter_response" } & FilterResponse | { "type": "export_http_request_request" } & ExportHttpRequestRequest | { "type": "export_http_request_response" } & ExportHttpRequestResponse | { "type": "send_http_request_request" } & SendHttpRequestRequest | { "type": "send_http_request_response" } & SendHttpRequestResponse | { "type": "get_http_request_actions_request" } & GetHttpRequestActionsRequest | { "type": "get_http_request_actions_response" } & GetHttpRequestActionsResponse | { "type": "call_http_request_action_request" } & CallHttpRequestActionRequest | { "type": "get_template_functions_request" } | { "type": "get_template_functions_response" } & GetTemplateFunctionsResponse | { "type": "call_template_function_request" } & CallTemplateFunctionRequest | { "type": "call_template_function_response" } & CallTemplateFunctionResponse | { "type": "copy_text_request" } & CopyTextRequest | { "type": "template_render_request" } & TemplateRenderRequest | { "type": "template_render_response" } & TemplateRenderResponse | { "type": "show_toast_request" } & ShowToastRequest | { "type": "get_http_request_by_id_request" } & GetHttpRequestByIdRequest | { "type": "get_http_request_by_id_response" } & GetHttpRequestByIdResponse | { "type": "find_http_responses_request" } & FindHttpResponsesRequest | { "type": "find_http_responses_response" } & FindHttpResponsesResponse | { "type": "empty_response" };
|
export type InternalEventPayload = { "type": "boot_request" } & BootRequest | { "type": "boot_response" } & BootResponse | { "type": "reload_request" } | { "type": "reload_response" } | { "type": "terminate_request" } | { "type": "terminate_response" } | { "type": "import_request" } & ImportRequest | { "type": "import_response" } & ImportResponse | { "type": "filter_request" } & FilterRequest | { "type": "filter_response" } & FilterResponse | { "type": "export_http_request_request" } & ExportHttpRequestRequest | { "type": "export_http_request_response" } & ExportHttpRequestResponse | { "type": "send_http_request_request" } & SendHttpRequestRequest | { "type": "send_http_request_response" } & SendHttpRequestResponse | { "type": "get_http_request_actions_request" } & GetHttpRequestActionsRequest | { "type": "get_http_request_actions_response" } & GetHttpRequestActionsResponse | { "type": "call_http_request_action_request" } & CallHttpRequestActionRequest | { "type": "get_template_functions_request" } | { "type": "get_template_functions_response" } & GetTemplateFunctionsResponse | { "type": "call_template_function_request" } & CallTemplateFunctionRequest | { "type": "call_template_function_response" } & CallTemplateFunctionResponse | { "type": "copy_text_request" } & CopyTextRequest | { "type": "render_http_request_request" } & RenderHttpRequestRequest | { "type": "render_http_request_response" } & RenderHttpRequestResponse | { "type": "template_render_request" } & TemplateRenderRequest | { "type": "template_render_response" } & TemplateRenderResponse | { "type": "show_toast_request" } & ShowToastRequest | { "type": "get_http_request_by_id_request" } & GetHttpRequestByIdRequest | { "type": "get_http_request_by_id_response" } & GetHttpRequestByIdResponse | { "type": "find_http_responses_request" } & FindHttpResponsesRequest | { "type": "find_http_responses_response" } & FindHttpResponsesResponse | { "type": "empty_response" };
|
||||||
|
|
||||||
export type RenderHttpRequestRequest = { httpRequest: HttpRequest, purpose: RenderPurpose, };
|
export type RenderHttpRequestRequest = { httpRequest: HttpRequest, purpose: RenderPurpose, };
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,9 @@ pub enum InternalEventPayload {
|
|||||||
|
|
||||||
CopyTextRequest(CopyTextRequest),
|
CopyTextRequest(CopyTextRequest),
|
||||||
|
|
||||||
|
RenderHttpRequestRequest(RenderHttpRequestRequest),
|
||||||
|
RenderHttpRequestResponse(RenderHttpRequestResponse),
|
||||||
|
|
||||||
TemplateRenderRequest(TemplateRenderRequest),
|
TemplateRenderRequest(TemplateRenderRequest),
|
||||||
TemplateRenderResponse(TemplateRenderResponse),
|
TemplateRenderResponse(TemplateRenderResponse),
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user