feat add pre-request script execution

Initializes JavaScript runtime during application startup.
Executes user-defined pre-request scripts before sending API requests, allowing modification of request details like URL, headers, and body.
Updates script execution environment for better scoping and uses synchronous evaluation.
This commit is contained in:
Udhay-Adithya
2025-05-01 16:48:34 +05:30
parent e936f382e0
commit 36061f660a
4 changed files with 41 additions and 15 deletions

View File

@@ -487,7 +487,6 @@ const kMsgClearHistorySuccess = 'History cleared successfully';
const kMsgClearHistoryError = 'Error clearing history';
const kMsgShareError = "Unable to share";
const String setupScript = r"""
// === APIDash Setup Script ===
@@ -547,7 +546,7 @@ try {
// This object provides functions to interact with the request, response,
// environment, and the Dart host application.
const ad = {
var ad = {
/**
* Functions to modify the request object *before* it is sent.
* Only available in pre-request scripts.

View File

@@ -1,3 +1,4 @@
import 'package:apidash/services/flutter_js_service.dart';
import 'package:apidash_design_system/apidash_design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
@@ -11,6 +12,7 @@ void main() async {
WidgetsFlutterBinding.ensureInitialized();
var settingsModel = await getSettingsFromSharedPrefs();
var onboardingStatus = await getOnboardingStatusFromSharedPrefs();
initializeJsRuntime();
final initStatus = await initApp(
kIsDesktop,
settingsModel: settingsModel,

View File

@@ -1,3 +1,6 @@
import 'dart:developer';
import 'package:apidash/services/flutter_js_service.dart';
import 'package:apidash_core/apidash_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
@@ -280,6 +283,18 @@ class CollectionStateNotifier
return;
}
if (requestModel != null && requestModel.preRequestScript.isNotEmpty) {
final res = await executePreRequestScript(
currentRequestModel: requestModel,
activeEnvironment: {},
);
requestModel =
requestModel.copyWith(httpRequestModel: res.updatedRequest);
log(res.updatedRequest.url);
log(res.updatedRequest.headersMap.toString());
log(res.updatedRequest.body.toString());
}
APIType apiType = requestModel!.apiType;
HttpRequestModel substitutedHttpRequestModel =
getSubstitutedHttpRequestModel(requestModel.httpRequestModel!);

View File

@@ -3,6 +3,7 @@
import 'dart:convert';
import 'dart:developer';
import 'package:apidash/consts.dart';
import 'package:apidash/models/request_model.dart';
import 'package:apidash_core/models/http_request_model.dart';
import 'package:flutter/services.dart';
@@ -12,6 +13,7 @@ late JavascriptRuntime jsRuntime;
void initializeJsRuntime() {
jsRuntime = getJavascriptRuntime();
setupJsBridge();
}
void disposeJsRuntime() {
@@ -89,7 +91,6 @@ Future<
})> executePreRequestScript({
required RequestModel currentRequestModel,
required Map<String, dynamic> activeEnvironment,
required String setupScript,
}) async {
if (currentRequestModel.preRequestScript.trim().isEmpty) {
// No script, return original data
@@ -109,27 +110,37 @@ Future<
// Inject data as JS variables
// Escape strings properly if embedding directly
final dataInjection = """
const injectedRequestJson = ${jsEscapeString(requestJson)};
const injectedEnvironmentJson = ${jsEscapeString(environmentJson)};
const injectedResponseJson = null; // Not needed for pre-request
var injectedRequestJson = ${jsEscapeString(requestJson)};
var injectedEnvironmentJson = ${jsEscapeString(environmentJson)};
var injectedResponseJson = null; // Not needed for pre-request
""";
// Concatenate & Add Return
final fullScript = """
(function() {
// --- Data Injection (now constants within the IIFE scope) ---
$dataInjection
// --- Setup Script (will declare variables within the IIFE scope) ---
$setupScript
// --- User Script ---
// --- User Script (will execute within the IIFE scope)---
$userScript
// --- Return Result ---
JSON.stringify({ request: request, environment: environment });
// --- Return Result (accesses variables from the IIFE scope) ---
// Ensure 'request' and 'environment' are accessible here
return JSON.stringify({ request: request, environment: environment });
})(); // Immediately invoke the function
""";
// TODO: Do something better to avoid null check here.
HttpRequestModel resultingRequest = httpRequest!;
Map<String, dynamic> resultingEnvironment = Map.from(activeEnvironment);
try {
// Execute
final JsEvalResult result = await jsRuntime.evaluateAsync(fullScript);
final JsEvalResult result = jsRuntime.evaluate(fullScript);
// Process Results
if (result.isError) {
@@ -158,7 +169,6 @@ Future<
}
} catch (e) {
print("Dart-level error during pre-request script execution: $e");
// Handle Dart-level errors (e.g., JS runtime issues)
}
return (