From 758154fa14aecb49d32cef8eb1e07abe7e5c95b7 Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Sun, 12 Nov 2023 11:16:12 -0800 Subject: [PATCH] Request body is now an object --- ...20e5dcd35ec4288006e4a556448d59b63952.json} | 8 ++--- ...88df3c83e145860f8dd608410a9a9254659d.json} | 8 ++--- .../migrations/20231112180500_body_object.sql | 16 ++++++++++ src-tauri/src/main.rs | 30 ++++++++++++------- src-tauri/src/models.rs | 6 ++-- src-web/components/App.tsx | 9 +++--- src-web/components/RequestPane.tsx | 16 +++++----- .../components/WorkspaceActionsDropdown.tsx | 2 -- .../components/responseViewers/TextViewer.tsx | 1 - src-web/hooks/useActiveEnvironment.ts | 9 ++---- src-web/hooks/useActiveEnvironmentId.ts | 3 +- src-web/hooks/useFolders.ts | 2 +- src-web/hooks/useIntrospectGraphQL.ts | 6 +++- src-web/hooks/useUpdateAnyFolder.ts | 5 ++-- src-web/hooks/useVariables.ts | 4 +-- src-web/lib/models.ts | 2 +- 16 files changed, 73 insertions(+), 54 deletions(-) rename src-tauri/.sqlx/{query-a558e182f40286fe52bed5f03b2dc367b7229ab6bd9cda0a7ce219a438ccd5fd.json => query-55e4e8b66c18f85d17ada00b302720e5dcd35ec4288006e4a556448d59b63952.json} (78%) rename src-tauri/.sqlx/{query-854536c80af3f86bb9a63b8ce059ad724374b545cb23481bb3b2ce07d7414220.json => query-ae31827b9576ffba83a9de05e30688df3c83e145860f8dd608410a9a9254659d.json} (78%) create mode 100644 src-tauri/migrations/20231112180500_body_object.sql diff --git a/src-tauri/.sqlx/query-a558e182f40286fe52bed5f03b2dc367b7229ab6bd9cda0a7ce219a438ccd5fd.json b/src-tauri/.sqlx/query-55e4e8b66c18f85d17ada00b302720e5dcd35ec4288006e4a556448d59b63952.json similarity index 78% rename from src-tauri/.sqlx/query-a558e182f40286fe52bed5f03b2dc367b7229ab6bd9cda0a7ce219a438ccd5fd.json rename to src-tauri/.sqlx/query-55e4e8b66c18f85d17ada00b302720e5dcd35ec4288006e4a556448d59b63952.json index 6cf71fca..913e802e 100644 --- a/src-tauri/.sqlx/query-a558e182f40286fe52bed5f03b2dc367b7229ab6bd9cda0a7ce219a438ccd5fd.json +++ b/src-tauri/.sqlx/query-55e4e8b66c18f85d17ada00b302720e5dcd35ec4288006e4a556448d59b63952.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "\n SELECT\n id,\n model,\n workspace_id,\n folder_id,\n created_at,\n updated_at,\n name,\n url,\n method,\n body,\n body_type,\n authentication AS \"authentication!: Json>\",\n authentication_type,\n sort_priority,\n headers AS \"headers!: sqlx::types::Json>\"\n FROM http_requests\n WHERE workspace_id = ?\n ", + "query": "\n SELECT\n id,\n model,\n workspace_id,\n folder_id,\n created_at,\n updated_at,\n name,\n url,\n method,\n body AS \"body!: Json>\",\n body_type,\n authentication AS \"authentication!: Json>\",\n authentication_type,\n sort_priority,\n headers AS \"headers!: sqlx::types::Json>\"\n FROM http_requests\n WHERE workspace_id = ?\n ", "describe": { "columns": [ { @@ -49,7 +49,7 @@ "type_info": "Text" }, { - "name": "body", + "name": "body!: Json>", "ordinal": 9, "type_info": "Text" }, @@ -92,7 +92,7 @@ false, false, false, - true, + false, true, false, true, @@ -100,5 +100,5 @@ false ] }, - "hash": "a558e182f40286fe52bed5f03b2dc367b7229ab6bd9cda0a7ce219a438ccd5fd" + "hash": "55e4e8b66c18f85d17ada00b302720e5dcd35ec4288006e4a556448d59b63952" } diff --git a/src-tauri/.sqlx/query-854536c80af3f86bb9a63b8ce059ad724374b545cb23481bb3b2ce07d7414220.json b/src-tauri/.sqlx/query-ae31827b9576ffba83a9de05e30688df3c83e145860f8dd608410a9a9254659d.json similarity index 78% rename from src-tauri/.sqlx/query-854536c80af3f86bb9a63b8ce059ad724374b545cb23481bb3b2ce07d7414220.json rename to src-tauri/.sqlx/query-ae31827b9576ffba83a9de05e30688df3c83e145860f8dd608410a9a9254659d.json index eb50a819..f5e3ddd7 100644 --- a/src-tauri/.sqlx/query-854536c80af3f86bb9a63b8ce059ad724374b545cb23481bb3b2ce07d7414220.json +++ b/src-tauri/.sqlx/query-ae31827b9576ffba83a9de05e30688df3c83e145860f8dd608410a9a9254659d.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "\n SELECT\n id,\n model,\n workspace_id,\n folder_id,\n created_at,\n updated_at,\n name,\n url,\n method,\n body,\n body_type,\n authentication AS \"authentication!: Json>\",\n authentication_type,\n sort_priority,\n headers AS \"headers!: sqlx::types::Json>\"\n FROM http_requests\n WHERE id = ?\n ", + "query": "\n SELECT\n id,\n model,\n workspace_id,\n folder_id,\n created_at,\n updated_at,\n name,\n url,\n method,\n body AS \"body!: Json>\",\n body_type,\n authentication AS \"authentication!: Json>\",\n authentication_type,\n sort_priority,\n headers AS \"headers!: sqlx::types::Json>\"\n FROM http_requests\n WHERE id = ?\n ", "describe": { "columns": [ { @@ -49,7 +49,7 @@ "type_info": "Text" }, { - "name": "body", + "name": "body!: Json>", "ordinal": 9, "type_info": "Text" }, @@ -92,7 +92,7 @@ false, false, false, - true, + false, true, false, true, @@ -100,5 +100,5 @@ false ] }, - "hash": "854536c80af3f86bb9a63b8ce059ad724374b545cb23481bb3b2ce07d7414220" + "hash": "ae31827b9576ffba83a9de05e30688df3c83e145860f8dd608410a9a9254659d" } diff --git a/src-tauri/migrations/20231112180500_body_object.sql b/src-tauri/migrations/20231112180500_body_object.sql new file mode 100644 index 00000000..bba1b0a4 --- /dev/null +++ b/src-tauri/migrations/20231112180500_body_object.sql @@ -0,0 +1,16 @@ +-- Rename old column to backup name +ALTER TABLE http_requests + RENAME COLUMN body TO body_old; + +-- Create desired new body column +ALTER TABLE http_requests + ADD COLUMN body TEXT NOT NULL DEFAULT '{}'; + +-- Copy data from old to new body, in new JSON format +UPDATE http_requests +SET body = CASE WHEN body_old IS NULL THEN '{}' ELSE JSON_OBJECT('text', body_old) END +WHERE TRUE; + +-- Drop old column +ALTER TABLE http_requests + DROP COLUMN body_old; diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index be3501a4..0ec6d47d 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -17,7 +17,7 @@ use base64::Engine; use fern::colors::ColoredLevelConfig; use http::header::{HeaderName, ACCEPT, USER_AGENT}; use http::{HeaderMap, HeaderValue, Method}; -use log::info; +use log::{info, warn}; use rand::random; use reqwest::redirect::Policy; use serde::Serialize; @@ -182,17 +182,23 @@ async fn actually_send_request( let m = Method::from_bytes(request.method.to_uppercase().as_bytes()) .expect("Failed to create method"); - let builder = client.request(m, url_string.to_string()).headers(headers); - let sendable_req_result = match (request.body, request.body_type) { - (Some(raw_body), Some(_)) => { - let body = render::render(&raw_body, &workspace, environment_ref); - builder.body(body).build() + let mut request_builder = client.request(m, url_string.to_string()).headers(headers); + + if let Some(t) = &request.body_type { + let empty_value = &serde_json::to_value("").unwrap(); + let b = request.body.0; + + if t == "basic" { + let raw_text = b.get("text").unwrap_or(empty_value).as_str().unwrap_or(""); + let body = render::render(raw_text, &workspace, environment_ref); + request_builder = request_builder.body(body); + } else { + warn!("Unsupported body type: {}", t); } - _ => builder.build(), - }; + } - let sendable_req = match sendable_req_result { + let sendable_req = match request_builder.build() { Ok(r) => r, Err(e) => { return response_err(response, e.to_string(), app_handle, pool).await; @@ -648,9 +654,11 @@ async fn list_requests( db_instance: State<'_, Mutex>>, ) -> Result, String> { let pool = &*db_instance.lock().await; - models::find_requests(workspace_id, pool) + let requests = models::find_requests(workspace_id, pool) .await - .map_err(|e| e.to_string()) + .expect("Failed to find requests"); + // .map_err(|e| e.to_string()) + Ok(requests) } #[tauri::command] diff --git a/src-tauri/src/models.rs b/src-tauri/src/models.rs index e5285300..e7ab1fc3 100644 --- a/src-tauri/src/models.rs +++ b/src-tauri/src/models.rs @@ -72,7 +72,7 @@ pub struct HttpRequest { pub url: String, #[serde(default = "default_http_request_method")] pub method: String, - pub body: Option, + pub body: Json>, pub body_type: Option, pub authentication: Json>, pub authentication_type: Option, @@ -497,7 +497,7 @@ pub async fn find_requests( name, url, method, - body, + body AS "body!: Json>", body_type, authentication AS "authentication!: Json>", authentication_type, @@ -526,7 +526,7 @@ pub async fn get_request(id: &str, pool: &Pool) -> Result>", body_type, authentication AS "authentication!: Json>", authentication_type, diff --git a/src-web/components/App.tsx b/src-web/components/App.tsx index 8160ce47..f826e4ba 100644 --- a/src-web/components/App.tsx +++ b/src-web/components/App.tsx @@ -1,4 +1,5 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import { MotionConfig } from 'framer-motion'; import { Suspense } from 'react'; import { DndProvider } from 'react-dnd'; @@ -23,10 +24,10 @@ export function App() { - - - {/**/} - + + + + diff --git a/src-web/components/RequestPane.tsx b/src-web/components/RequestPane.tsx index 0edf4c38..604de7df 100644 --- a/src-web/components/RequestPane.tsx +++ b/src-web/components/RequestPane.tsx @@ -133,8 +133,8 @@ export const RequestPane = memo(function RequestPane({ style, fullHeight, classN [activeRequest, updateRequest], ); - const handleBodyChange = useCallback( - (body: string) => updateRequest.mutate({ body }), + const handleBodyTextChange = useCallback( + (text: string) => updateRequest.mutate({ body: { text } }), [updateRequest], ); const handleHeadersChange = useCallback( @@ -211,9 +211,9 @@ export const RequestPane = memo(function RequestPane({ style, fullHeight, classN placeholder="..." className="!bg-gray-50" heightMode={fullHeight ? 'full' : 'auto'} - defaultValue={activeRequest.body ?? ''} + defaultValue={`${activeRequest?.body?.text}` ?? ''} contentType="application/json" - onChange={handleBodyChange} + onChange={handleBodyTextChange} format={(v) => tryFormatJson(v)} /> ) : activeRequest.bodyType === BODY_TYPE_XML ? ( @@ -224,17 +224,17 @@ export const RequestPane = memo(function RequestPane({ style, fullHeight, classN placeholder="..." className="!bg-gray-50" heightMode={fullHeight ? 'full' : 'auto'} - defaultValue={activeRequest.body ?? ''} + defaultValue={`${activeRequest?.body?.text}` ?? ''} contentType="text/xml" - onChange={handleBodyChange} + onChange={handleBodyTextChange} /> ) : activeRequest.bodyType === BODY_TYPE_GRAPHQL ? ( ) : ( No Body diff --git a/src-web/components/WorkspaceActionsDropdown.tsx b/src-web/components/WorkspaceActionsDropdown.tsx index 5896c6e7..fd3cb266 100644 --- a/src-web/components/WorkspaceActionsDropdown.tsx +++ b/src-web/components/WorkspaceActionsDropdown.tsx @@ -2,7 +2,6 @@ import { invoke } from '@tauri-apps/api'; import classNames from 'classnames'; import { memo, useMemo } from 'react'; import { useActiveWorkspace } from '../hooks/useActiveWorkspace'; -import { useAlert } from '../hooks/useAlert'; import { useAppRoutes } from '../hooks/useAppRoutes'; import { useCreateWorkspace } from '../hooks/useCreateWorkspace'; import { useDeleteWorkspace } from '../hooks/useDeleteWorkspace'; @@ -39,7 +38,6 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({ const { appearance, toggleAppearance } = useTheme(); const dialog = useDialog(); const prompt = usePrompt(); - const alert = useAlert(); const routes = useAppRoutes(); const items: DropdownItem[] = useMemo(() => { diff --git a/src-web/components/responseViewers/TextViewer.tsx b/src-web/components/responseViewers/TextViewer.tsx index 62c2ebc3..d69e3b47 100644 --- a/src-web/components/responseViewers/TextViewer.tsx +++ b/src-web/components/responseViewers/TextViewer.tsx @@ -1,4 +1,3 @@ -import { w } from '@tauri-apps/api/clipboard-79413165'; import { useResponseBodyText } from '../../hooks/useResponseBodyText'; import { useResponseContentType } from '../../hooks/useResponseContentType'; import { tryFormatJson } from '../../lib/formatters'; diff --git a/src-web/hooks/useActiveEnvironment.ts b/src-web/hooks/useActiveEnvironment.ts index 0b22d01a..19f3fbc2 100644 --- a/src-web/hooks/useActiveEnvironment.ts +++ b/src-web/hooks/useActiveEnvironment.ts @@ -1,4 +1,4 @@ -import { useCallback, useMemo } from 'react'; +import { useMemo } from 'react'; import type { Environment } from '../lib/models'; import { useActiveEnvironmentId } from './useActiveEnvironmentId'; import { useEnvironments } from './useEnvironments'; @@ -6,10 +6,5 @@ import { useEnvironments } from './useEnvironments'; export function useActiveEnvironment(): Environment | null { const id = useActiveEnvironmentId(); const environments = useEnvironments(); - const environment = useMemo( - () => environments.find((w) => w.id === id) ?? null, - [environments, id], - ); - - return environment; + return useMemo(() => environments.find((w) => w.id === id) ?? null, [environments, id]); } diff --git a/src-web/hooks/useActiveEnvironmentId.ts b/src-web/hooks/useActiveEnvironmentId.ts index 412ae12a..a0b333c8 100644 --- a/src-web/hooks/useActiveEnvironmentId.ts +++ b/src-web/hooks/useActiveEnvironmentId.ts @@ -1,5 +1,4 @@ -import { useCallback } from 'react'; -import { useParams, useSearchParams } from 'react-router-dom'; +import { useParams } from 'react-router-dom'; import type { RouteParamsRequest } from './useAppRoutes'; export function useActiveEnvironmentId(): string | null { diff --git a/src-web/hooks/useFolders.ts b/src-web/hooks/useFolders.ts index e68a4330..a1ace628 100644 --- a/src-web/hooks/useFolders.ts +++ b/src-web/hooks/useFolders.ts @@ -1,6 +1,6 @@ import { useQuery } from '@tanstack/react-query'; import { invoke } from '@tauri-apps/api'; -import type { Folder, HttpRequest } from '../lib/models'; +import type { Folder } from '../lib/models'; import { useActiveWorkspaceId } from './useActiveWorkspaceId'; export function foldersQueryKey({ workspaceId }: { workspaceId: string }) { diff --git a/src-web/hooks/useIntrospectGraphQL.ts b/src-web/hooks/useIntrospectGraphQL.ts index 4688d63b..9091bce9 100644 --- a/src-web/hooks/useIntrospectGraphQL.ts +++ b/src-web/hooks/useIntrospectGraphQL.ts @@ -32,7 +32,11 @@ export function useIntrospectGraphQL(baseRequest: HttpRequest) { const fetchIntrospection = async () => { setIsLoading(true); setError(undefined); - const args = { ...baseRequest, body: introspectionRequestBody }; + const args = { + ...baseRequest, + bodyType: 'graphql', + body: { text: introspectionRequestBody }, + }; const response = await minPromiseMillis(sendEphemeralRequest(args, activeEnvironmentId), 700); if (response.error) { diff --git a/src-web/hooks/useUpdateAnyFolder.ts b/src-web/hooks/useUpdateAnyFolder.ts index 9755e15d..b093f2b6 100644 --- a/src-web/hooks/useUpdateAnyFolder.ts +++ b/src-web/hooks/useUpdateAnyFolder.ts @@ -1,8 +1,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { invoke } from '@tauri-apps/api'; -import type { Folder, HttpRequest } from '../lib/models'; -import { getFolder, getRequest } from '../lib/store'; -import { requestsQueryKey } from './useRequests'; +import type { Folder } from '../lib/models'; +import { getFolder } from '../lib/store'; import { foldersQueryKey } from './useFolders'; export function useUpdateAnyFolder() { diff --git a/src-web/hooks/useVariables.ts b/src-web/hooks/useVariables.ts index 67c39ac8..0a9cfaa8 100644 --- a/src-web/hooks/useVariables.ts +++ b/src-web/hooks/useVariables.ts @@ -1,6 +1,6 @@ import { useQuery } from '@tanstack/react-query'; import { invoke } from '@tauri-apps/api'; -import type { Variable } from '../lib/models'; +import type { EnvironmentVariable } from '../lib/models'; export function variablesQueryKey({ environmentId }: { environmentId: string }) { return ['variables', { environmentId }]; @@ -11,7 +11,7 @@ export function useVariables({ environmentId }: { environmentId: string }) { useQuery({ queryKey: variablesQueryKey({ environmentId }), queryFn: async () => { - return (await invoke('list_variables', { environmentId })) as Variable[]; + return (await invoke('list_variables', { environmentId })) as EnvironmentVariable[]; }, }).data ?? [] ); diff --git a/src-web/lib/models.ts b/src-web/lib/models.ts index 51836e8e..6a208c8b 100644 --- a/src-web/lib/models.ts +++ b/src-web/lib/models.ts @@ -56,7 +56,7 @@ export interface HttpRequest extends BaseModel { sortPriority: number; name: string; url: string; - body: string | null; + body: Record; bodyType: string | null; authentication: Record; authenticationType: string | null;