Browse Source

initial concept

tonyboylehub 11 months ago
parent
commit
4691186219

+ 8 - 2
markdoc/tags.js

@@ -8,6 +8,7 @@ import Image from '@/components/Image'
 import { QuickLink, QuickLinks } from '@/components/QuickLinks'
 import { QuickLink, QuickLinks } from '@/components/QuickLinks'
 import { Seperator } from '@/components/Seperator'
 import { Seperator } from '@/components/Seperator'
 import { Totem, TotemAccordion, TotemProse } from '@/components/Totem'
 import { Totem, TotemAccordion, TotemProse } from '@/components/Totem'
+import ApiComponentWrapper from '@/components/apiComponents/apiComponentWrapper'
 import {
 import {
   Diagram,
   Diagram,
   transformDiagramTag,
   transformDiagramTag,
@@ -17,7 +18,6 @@ import { PackagesUsed } from '@/components/helperComponents/packagesUsed'
 import { MarkdocGrid as ProductGrid } from '@/components/products/Grid'
 import { MarkdocGrid as ProductGrid } from '@/components/products/Grid'
 import { MarkdocGrid as AllProductsGrid } from '@/components/products/GridAllProducts'
 import { MarkdocGrid as AllProductsGrid } from '@/components/products/GridAllProducts'
 
 
-
 const tags = {
 const tags = {
   callout: {
   callout: {
     attributes: {
     attributes: {
@@ -58,7 +58,7 @@ const tags = {
       description: { type: String },
       description: { type: String },
       icon: { type: String },
       icon: { type: String },
       href: { type: String },
       href: { type: String },
-      target: { type: String }
+      target: { type: String },
     },
     },
   },
   },
   'product-grid': {
   'product-grid': {
@@ -162,6 +162,12 @@ const tags = {
     },
     },
     selfClosing: true,
     selfClosing: true,
   },
   },
+  apiRenderer: {
+    attributes: {
+      method: { type: String },
+    },
+    render: ApiComponentWrapper,
+  },
 }
 }
 
 
 export default tags
 export default tags

+ 2 - 2
src/components/Fence.jsx

@@ -11,9 +11,9 @@ export function Fence({ children, language }) {
       theme={undefined}
       theme={undefined}
     >
     >
       {({ className, style, tokens, getTokenProps }) => (
       {({ className, style, tokens, getTokenProps }) => (
-        <pre className={className + ' relative scrollbar '} style={style}>
+        <pre className={className + ' scrollbar relative '} style={style}>
           <CopyToClipboardButton text={children} />
           <CopyToClipboardButton text={children} />
-          <code className='w-[calc(100%-25px)] block overflow-auto '>
+          <code className="block w-[calc(100%-25px)] overflow-auto ">
             {tokens.map((line, lineIndex) => (
             {tokens.map((line, lineIndex) => (
               <Fragment key={lineIndex}>
               <Fragment key={lineIndex}>
                 {line
                 {line

+ 33 - 0
src/components/apiComponents/apiComponentWrapper.jsx

@@ -0,0 +1,33 @@
+'use client'
+
+import apiMethods from '@/lib/api/aura/methods'
+import { useState } from 'react'
+import ApiParameterDisplay from './apiParams'
+import LanguageRenderer from './languageRenderer'
+
+const ApiComponentWrapper = (args) => {
+  const api = apiMethods[args.method]
+
+  const [playGroundParams, setPlayGroundParams] = useState(api)
+
+  const handleSetParam = (param) => {
+    const newParams = playGroundApi.params.map((p) => {
+      if (p.name === param.name) {
+        return param
+      }
+      return p
+    })
+
+    setPlayGroundApi({ ...playGroundApi, params: newParams })
+  }
+
+  console.log(api)
+  return (
+    <div className="max-width[800px] flex gap-8">
+      <ApiParameterDisplay params={api.params} setParam={(param) => {}} />
+      <LanguageRenderer api={api} playgroundParams={playGroundParams} />
+    </div>
+  )
+}
+
+export default ApiComponentWrapper

+ 91 - 0
src/components/apiComponents/apiParams.jsx

@@ -0,0 +1,91 @@
+// Recursive component for rendering nested parameters
+const ParamRenderer = ({ param, subValue }) => {
+  let content
+
+  switch (param.type) {
+    case 'string':
+      content = (
+        <input
+          type="text"
+          className="w-full rounded px-2"
+          placeholder={param.value}
+        />
+      )
+      break
+
+    case 'number':
+      content = (
+        <input
+          type="number"
+          className="w-full rounded px-2"
+          placeholder={param.value}
+        />
+      )
+      break
+
+    case 'object':
+      content = (
+        <div className="flex flex-col gap-4">
+          {Object.entries(param.value).map(([key, value]) => (
+            <ParamRenderer
+              key={key}
+              param={{ name: key, ...value, subValue: true }}
+            />
+          ))}
+        </div>
+      )
+      break
+
+    case 'array':
+      content = (
+        <ul>
+          {param.value.map((item, index) => (
+            <li key={index}>{item}</li>
+          ))}
+        </ul>
+      )
+      break
+
+    case 'boolean':
+      content = (
+        <select className="w-full rounded px-2">
+          <option value="true">true</option>
+          <option value="false">false</option>
+        </select>
+      )
+      break
+
+    default:
+      content = <span>{String(param.value)}</span>
+  }
+
+  return (
+    <div
+      className={`${!subValue && 'border-t border-white'} py-4 ${
+        param.type === 'object' ? '' : 'flex gap-2'
+      }`}
+    >
+      <strong>{param.name} </strong>({param.type}) {content}
+    </div>
+  )
+}
+
+// Main component
+const ApiParameterDisplay = ({ params }) => {
+  console.log(params)
+
+  return (
+    <div
+      className={`flex w-full max-w-[400px] flex-col gap-4 rounded-xl border border-white p-4`}
+    >
+      <div>Body</div>
+      <div className="flex flex-col">
+        {params.map((param) => (
+          <ParamRenderer key={param.name} param={param} />
+        ))}
+      </div>
+    </div>
+  )
+}
+
+export default ApiParameterDisplay

+ 60 - 0
src/components/apiComponents/endPointSelector.jsx

@@ -0,0 +1,60 @@
+import { useState } from 'react'
+
+const endPoints = {
+  solanaAuraMainnet: {
+    name: 'Aura Mainnet',
+    uri: 'https://aura-mainnet.metaplex.com',
+  },
+  solanaAuraDevnet: {
+    name: 'Aura Devnet',
+    uri: 'https://aura-devnet.metaplex.com',
+  },
+  eclipseAuraMainnet: {
+    name: 'Eclipse Mainnet',
+    uri: 'https://aura-eclipse-mainnet.metaplex.com',
+  },
+  eclipseAuraDevnet: {
+    name: 'Eclipse Devnet',
+    uri: 'https://aura-eclipse-devnet.metaplex.com',
+  },
+  custom: {
+    name: 'Custom',
+    uri: 'custom',
+  },
+}
+
+const EndPointSelector = ({ setActiveEndpoint }) => {
+  const [isCustom, setIsCustom] = useState(false)
+
+  return (
+    <div className="flex flex-col gap-8">
+      <div>End Point</div>
+      <select
+        className="w-full rounded-xl p-2"
+        onChange={(e) => {
+          if (e.target.value === 'custom') {
+            setIsCustom(true)
+          } else {
+            setIsCustom(false)
+            setActiveEndpoint(e.target.value)
+          }
+        }}
+      >
+        {Object.entries(endPoints).map(([key, value]) => (
+          <option key={key} value={value.uri}>
+            {value.name}
+          </option>
+        ))}
+      </select>
+      {isCustom && (
+        <input
+          type="text"
+          placeholder="https://"
+          className="w-full rounded-xl p-2"
+        />
+      )}
+    </div>
+  )
+}
+
+export default EndPointSelector

+ 63 - 0
src/components/apiComponents/languageComponents/cSharpRenderer.jsx

@@ -0,0 +1,63 @@
+const { Fence } = require("@/components/Fence")
+const { default: renderRequestBody } = require("@/lib/api/renderRequestBody")
+
+const CSharpRequestRenderer = ({ method, url, headers, body }) => {
+    const headerString = headers
+      ? headers.map(({ key, value }) => `'${key}': '${value}'`).join(', ')
+      : ''
+    const bodyString = body ? renderRequestBody(body) : ''
+  
+    const object = {
+      method: method,
+      headers: headers,
+      body: bodyString,
+    }
+  
+    const code = `using System;
+  using System.Net.Http;
+  using System.Text;
+  
+  class Program
+  
+  {
+      static void Main()
+      {
+          var url = "${url}";
+          var headers = new System.Collections.Generic.Dictionary<string, string>
+          {
+              ${headerString}
+          };
+          var data = new StringContent(\`${JSON.stringify(
+            object,
+            null,
+            2
+          )}\`, Encoding.UTF8, "application/json");
+  
+          var client = new HttpClient();
+          var request = new HttpRequestMessage
+          {
+              Method = new HttpMethod("${method}"),
+              RequestUri = new Uri(url),
+              Content = data
+          };
+  
+          foreach (var header in headers)
+          {
+              request.Headers.Add(header.Key, header.Value);
+          }
+  
+          var response = client.SendAsync(request).Result;
+  
+          Console.WriteLine(response.StatusCode);
+      }
+  }
+    `
+  
+    return (
+      <Fence className="w-full" language="c">
+        {code}
+      </Fence>
+    )
+  }
+
+  export default CSharpRequestRenderer

+ 19 - 0
src/components/apiComponents/languageComponents/curlRequestRenderer.jsx

@@ -0,0 +1,19 @@
+import { Fence } from '@/components/Fence'
+import renderRequestBody from '@/lib/api/renderRequestBody'
+
+const CurlRequestRenderer = ({ method, url, headers, body }) => {
+  const headerString = headers
+    ? headers.map(({ key, value }) => `-H '${key}: ${value}'`).join(' ')
+    : ''
+  const bodyString = body ? renderRequestBody(body) : ''
+
+  const code = `curl -X ${method} ${headerString} -d '${bodyString}' ${url}`
+
+  return (
+    <Fence className="w-full" language="bash">
+      {code}
+    </Fence>
+  )
+}
+
+export default CurlRequestRenderer

+ 61 - 0
src/components/apiComponents/languageComponents/goRequestRenderer.jsx

@@ -0,0 +1,61 @@
+import renderRequestBody from '@/lib/api/renderRequestBody'
+
+const { Fence } = require('@/components/Fence')
+
+const GoRequestRenderer = ({ method, url, headers, body }) => {
+  const headerString = headers
+    ? headers.map(({ key, value }) => `'${key}': '${value}'`).join(', ')
+    : ''
+  const bodyString = body ? renderRequestBody(body) : ''
+
+  const object = {
+    method: method,
+    headers: headers,
+    body: bodyString,
+  }
+
+  const code = `package main
+
+import (
+  "bytes"
+  "fmt"
+  "net/http"
+)
+
+
+func main() {
+  url := "${url}"
+  headers := map[string]string{
+    ${headerString}
+  }
+  data := bytes.NewBuffer([]byte(\`${JSON.stringify(object, null, 2)}\`))
+
+  req, err := http.NewRequest("${method}", url, data)
+  if err != nil {
+    fmt.Println(err)
+  }
+
+  for key, value := range headers {
+    req.Header.Set(key, value)
+  }
+
+  client := &http.Client{}
+  resp, err := client.Do(req)
+  if err != nil {
+    fmt.Println(err)
+  }
+
+  defer resp.Body.Close()
+
+  fmt.Println(resp.Status)
+}
+  `
+
+  return (
+    <Fence className="w-full" language="go">
+      {code}
+    </Fence>
+  )
+}
+
+export default GoRequestRenderer

+ 56 - 0
src/components/apiComponents/languageComponents/javaRenderer.jsx

@@ -0,0 +1,56 @@
+const { Fence } = require("@/components/Fence")
+const { default: renderRequestBody } = require("@/lib/api/renderRequestBody")
+
+const JavaRenderer = ({ method, url, headers, body }) => {
+    const headerString = headers
+      ? headers.map(({ key, value }) => `'${key}': '${value}'`).join(', ')
+      : ''
+    const bodyString = body ? renderRequestBody(body) : ''
+  
+    const object = {
+      method: method,
+      headers: headers,
+      body: bodyString,
+    }
+  
+    const code = `import java.net.URI;
+    import java.net.http.HttpClient;
+    import java.net.http.HttpRequest;
+    import java.net.http.HttpResponse;
+    import java.net.http.HttpResponse.BodyHandlers;
+    import java.net.http.HttpRequest.BodyPublishers;
+    import java.util.Map;
+    import java.util.HashMap;
+    
+    public class Main {
+        public static void main(String[] args) throws Exception {
+            String url = "${url}";
+            Map<String, String> headers = new HashMap<String, String>() {{
+                ${headerString}
+            }};
+            String data = "${JSON.stringify(object, null, 2)}";
+    
+            HttpClient client = HttpClient.newHttpClient();
+            HttpRequest request = HttpRequest.newBuilder()
+                .uri(URI.create(url))
+                .headers(headers.entrySet().stream()
+                    .map(e -> e.getKey() + ": " + e.getValue())
+                    .toArray(String[]::new))
+                .method("${method}", BodyPublishers.ofString(data))
+                .build();
+    
+            HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
+    
+            System.out.println(response.body());
+        }
+    }
+    `
+  
+    return (
+      <Fence className="w-full" language="java">
+        {code}
+      </Fence>
+    )
+  }
+
+  export default JavaRenderer

+ 34 - 0
src/components/apiComponents/languageComponents/javascriptRequestRenderer.jsx

@@ -0,0 +1,34 @@
+import { Fence } from '@/components/Fence'
+import renderRequestBody from '@/lib/api/renderRequestBody'
+
+const JavascriptRequestRenderer = ({ method, url, headers, body }) => {
+  const headerString = headers
+    ? headers.map(({ key, value }) => `'${key}': '${value}'`).join(', ')
+    : ''
+  const bodyString = body ? renderRequestBody(body) : ''
+
+  const object = {
+    method: method,
+    headers: headers,
+    body: bodyString,
+  }
+
+  const code = `const res = await fetch('${url}', ${JSON.stringify(
+    object,
+    null,
+    2
+  )}
+  
+  const json = await res.json()
+
+  console.log(json)
+  )`
+
+  return (
+    <Fence className="w-full" language="javascript">
+      {code}
+    </Fence>
+  )
+}
+
+export default JavascriptRequestRenderer

+ 45 - 0
src/components/apiComponents/languageComponents/phpRenderer.jsx

@@ -0,0 +1,45 @@
+import { Fence } from '@/components/Fence'
+import renderRequestBody from '@/lib/api/renderRequestBody'
+
+const PhpRenderer = ({ method, url, headers, body }) => {
+  const headerString = headers
+    ? headers.map(({ key, value }) => `'${key}' => '${value}'`).join(', ')
+    : ''
+  const bodyString = body ? renderRequestBody(body) : ''
+
+  const object = {
+    method: method,
+    headers: headers,
+    body: bodyString,
+  }
+
+  const code = `<?php
+    $url = '${url}';
+    $headers = array(
+      ${headerString}
+    );
+    $data = json_encode(${JSON.stringify(object, null, 2)});
+    
+    $ch = curl_init();
+    
+    curl_setopt($ch, CURLOPT_URL, $url);
+    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, '${method}');
+    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
+    
+    $result = curl_exec($ch);
+    
+    curl_close($ch);
+    
+    echo $result;
+    ?>`
+
+  return (
+    <Fence className="w-full" language="php">
+      {code}
+    </Fence>
+  )
+}
+
+export default PhpRenderer

+ 38 - 0
src/components/apiComponents/languageComponents/pythonRequestRenderer.jsx

@@ -0,0 +1,38 @@
+import { Fence } from '@/components/Fence'
+import renderRequestBody from '@/lib/api/renderRequestBody'
+
+const PythonRequestRenderer = ({ method, url, headers, body }) => {
+  const headerString = headers
+    ? headers.map(({ key, value }) => `'${key}': '${value}'`).join(', ')
+    : ''
+  const bodyString = body ? renderRequestBody(body) : ''
+
+  const object = {
+    method: method,
+    headers: headers,
+    body: bodyString,
+  }
+
+  const code = `import requests
+  
+  url = "${url}"
+  headers = {
+      ${headerString}
+  }
+  data = ${JSON.stringify(object, null, 2)}
+  
+  response = requests.request("${method}", url, headers=headers, data=data)
+  
+  print(response.text)
+  `
+
+  return (
+    <Fence className="w-full" language="python">
+      {code}
+    </Fence>
+  )
+}
+
+export default PythonRequestRenderer
+
+

+ 0 - 0
src/components/apiComponents/languageComponents/umiRequestRenderer.jsx


+ 126 - 0
src/components/apiComponents/languageRenderer.jsx

@@ -0,0 +1,126 @@
+import { useState } from 'react'
+import EndPointSelector from './endPointSelector'
+import CSharpRequestRenderer from './languageComponents/cSharpRenderer'
+import CurlRequestRenderer from './languageComponents/curlRequestRenderer'
+import GoRequestRenderer from './languageComponents/goRequestRenderer'
+import JavaRenderer from './languageComponents/javaRenderer'
+import JavascriptRequestRenderer from './languageComponents/javascriptRequestRenderer'
+import PhpRenderer from './languageComponents/phpRenderer'
+import PythonRequestRenderer from './languageComponents/pythonRequestRenderer'
+import LanguageSelector from './languageSelector'
+
+const LanguageRenderer = ({ api, playgroundParams }) => {
+  const [activeEndpoint, setActiveEndpoint] = useState(
+    'https://aura-mainnet.metaplex.com'
+  )
+  const [activeLanguage, setActiveLanguage] = useState('javascript')
+
+  const renderLanguage = (activeLanguage) => {
+    switch (activeLanguage) {
+      case 'javascript':
+        return (
+          <div className="flex flex-col">
+            <div>{activeLanguage}</div>
+            <JavascriptRequestRenderer
+              method={api.method}
+              url={activeEndpoint}
+              headers={api.headers}
+              body={api.params}
+            />
+          </div>
+        )
+
+      case 'python':
+        return (
+          <div className="flex flex-col">
+            <div>{activeLanguage}</div>
+            <PythonRequestRenderer
+              method={api.method}
+              url={activeEndpoint}
+              headers={api.headers}
+              body={api.params}
+            />
+          </div>
+        )
+
+      case 'curl':
+        return (
+          <div className="flex flex-col">
+            <div>{activeLanguage}</div>
+            <CurlRequestRenderer
+              method={api.method}
+              url={activeEndpoint}
+              headers={api.headers}
+              body={api.params}
+            />
+          </div>
+        )
+
+      case 'go':
+        return (
+          <div className="flex flex-col">
+            <div>{activeLanguage}</div>
+            <GoRequestRenderer
+              method={api.method}
+              url={activeEndpoint}
+              headers={api.headers}
+              body={api.params}
+            />
+          </div>
+        )
+
+      case 'csharp':
+        return (
+          <div className="flex flex-col">
+            <div>{activeLanguage}</div>
+            <CSharpRequestRenderer
+              method={api.method}
+              url={activeEndpoint}
+              headers={api.headers}
+              body={api.params}
+            />
+          </div>
+        )
+
+      case 'java':
+        return (
+          <div className="flex flex-col">
+            <div>{activeLanguage}</div>
+            <JavaRenderer
+              method={api.method}
+              url={activeEndpoint}
+              headers={api.headers}
+              body={api.params}
+            />
+          </div>
+        )
+
+      case 'php':
+        return (
+          <div className="flex flex-col">
+            <div>{activeLanguage}</div>
+            <PhpRenderer
+              method={api.method}
+              url={activeEndpoint}
+              headers={api.headers}
+              body={api.params}
+            />
+          </div>
+        )
+    }
+  }
+
+  return (
+    <div className="flex w-full flex-col gap-8 overflow-hidden">
+      <EndPointSelector
+        setActiveEndpoint={(endpoint) => setActiveEndpoint(endpoint)}
+      />
+      <LanguageSelector
+        setActiveLanguage={(language) => setActiveLanguage(language)}
+      />
+      {renderLanguage(activeLanguage)}
+    </div>
+  )
+}
+
+export default LanguageRenderer

+ 41 - 0
src/components/apiComponents/languageSelector.jsx

@@ -0,0 +1,41 @@
+const languages = [
+  'javascript',
+  'python',
+  'ruby',
+  'go',
+  'java',
+  'csharp',
+  'swift',
+  'kotlin',
+  'php',
+  'typescript',
+  'shell',
+  'curl',
+]
+
+const LanguageSelector = ({ activeLanguage, setActiveLanguage }) => {
+  return (
+    <div className="flex flex-col gap-2">
+        <div>Language Selector</div>
+      <div className="flex gap-4 overflow-auto py-2">
+        {languages
+          .sort((a, b) => a.localeCompare(b))
+          .map((language) => (
+            <button
+              key={language}
+              className={`rounded-md px-4 py-2 ${
+                activeLanguage === language
+                  ? 'bg-primary text-white'
+                  : 'bg-gray-200 text-gray-800'
+              }`}
+              onClick={() => setActiveLanguage(language)}
+            >
+              {language}
+            </button>
+          ))}
+      </div>
+    </div>
+  )
+}
+
+export default LanguageSelector

+ 33 - 0
src/lib/api/aura/getAsset.js

@@ -0,0 +1,33 @@
+const testApiMethod = {
+    method: 'getAsset',
+    params: [
+      {
+        type: 'string',
+        name: 'name',
+        value: 'John Doe',
+        availableValues: ['John Doe', 'Jane Doe'],
+        optional: true,
+      },
+      { type: 'number', name: 'age', value: 30 },
+      { type: 'boolean', name: 'isStudent', value: false },
+      {
+        type: 'array',
+        name: 'hobbies',
+        value: ['reading', 'coding', 'hiking'],
+      },
+      {
+        type: 'object',
+        name: 'address',
+        value: {
+          city: { type: 'string', value: 'Metropolis' },
+          street: { type: 'string', value: 'Main Street' },
+          zip: { type: 'number', value: 54321 },
+        },
+      },
+      { type: 'null', name: 'middleName', value: null },
+      { type: 'string', name: 'dateOfBirth', value: '1992-05-14' },
+      { type: 'file', name: 'profilePicture', value: 'base64_encoded_string' },
+    ],
+  }
+  
+  export default testApiMethod

+ 7 - 0
src/lib/api/aura/methods.js

@@ -0,0 +1,7 @@
+import testApiMethod from "./test"
+
+
+const apiMethods = {
+  testApiMethod: testApiMethod,
+}
+export default apiMethods

+ 35 - 0
src/lib/api/aura/test.js

@@ -0,0 +1,35 @@
+// Mock API object
+
+const testApiMethod = {
+  method: 'template',
+  params: [
+    {
+      type: 'string',
+      name: 'name',
+      value: 'John Doe',
+      availableValues: ['John Doe', 'Jane Doe'],
+      optional: true,
+    },
+    { type: 'number', name: 'age', value: 30 },
+    { type: 'boolean', name: 'isStudent', value: false },
+    {
+      type: 'array',
+      name: 'hobbies',
+      value: ['reading', 'coding', 'hiking'],
+    },
+    {
+      type: 'object',
+      name: 'address',
+      value: {
+        city: { type: 'string', value: 'Metropolis' },
+        street: { type: 'string', value: 'Main Street' },
+        zip: { type: 'number', value: 54321 },
+      },
+    },
+    { type: 'null', name: 'middleName', value: null },
+    { type: 'string', name: 'dateOfBirth', value: '1992-05-14' },
+    { type: 'file', name: 'profilePicture', value: 'base64_encoded_string' },
+  ],
+}
+
+export default testApiMethod

+ 23 - 0
src/lib/api/renderRequestBody.js

@@ -0,0 +1,23 @@
+const renderRequestBody = (params) => {
+  const renderParam = (param) => {
+    switch (param.type) {
+      case 'object':
+        return Object.entries(param.value).reduce((acc, [key, value]) => {
+          acc[key] = renderParam(value)
+          return acc
+        }, {})
+      case 'array':
+        return param.value.map((item) => renderParam(item))
+      default:
+        // Return the value for primitive types
+        return param.value
+    }
+  }
+
+  return params.reduce((acc, param) => {
+    acc[param.name] = renderParam(param)
+    return acc
+  }, {})
+}
+
+export default renderRequestBody

+ 35 - 0
src/lib/api/template.js

@@ -0,0 +1,35 @@
+// Mock API object
+
+const templateApiMethod = {
+  method: 'templateApiMethod',
+  params: [
+    {
+      type: 'string',
+      name: 'name',
+      value: 'John Doe',
+      availableValues: ['John Doe', 'Jane Doe'],
+      optional: true,
+    },
+    { type: 'number', name: 'age', value: 30 },
+    { type: 'boolean', name: 'isStudent', value: false },
+    {
+      type: 'array',
+      name: 'hobbies',
+      value: ['reading', 'coding', 'hiking'],
+    },
+    {
+      type: 'object',
+      name: 'address',
+      value: {
+        city: { type: 'string', value: 'Metropolis' },
+        street: { type: 'string', value: 'Main Street' },
+        zip: { type: 'number', value: 54321 },
+      },
+    },
+    { type: 'null', name: 'middleName', value: null },
+    { type: 'string', name: 'dateOfBirth', value: '1992-05-14' },
+    { type: 'file', name: 'profilePicture', value: 'base64_encoded_string' },
+  ],
+}
+
+export default templateApiMethod

+ 8 - 0
src/pages/aura/api/v1/testApiMethod.md

@@ -0,0 +1,8 @@
+---
+title: Test Api Method
+metaTitle: Test Api Method | Aura Api
+description: Learn how Batch Minting works.
+---
+
+
+{% apiRenderer method="testApiMethod" %}