diff --git a/src/frontend/src/components/forms/ApiForm.tsx b/src/frontend/src/components/forms/ApiForm.tsx
index c04b49d48c..79779c6cda 100644
--- a/src/frontend/src/components/forms/ApiForm.tsx
+++ b/src/frontend/src/components/forms/ApiForm.tsx
@@ -1,7 +1,8 @@
 import { t } from '@lingui/macro';
-import { Divider, Modal } from '@mantine/core';
+import { Alert, Divider, Modal } from '@mantine/core';
 import { Button, Center, Group, Loader, Stack, Text } from '@mantine/core';
 import { useForm } from '@mantine/form';
+import { IconAlertCircle } from '@tabler/icons-react';
 import { useQuery } from '@tanstack/react-query';
 import { AxiosResponse } from 'axios';
 import { useEffect } from 'react';
@@ -15,12 +16,13 @@ import { api } from '../../App';
  * - All other attributes are optional, and may be provided by the API
  * - However, they can be overridden by the user
  */
-export type ApiFormField = {
+export type ApiFormFieldType = {
   name: string;
   label?: string;
   value?: any;
   type?: string;
   required?: boolean;
+  hidden?: boolean;
   placeholder?: string;
   help_text?: string;
   icon?: string;
@@ -28,13 +30,21 @@ export type ApiFormField = {
 };
 
 /**
- * Extract a list of field definitions from an API response.
- * @param response : The API response to extract the field definitions from.
- * @returns A list of field definitions.
+ * Render an individual form field
  */
-function extractFieldDefinitions(response: AxiosResponse): ApiFormField[] {
-  // TODO: [];
-  return [];
+function ApiFormField({
+  field,
+  definitions
+}: {
+  field: ApiFormFieldType;
+  definitions: ApiFormFieldType[];
+}) {
+  useEffect(() => {
+    console.log('field:', field);
+    console.log('definitions:', definitions);
+  }, []);
+
+  return <Text>{field.name}</Text>;
 }
 
 /**
@@ -58,15 +68,17 @@ export function ApiForm({
   onFormSuccess,
   onFormError,
   cancelText = t`Cancel`,
-  submitText = t`Submit`
+  submitText = t`Submit`,
+  method = 'PUT'
 }: {
   name: string;
   url: string;
   pk?: number;
   title: string;
-  fields: ApiFormField[];
+  fields: ApiFormFieldType[];
   cancelText?: string;
   submitText?: string;
+  method?: string;
   opened: boolean;
   onClose?: () => void;
   onFormSuccess?: () => void;
@@ -76,35 +88,96 @@ export function ApiForm({
   const form = useForm({});
 
   // Form field definitions (via API)
-  const [fieldDefinitions, setFieldDefinitions] = useState<ApiFormField[]>([]);
+  const [fieldDefinitions, setFieldDefinitions] = useState<ApiFormFieldType[]>(
+    []
+  );
+
+  // Error observed during form construction
+  const [error, setError] = useState<string>('');
 
   const definitionQuery = useQuery({
     enabled: opened && !!url,
     queryKey: ['form-definition', name, url, pk, fields],
     queryFn: async () => {
-      let _url = url;
-
-      if (pk && pk > 0) {
-        _url += `${pk}/`;
-      }
-      console.log('Fetching form definition from API:', _url);
-
+      // Clear form construction error field
+      setError('');
       return api
-        .options(_url)
+        .options(getUrl())
         .then((response) => {
-          console.log('response:', response);
           setFieldDefinitions(extractFieldDefinitions(response));
           return response;
         })
         .catch((error) => {
-          console.error('error:', error);
+          console.error('Error fetching field definitions:', error);
+          setError(error.message);
           setFieldDefinitions([]);
         });
     }
   });
 
+  // State variable to determine if the form can render the data
+  const [canRender, setCanRender] = useState<boolean>(false);
+
+  // Update the canRender state variable on status change
+  useEffect(() => {
+    setCanRender(
+      !definitionQuery.isFetching && definitionQuery.isSuccess && !error
+    );
+  }, [definitionQuery, error]);
+
+  // Construct a fully-qualified URL based on the provided details
+  function getUrl(): string {
+    let u = url;
+
+    if (pk && pk > 0) {
+      u += `${pk}/`;
+    }
+
+    return u;
+  }
+
+  /**
+   * Extract a list of field definitions from an API response.
+   * @param response : The API response to extract the field definitions from.
+   * @returns A list of field definitions.
+   */
+  function extractFieldDefinitions(
+    response: AxiosResponse
+  ): ApiFormFieldType[] {
+    let actions = response.data?.actions[method.toUpperCase()] || [];
+
+    if (actions.length == 0) {
+      setError(`Permission denied for ${method} at ${url}`);
+      return [];
+    }
+
+    let definitions: ApiFormFieldType[] = [];
+
+    for (const fieldName in actions) {
+      const field = actions[fieldName];
+      definitions.push({
+        name: fieldName,
+        label: field.label,
+        help_text: field.help_text,
+        value: field.value,
+        type: field.type,
+        required: field.required,
+        placeholder: field.placeholder,
+        icon: field.icon
+      });
+    }
+
+    return definitions;
+  }
+
   return (
-    <Modal opened={opened} onClose={onClose} title={title}>
+    <Modal
+      size="xl"
+      radius="sm"
+      opened={opened}
+      onClose={onClose}
+      title={title}
+    >
       <Stack>
         <Divider />
         {definitionQuery.isFetching && (
@@ -112,13 +185,38 @@ export function ApiForm({
             <Loader />
           </Center>
         )}
-        {!definitionQuery.isFetching && <Text>Form definition fetched!</Text>}
+        {error && (
+          <Alert
+            radius="sm"
+            color="red"
+            title={`Error`}
+            icon={<IconAlertCircle size="1rem" />}
+          >
+            {error}
+          </Alert>
+        )}
+        {canRender && (
+          <Stack spacing="md">
+            {fields.map((field) => (
+              <ApiFormField
+                key={field.name}
+                field={field}
+                definitions={fieldDefinitions}
+              />
+            ))}
+          </Stack>
+        )}
         <Divider />
         <Group position="right">
-          <Button onClick={onClose} variant="outline" color="red">
+          <Button onClick={onClose} variant="outline" radius="sm" color="red">
             {cancelText}
           </Button>
-          <Button onClick={() => null} variant="outline" color="green">
+          <Button
+            onClick={() => null}
+            variant="outline"
+            radius="sm"
+            color="green"
+          >
             {submitText}
           </Button>
         </Group>
diff --git a/src/frontend/src/pages/Index/Home.tsx b/src/frontend/src/pages/Index/Home.tsx
index 00e32b5ea4..6ba15cc198 100644
--- a/src/frontend/src/pages/Index/Home.tsx
+++ b/src/frontend/src/pages/Index/Home.tsx
@@ -3,14 +3,14 @@ import { Group } from '@mantine/core';
 import { Button } from '@mantine/core';
 import { useState } from 'react';
 
-import { ApiForm, ApiFormField } from '../../components/forms/ApiForm';
+import { ApiForm, ApiFormFieldType } from '../../components/forms/ApiForm';
 import { PlaceholderPill } from '../../components/items/Placeholder';
 import { StylishText } from '../../components/items/StylishText';
 
 export default function Home() {
   const [formOpened, setFormOpened] = useState(false);
 
-  const fields: ApiFormField[] = [
+  const fields: ApiFormFieldType[] = [
     {
       name: 'name'
     },
@@ -31,6 +31,7 @@ export default function Home() {
         name="part-edit"
         url="/part/1/"
         fields={fields}
+        method="PUT"
         title="Edit Part"
         opened={formOpened}
         onClose={() => setFormOpened(false)}