corrad-af-2024/components/api-platform/CodeGenerationModal.vue

634 lines
19 KiB
Vue

<template>
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50 p-4">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-xl w-full max-w-6xl h-full max-h-[95vh] flex flex-col">
<!-- Header -->
<div class="flex items-center justify-between p-6 border-b border-gray-200 dark:border-gray-700 flex-shrink-0">
<div class="flex items-center gap-3">
<Icon name="ic:outline-code" size="24" class="text-primary-600" />
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Code Generation</h3>
</div>
<rs-button
variant="text"
size="sm"
@click="$emit('close')"
class="p-2"
>
<Icon name="ic:outline-close" size="16" />
</rs-button>
</div>
<!-- Content -->
<div class="flex flex-1 overflow-hidden min-h-0">
<!-- Language/Framework Selector -->
<div class="w-64 border-r border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900 flex-shrink-0 flex flex-col">
<div class="p-4 border-b border-gray-200 dark:border-gray-700">
<h4 class="font-medium text-gray-900 dark:text-white">Select Language</h4>
</div>
<div class="flex-1 overflow-y-auto p-4 space-y-1">
<button
v-for="lang in languages"
:key="lang.id"
@click="selectedLanguage = lang.id"
:class="[
'w-full text-left p-3 rounded-lg transition-colors flex items-center gap-3',
selectedLanguage === lang.id
? 'bg-primary-100 text-primary-900 dark:bg-primary-900 dark:text-primary-100'
: 'hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-300'
]"
>
<Icon :name="lang.icon" size="20" />
<div class="min-w-0">
<div class="font-medium truncate">{{ lang.name }}</div>
<div class="text-xs opacity-70 truncate">{{ lang.description }}</div>
</div>
</button>
</div>
</div>
<!-- Code Display -->
<div class="flex-1 flex flex-col min-w-0">
<!-- Code Header -->
<div class="p-4 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900 flex-shrink-0">
<div class="flex items-center justify-between">
<div class="flex items-center gap-2 min-w-0">
<Icon :name="currentLanguage.icon" size="16" />
<span class="font-medium text-gray-900 dark:text-white truncate">{{ currentLanguage.name }}</span>
<rs-badge variant="secondary" size="sm">{{ generatedCode.split('\n').length }} lines</rs-badge>
</div>
<div class="flex items-center gap-2 flex-shrink-0">
<rs-button
variant="secondary-outline"
size="sm"
@click="copyToClipboard"
class="flex items-center gap-2"
>
<Icon name="ic:outline-content-copy" size="16" />
Copy
</rs-button>
<rs-button
variant="secondary-outline"
size="sm"
@click="downloadCode"
class="flex items-center gap-2"
>
<Icon name="ic:outline-download" size="16" />
Download
</rs-button>
</div>
</div>
</div>
<!-- Code Content -->
<div class="flex-1 overflow-hidden p-4 min-h-0">
<pre
class="text-sm bg-gray-50 dark:bg-gray-900 p-4 rounded-lg whitespace-pre-wrap border font-mono leading-relaxed w-full h-full overflow-auto resize-none"
:class="`language-${currentLanguage.highlightLanguage}`"
>{{ generatedCode }}</pre>
</div>
</div>
</div>
<!-- Footer -->
<div class="flex items-center justify-between p-6 border-t border-gray-200 dark:border-gray-700 flex-shrink-0">
<div class="text-sm text-gray-500 dark:text-gray-400">
Generated from current request configuration
</div>
<rs-button
variant="primary"
@click="$emit('close')"
>
Done
</rs-button>
</div>
</div>
</div>
</template>
<script setup>
const emit = defineEmits(['close'])
const {
httpMethod,
requestUrl,
requestParams,
requestHeaders,
requestAuth,
requestBody,
showNotification
} = useApiPlatform()
const { copyToClipboard: copyToClipboardUtil } = useApiRequest()
const selectedLanguage = ref('curl')
const languages = [
{
id: 'curl',
name: 'cURL',
description: 'Command line tool',
icon: 'ic:outline-terminal',
highlightLanguage: 'bash'
},
{
id: 'javascript-fetch',
name: 'JavaScript (Fetch)',
description: 'Modern JavaScript',
icon: 'ic:outline-javascript',
highlightLanguage: 'javascript'
},
{
id: 'javascript-axios',
name: 'JavaScript (Axios)',
description: 'Popular HTTP client',
icon: 'ic:outline-javascript',
highlightLanguage: 'javascript'
},
{
id: 'python-requests',
name: 'Python (Requests)',
description: 'Python HTTP library',
icon: 'ic:outline-data-object',
highlightLanguage: 'python'
},
{
id: 'php-curl',
name: 'PHP (cURL)',
description: 'PHP with cURL',
icon: 'ic:outline-language',
highlightLanguage: 'php'
},
{
id: 'node-http',
name: 'Node.js (HTTP)',
description: 'Native Node.js',
icon: 'ic:outline-settings',
highlightLanguage: 'javascript'
},
{
id: 'java-okhttp',
name: 'Java (OkHttp)',
description: 'Java HTTP client',
icon: 'ic:outline-coffee',
highlightLanguage: 'java'
},
{
id: 'go-http',
name: 'Go (net/http)',
description: 'Go standard library',
icon: 'ic:outline-speed',
highlightLanguage: 'go'
}
]
const currentLanguage = computed(() => {
return languages.find(lang => lang.id === selectedLanguage.value) || languages[0]
})
// Generate code based on current request
const generatedCode = computed(() => {
const url = requestUrl.value || 'https://api.example.com/endpoint'
const method = httpMethod.value
const headers = requestHeaders.value.filter(h => h.active && h.key)
const params = requestParams.value.filter(p => p.active && p.key)
const body = requestBody.value
const auth = requestAuth.value
switch (selectedLanguage.value) {
case 'curl':
return generateCurl(url, method, headers, params, body, auth)
case 'javascript-fetch':
return generateJavaScriptFetch(url, method, headers, params, body, auth)
case 'javascript-axios':
return generateJavaScriptAxios(url, method, headers, params, body, auth)
case 'python-requests':
return generatePythonRequests(url, method, headers, params, body, auth)
case 'php-curl':
return generatePhpCurl(url, method, headers, params, body, auth)
case 'node-http':
return generateNodeHttp(url, method, headers, params, body, auth)
case 'java-okhttp':
return generateJavaOkHttp(url, method, headers, params, body, auth)
case 'go-http':
return generateGoHttp(url, method, headers, params, body, auth)
default:
return '// Code generation not available for this language'
}
})
// Code generation functions
const generateCurl = (url, method, headers, params, body, auth) => {
let code = `curl -X ${method}`
// Add URL with params
if (params.length > 0) {
const queryString = params.map(p => `${encodeURIComponent(p.key)}=${encodeURIComponent(p.value)}`).join('&')
url += `?${queryString}`
}
code += ` \\\n "${url}"`
// Add headers
headers.forEach(header => {
code += ` \\\n -H "${header.key}: ${header.value}"`
})
// Add auth
if (auth.type === 'bearer' && auth.bearer) {
code += ` \\\n -H "Authorization: Bearer ${auth.bearer}"`
} else if (auth.type === 'basic' && auth.basic.username) {
code += ` \\\n -u "${auth.basic.username}:${auth.basic.password}"`
} else if (auth.type === 'apiKey' && auth.apiKey.key) {
if (auth.apiKey.addTo === 'header') {
code += ` \\\n -H "${auth.apiKey.key}: ${auth.apiKey.value}"`
}
}
// Add body
if (body.type === 'raw' && body.raw) {
code += ` \\\n -H "Content-Type: application/json"`
code += ` \\\n -d '${body.raw}'`
} else if (body.type === 'x-www-form-urlencoded' && body.urlEncoded.some(item => item.active && item.key)) {
const formData = body.urlEncoded.filter(item => item.active && item.key)
.map(item => `${encodeURIComponent(item.key)}=${encodeURIComponent(item.value)}`)
.join('&')
code += ` \\\n -H "Content-Type: application/x-www-form-urlencoded"`
code += ` \\\n -d "${formData}"`
}
return code
}
const generateJavaScriptFetch = (url, method, headers, params, body, auth) => {
let code = '// Using fetch API\n'
// Build URL with params
if (params.length > 0) {
const queryString = params.map(p => `${encodeURIComponent(p.key)}=${encodeURIComponent(p.value)}`).join('&')
url += `?${queryString}`
}
code += `const url = '${url}';\n\n`
// Build options object
code += 'const options = {\n'
code += ` method: '${method}',\n`
// Headers
const allHeaders = [...headers]
if (auth.type === 'bearer' && auth.bearer) {
allHeaders.push({ key: 'Authorization', value: `Bearer ${auth.bearer}` })
} else if (auth.type === 'apiKey' && auth.apiKey.key && auth.apiKey.addTo === 'header') {
allHeaders.push({ key: auth.apiKey.key, value: auth.apiKey.value })
}
if (allHeaders.length > 0) {
code += ' headers: {\n'
allHeaders.forEach(header => {
code += ` '${header.key}': '${header.value}',\n`
})
code += ' },\n'
}
// Body
if (body.type === 'raw' && body.raw) {
code += ` body: ${body.raw}\n`
} else if (body.type === 'x-www-form-urlencoded' && body.urlEncoded.some(item => item.active && item.key)) {
const formData = body.urlEncoded.filter(item => item.active && item.key)
.map(item => `${encodeURIComponent(item.key)}=${encodeURIComponent(item.value)}`)
.join('&')
code += ` body: '${formData}'\n`
}
code += '};\n\n'
code += `fetch(url, options)\n`
code += ` .then(response => response.json())\n`
code += ` .then(data => console.log(data))\n`
code += ` .catch(error => console.error('Error:', error));`
return code
}
const generateJavaScriptAxios = (url, method, headers, params, body, auth) => {
let code = '// Using Axios\n'
code += "import axios from 'axios';\n\n"
code += 'const config = {\n'
code += ` method: '${method.toLowerCase()}',\n`
code += ` url: '${url}',\n`
// Params
if (params.length > 0) {
code += ' params: {\n'
params.forEach(param => {
code += ` '${param.key}': '${param.value}',\n`
})
code += ' },\n'
}
// Headers
const allHeaders = [...headers]
if (auth.type === 'bearer' && auth.bearer) {
allHeaders.push({ key: 'Authorization', value: `Bearer ${auth.bearer}` })
} else if (auth.type === 'apiKey' && auth.apiKey.key && auth.apiKey.addTo === 'header') {
allHeaders.push({ key: auth.apiKey.key, value: auth.apiKey.value })
}
if (allHeaders.length > 0) {
code += ' headers: {\n'
allHeaders.forEach(header => {
code += ` '${header.key}': '${header.value}',\n`
})
code += ' },\n'
}
// Body
if (body.type === 'raw' && body.raw) {
code += ` data: ${body.raw}\n`
}
code += '};\n\n'
code += 'axios(config)\n'
code += ' .then(response => console.log(response.data))\n'
code += ' .catch(error => console.error(error));'
return code
}
const generatePythonRequests = (url, method, headers, params, body, auth) => {
let code = '# Using requests library\n'
code += 'import requests\n\n'
code += `url = "${url}"\n\n`
// Headers
const allHeaders = [...headers]
if (auth.type === 'bearer' && auth.bearer) {
allHeaders.push({ key: 'Authorization', value: `Bearer ${auth.bearer}` })
} else if (auth.type === 'apiKey' && auth.apiKey.key && auth.apiKey.addTo === 'header') {
allHeaders.push({ key: auth.apiKey.key, value: auth.apiKey.value })
}
if (allHeaders.length > 0) {
code += 'headers = {\n'
allHeaders.forEach(header => {
code += ` "${header.key}": "${header.value}",\n`
})
code += '}\n\n'
}
// Params
if (params.length > 0) {
code += 'params = {\n'
params.forEach(param => {
code += ` "${param.key}": "${param.value}",\n`
})
code += '}\n\n'
}
// Body
if (body.type === 'raw' && body.raw) {
code += `data = ${body.raw}\n\n`
}
// Request
code += `response = requests.${method.toLowerCase()}(url`
if (allHeaders.length > 0) code += ', headers=headers'
if (params.length > 0) code += ', params=params'
if (body.type === 'raw' && body.raw) code += ', json=data'
code += ')\n\n'
code += 'print(response.json())'
return code
}
const generatePhpCurl = (url, method, headers, params, body, auth) => {
let code = '<?php\n'
code += '// Using cURL\n\n'
// Build URL with params
if (params.length > 0) {
const queryString = params.map(p => `${p.key}=${p.value}`).join('&')
url += `?${queryString}`
}
code += `$url = "${url}";\n\n`
code += '$curl = curl_init();\n\n'
code += 'curl_setopt_array($curl, [\n'
code += ' CURLOPT_URL => $url,\n'
code += ' CURLOPT_RETURNTRANSFER => true,\n'
code += ` CURLOPT_CUSTOMREQUEST => "${method}",\n`
// Headers
const allHeaders = [...headers]
if (auth.type === 'bearer' && auth.bearer) {
allHeaders.push({ key: 'Authorization', value: `Bearer ${auth.bearer}` })
}
if (allHeaders.length > 0) {
code += ' CURLOPT_HTTPHEADER => [\n'
allHeaders.forEach(header => {
code += ` "${header.key}: ${header.value}",\n`
})
code += ' ],\n'
}
// Body
if (body.type === 'raw' && body.raw) {
code += ` CURLOPT_POSTFIELDS => '${body.raw}',\n`
}
code += ']);\n\n'
code += '$response = curl_exec($curl);\n'
code += 'curl_close($curl);\n\n'
code += 'echo $response;'
return code
}
const generateNodeHttp = (url, method, headers, params, body, auth) => {
let code = '// Using Node.js http module\n'
code += "const http = require('http');\n"
code += "const https = require('https');\n"
code += "const { URL } = require('url');\n\n"
code += `const url = new URL('${url}');\n\n`
// Add params
if (params.length > 0) {
params.forEach(param => {
code += `url.searchParams.append('${param.key}', '${param.value}');\n`
})
code += '\n'
}
code += 'const options = {\n'
code += ' hostname: url.hostname,\n'
code += ' port: url.port,\n'
code += ' path: url.pathname + url.search,\n'
code += ` method: '${method}',\n`
// Headers
const allHeaders = [...headers]
if (auth.type === 'bearer' && auth.bearer) {
allHeaders.push({ key: 'Authorization', value: `Bearer ${auth.bearer}` })
}
if (allHeaders.length > 0) {
code += ' headers: {\n'
allHeaders.forEach(header => {
code += ` '${header.key}': '${header.value}',\n`
})
code += ' }\n'
}
code += '};\n\n'
code += 'const req = (url.protocol === "https:" ? https : http).request(options, (res) => {\n'
code += ' let data = "";\n'
code += ' res.on("data", (chunk) => { data += chunk; });\n'
code += ' res.on("end", () => { console.log(JSON.parse(data)); });\n'
code += '});\n\n'
if (body.type === 'raw' && body.raw) {
code += `req.write(${body.raw});\n`
}
code += 'req.end();'
return code
}
const generateJavaOkHttp = (url, method, headers, params, body, auth) => {
let code = '// Using OkHttp\n'
code += 'import okhttp3.*;\n\n'
code += 'OkHttpClient client = new OkHttpClient();\n\n'
// Build URL with params
if (params.length > 0) {
const queryString = params.map(p => `${p.key}=${p.value}`).join('&')
url += `?${queryString}`
}
// Request builder
code += 'Request.Builder builder = new Request.Builder()\n'
code += ` .url("${url}")\n`
// Headers
const allHeaders = [...headers]
if (auth.type === 'bearer' && auth.bearer) {
allHeaders.push({ key: 'Authorization', value: `Bearer ${auth.bearer}` })
}
allHeaders.forEach(header => {
code += ` .addHeader("${header.key}", "${header.value}")\n`
})
// Body and method
if (body.type === 'raw' && body.raw) {
code += ` .${method.toLowerCase()}(RequestBody.create(MediaType.parse("application/json"), ${body.raw}));\n\n`
} else {
code += ` .${method.toLowerCase()}();\n\n`
}
code += 'Request request = builder.build();\n\n'
code += 'try {\n'
code += ' Response response = client.newCall(request).execute();\n'
code += ' System.out.println(response.body().string());\n'
code += '} catch (IOException e) {\n'
code += ' e.printStackTrace();\n'
code += '}'
return code
}
const generateGoHttp = (url, method, headers, params, body, auth) => {
let code = '// Using Go net/http\n'
code += 'package main\n\n'
code += 'import (\n'
code += ' "fmt"\n'
code += ' "net/http"\n'
code += ' "io/ioutil"\n'
if (body.type === 'raw' && body.raw) {
code += ' "strings"\n'
}
code += ')\n\n'
code += 'func main() {\n'
// Build URL with params
if (params.length > 0) {
const queryString = params.map(p => `${p.key}=${p.value}`).join('&')
url += `?${queryString}`
}
code += ` url := "${url}"\n\n`
// Create request
if (body.type === 'raw' && body.raw) {
code += ` payload := strings.NewReader(${JSON.stringify(body.raw)})\n`
code += ' req, _ := http.NewRequest("${method}", url, payload)\n\n'
} else {
code += ` req, _ := http.NewRequest("${method}", url, nil)\n\n`
}
// Headers
const allHeaders = [...headers]
if (auth.type === 'bearer' && auth.bearer) {
allHeaders.push({ key: 'Authorization', value: `Bearer ${auth.bearer}` })
}
allHeaders.forEach(header => {
code += ` req.Header.Add("${header.key}", "${header.value}")\n`
})
code += '\n res, _ := http.DefaultClient.Do(req)\n'
code += ' defer res.Body.Close()\n'
code += ' body, _ := ioutil.ReadAll(res.Body)\n\n'
code += ' fmt.Println(string(body))\n'
code += '}'
return code
}
const copyToClipboard = async () => {
await copyToClipboardUtil(generatedCode.value, 'Code copied to clipboard', { showNotification })
}
const downloadCode = () => {
const extension = getFileExtension(selectedLanguage.value)
const filename = `api-request.${extension}`
const blob = new Blob([generatedCode.value], { type: 'text/plain' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = filename
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
URL.revokeObjectURL(url)
showNotification(`Code downloaded as ${filename}`, 'success')
}
const getFileExtension = (languageId) => {
const extensions = {
'curl': 'sh',
'javascript-fetch': 'js',
'javascript-axios': 'js',
'python-requests': 'py',
'php-curl': 'php',
'node-http': 'js',
'java-okhttp': 'java',
'go-http': 'go'
}
return extensions[languageId] || 'txt'
}
</script>