Skip to content

Commit

Permalink
fully transitioned to detailed state data structure
Browse files Browse the repository at this point in the history
  • Loading branch information
Mazuh committed Feb 24, 2024
1 parent d97d20a commit 6fd5ba1
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 29 deletions.
4 changes: 4 additions & 0 deletions src/entities/project-entities.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
/** Each project is like a "folder" to store multiple specs of requests. */
export interface Project {
readonly uuid: string;
readonly name: string;
readonly sections: ProjectSection[];
readonly specs: ProjectRequestSpec[];
}

/** TODO: to organize requests as "subfolders" in a project. */
export interface ProjectSection {
readonly uuid: string;
readonly name: string;
}

/** User specification of how its request looks like. */
export interface ProjectRequestSpec {
readonly uuid: string;
readonly url: string;
Expand All @@ -18,6 +21,7 @@ export interface ProjectRequestSpec {
readonly body: string;
}

/** Data structure of HTTP headers specified in a `ProjectRequestSpec`, can be toggled. */
export interface ProjectRequestSpecHeader {
readonly key: string;
readonly value: string;
Expand Down
34 changes: 30 additions & 4 deletions src/entities/runtime-entities.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,46 @@
/**
* Representation of each spec being put to exectution,
* become concrete and not only a spec.
*/
export interface RuntimeState {
/**
* `"idle"` is waiting runtime didn't start yet.
* `"running"` is request being performed right now.
* `"success"` is request finished, responded with ok status.
* `"unsuccess"` is request finished, responded with not ok status.
* `"error"` for when the request didn't even reach the server.
*/
readonly step: "idle" | "running" | "success" | "unsuccess" | "error";
readonly text: string;
readonly status: number;
/** Observability snapshot of the request. With blank values while `step="idle"`. */
readonly request: RequestInfo;
/** Observability of the response. With blank values if there wasn't a server response yet. */
readonly response: ResponseInfo;
/** Any exception unrelated to the direct 1:1 request-response relation (see `step="error"`). */
readonly errorMessage: string;
/** Useful metadata for performance visibility. */
readonly startedAt: number;
/** Useful metadata for performance visibility. */
readonly finishedAt: number;
}

/**
* Applied final data used to make a real request run.
*
* However, due to browser policies, the actual request headers for example are not
* fully acessible. There's no API available to preview what the browser itself intercepted.
*/
export interface RequestInfo {
readonly url: string;
readonly method: string;
readonly body: string;
readonly headers: { [key: string]: string };
readonly headers: Array<{ key: string; value: string }>;
}

/**
* Response received by the server after a request.
*/
export interface ResponseInfo {
readonly status: number;
readonly body: string;
readonly headers: { [key: string]: string };
readonly headers: Array<{ key: string; value: string }>;
}
89 changes: 64 additions & 25 deletions src/features/project-workspace/ProjectWorkspacePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ import {
} from "@/components/ui/dialog";
import { RequestsSpecsContextProvider } from "./RequestsSpecsContextProvider";
import { useRequestsSpecs } from "./RequestsSpecsContext";
import {
RuntimeState,
RequestInfo,
ResponseInfo,
} from "@/entities/runtime-entities";
import { Input } from "@/components/ui/input";
import {
Select,
Expand All @@ -33,7 +38,6 @@ import {
SelectValue,
} from "@/components/ui/select";
import { Progress } from "@/components/ui/progress";
import { RuntimeState } from "@/entities/runtime-entities";

export function ProjectWorkspacePage() {
const params = useParams();
Expand Down Expand Up @@ -190,36 +194,49 @@ function RequestSpecEditor(props: {

const [runtime, setRuntime] = useState<RuntimeState>({
step: "idle",
text: "",
status: 0,
request: {
url: "",
method: "",
body: "",
headers: [],
},
response: {
status: 0,
body: "",
headers: [],
},
errorMessage: "",
startedAt: 0,
finishedAt: 0,
});

const begin = () =>
const begin = (request: RequestInfo) =>
setRuntime({
step: "running",
text: "",
status: 0,
request,
response: {
status: 0,
body: "",
headers: [],
},
errorMessage: "",
startedAt: Date.now(),
finishedAt: 0,
});

const success = (text: string, status: number) =>
const success = (response: ResponseInfo) =>
setRuntime((updatingRuntime) => ({
...updatingRuntime,
step: "success",
status,
text,
response,
finishedAt: Date.now(),
}));

const unsuccess = (text: string, status: number) =>
const unsuccess = (response: ResponseInfo) =>
setRuntime((updatingRuntime) => ({
...updatingRuntime,
step: "unsuccess",
text,
status,
response,
finishedAt: Date.now(),
}));

Expand All @@ -232,16 +249,35 @@ function RequestSpecEditor(props: {
}));

const runSpec = async (running: { method: string; url: string }) => {
begin();
const requestInfo: RequestInfo = {
url: running.url,
method: running.method,
body: "",
headers: spec?.headers.length
? spec.headers.filter((h) => h.isEnabled)
: [],
};

begin(requestInfo);
try {
const response = await fetch(running.url, {
method: running.method,
method: requestInfo.method,
headers: requestInfo.headers.reduce(
(headers, header) => ({ ...headers, [header.key]: header.value }),
{}
),
});
const text = await response.text();
const responseInfo: ResponseInfo = {
status: response.status,
body: await response.text(),
headers: Object.entries(response.headers).map(
([key, value]: [string, string]) => ({ key, value })
),
};
if (response.ok) {
success(text, response.status);
success(responseInfo);
} else {
unsuccess(text, response.status);
unsuccess(responseInfo);
}
} catch (exception) {
error((exception as Error).message);
Expand Down Expand Up @@ -308,11 +344,12 @@ function RequestSpecEditor(props: {
{runtime.step === "success" && (
<>
<p className="text-green-400 mb-3">
<strong>HTTP success:</strong> <code>{runtime.status}</code>
<strong>HTTP success:</strong>{" "}
<code>{runtime.response.status}</code>
</p>
{runtime.text ? (
{runtime.response.body ? (
<p>
<code>{runtime.text}</code>
<code>{runtime.response.body}</code>
</p>
) : (
<p>
Expand All @@ -324,11 +361,12 @@ function RequestSpecEditor(props: {
{runtime.step === "unsuccess" && (
<>
<p className="text-red-400 mb-3">
<strong>HTTP bad code:</strong> <code>{runtime.status}</code>
<strong>HTTP bad code:</strong>{" "}
<code>{runtime.response.status}</code>
</p>
{runtime.text ? (
{runtime.response.body ? (
<p>
<code>{runtime.text}</code>
<code>{runtime.response.body}</code>
</p>
) : (
<p>
Expand All @@ -340,9 +378,10 @@ function RequestSpecEditor(props: {
{runtime.step === "error" && (
<>
<p className="text-red-400 mb-3">Error.</p>
{runtime.text ? (
{runtime.errorMessage ? (
<p>
<strong>Browser reason:</strong> <code>{runtime.text}</code>
<strong>Browser reason:</strong>{" "}
<code>{runtime.errorMessage}</code>
</p>
) : (
<p>
Expand Down

0 comments on commit 6fd5ba1

Please sign in to comment.