HTTP API
Complete reference for lightshell.http — CORS-free HTTP requests.
The lightshell.http module makes HTTP requests through the Go backend, completely bypassing CORS restrictions. Unlike fetch() in the webview (which is subject to browser CORS policies), lightshell.http.fetch() can call any API endpoint without CORS headers. This is one of the most important advantages of a desktop app over a web app. All methods are async and return Promises.
Methods
Section titled “Methods”fetch(url, options?)
Section titled “fetch(url, options?)”Make an HTTP request to any URL. The request is executed by the Go backend using net/http, so CORS does not apply.
Parameters:
url(string) — the full URL to requestoptions(object, optional):method(string) — HTTP method:"GET","POST","PUT","PATCH","DELETE","HEAD"(default:"GET")headers(object) — key-value pairs of request headersbody(string) — request body (for POST, PUT, PATCH)timeout(number) — request timeout in milliseconds (default:30000)
Returns: Promise<{ status: number, headers: object, body: string }> — the response object:
status— HTTP status code (e.g.,200,404)headers— response headers as key-value pairsbody— response body as a string (parse withJSON.parse()for JSON APIs)
Example:
// Simple GET requestconst response = await lightshell.http.fetch('https://api.github.com/zen')console.log(response.body) // "Encourage flow."
// GET with headersconst data = await lightshell.http.fetch('https://api.github.com/user', { headers: { 'Authorization': 'Bearer ghp_xxxxx', 'Accept': 'application/json' }})const user = JSON.parse(data.body)console.log(user.login)
// POST with JSON bodyconst result = await lightshell.http.fetch('https://api.example.com/items', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'New Item', priority: 'high' })})console.log(result.status) // 201Errors: Rejects on network errors (DNS failure, connection refused, timeout). HTTP error status codes (4xx, 5xx) do NOT cause a rejection — check response.status instead.
download(url, options?)
Section titled “download(url, options?)”Download a file directly to disk. Unlike fetch(), this does not load the entire response into memory, making it suitable for large files.
Parameters:
url(string) — the URL of the file to downloadoptions(object, optional):saveTo(string) — destination file path. Supports path variables like$DOWNLOADS,$TEMP,$DESKTOP.headers(object) — request headers (e.g., for authentication)onProgress(function) — callback fired during download with progress info
Returns: Promise<{ path: string, size: number }> — the saved file path and size in bytes
Example:
const result = await lightshell.http.download( 'https://example.com/report.pdf', { saveTo: '$DOWNLOADS/report.pdf', onProgress: (p) => { console.log(`${p.percent}% (${p.bytesDownloaded}/${p.totalBytes})`) } })console.log(`Saved to ${result.path} (${result.size} bytes)`)Errors: Rejects on network errors or if the destination path is not writable.
Common Patterns
Section titled “Common Patterns”Calling REST APIs
Section titled “Calling REST APIs”async function fetchTodos() { const response = await lightshell.http.fetch('https://api.myapp.com/todos', { headers: { 'Authorization': `Bearer ${apiToken}`, 'Accept': 'application/json' } })
if (response.status !== 200) { throw new Error(`API error: ${response.status}`) }
return JSON.parse(response.body)}
async function createTodo(title) { const response = await lightshell.http.fetch('https://api.myapp.com/todos', { method: 'POST', headers: { 'Authorization': `Bearer ${apiToken}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ title, completed: false }) })
if (response.status !== 201) { throw new Error(`Failed to create todo: ${response.status}`) }
return JSON.parse(response.body)}API Key Authentication
Section titled “API Key Authentication”// Create a reusable API clientfunction createApiClient(baseUrl, apiKey) { async function request(path, options = {}) { const response = await lightshell.http.fetch(`${baseUrl}${path}`, { ...options, headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json', ...options.headers } }) return { status: response.status, data: JSON.parse(response.body) } }
return { get: (path) => request(path), post: (path, body) => request(path, { method: 'POST', body: JSON.stringify(body) }), put: (path, body) => request(path, { method: 'PUT', body: JSON.stringify(body) }), delete: (path) => request(path, { method: 'DELETE' }) }}
// Usageconst api = createApiClient('https://api.example.com', 'sk_live_xxxxx')const { data } = await api.get('/users/me')await api.post('/messages', { text: 'Hello!' })Download with Progress UI
Section titled “Download with Progress UI”async function downloadFile(url, filename) { const progressBar = document.getElementById('progress') const statusText = document.getElementById('status')
statusText.textContent = 'Downloading...' progressBar.style.width = '0%'
try { const result = await lightshell.http.download(url, { saveTo: `$DOWNLOADS/${filename}`, onProgress: (p) => { progressBar.style.width = `${p.percent}%` statusText.textContent = `${p.percent}% — ${formatBytes(p.bytesDownloaded)} / ${formatBytes(p.totalBytes)}` } })
statusText.textContent = `Downloaded to ${result.path}` await lightshell.notify.send('Download Complete', `${filename} saved to Downloads.`) } catch (err) { statusText.textContent = `Download failed: ${err.message}` }}
function formatBytes(bytes) { if (bytes < 1024) return `${bytes} B` if (bytes < 1048576) return `${(bytes / 1024).toFixed(1)} KB` return `${(bytes / 1048576).toFixed(1)} MB`}Platform Notes
Section titled “Platform Notes”- Requests are made by the Go backend using
net/http, not by the webview. This means CORS headers are not required on the target server. - The response
bodyis always a string. For JSON responses, parse withJSON.parse(). For binary responses, the body is base64-encoded. - There is no streaming support in v1 — the entire response is buffered in memory for
fetch(). Usedownload()for large files. download()writes directly to disk and does not load the file into memory.- Path variables in
saveTo:$DOWNLOADSresolves to~/Downloads,$TEMPto/tmp,$DESKTOPto~/Desktop. - In restricted permission mode, URLs must match patterns defined in
permissions.http.allowinlightshell.json. Without apermissionskey, all URLs are allowed. - HTTPS is enforced for production builds in the updater, but
lightshell.http.fetch()allows both HTTP and HTTPS in all modes. - WebSocket support is not available in v1. Use polling or
lightshell.http.fetch()for real-time data.