DEV Community

Alex Spinov
Alex Spinov

Posted on

Val Town Has a Free API That Runs JavaScript Functions in the Cloud Instantly

Val Town is a social website for writing and deploying JavaScript. Write a function, get an API endpoint — instantly, with zero deployment.

Vals: Cloud Functions

// A val = a function that runs in the cloud
export function hello(name: string) {
  return `Hello, ${name}!`;
}
// Instantly available at: https://username-hello.web.val.run?name=World
Enter fullscreen mode Exit fullscreen mode

HTTP Val: Instant API

export default async function(req: Request): Promise<Response> {
  const url = new URL(req.url);
  const category = url.searchParams.get("category");

  if (req.method === "GET") {
    const products = await getProducts(category);
    return Response.json(products);
  }

  if (req.method === "POST") {
    const body = await req.json();
    const product = await createProduct(body);
    return Response.json(product, { status: 201 });
  }

  return new Response("Method not allowed", { status: 405 });
}
Enter fullscreen mode Exit fullscreen mode

Deploy = save. That's it. Your function is live.

Cron Val: Scheduled Jobs

import { email } from "https://esm.town/v/std/email";

// Runs on a schedule (configure in UI)
export default async function dailyPriceCheck() {
  const prices = await fetchPrices();
  const drops = prices.filter(p => p.currentPrice < p.previousPrice);

  if (drops.length > 0) {
    await email({
      subject: `${drops.length} price drops detected!`,
      text: drops.map(d => `${d.title}: $${d.previousPrice} → $${d.currentPrice}`).join("\n"),
    });
  }

  return { checked: prices.length, drops: drops.length };
}
Enter fullscreen mode Exit fullscreen mode

SQLite: Built-In Database

import { sqlite } from "https://esm.town/v/std/sqlite";

// Create table
await sqlite.execute(`CREATE TABLE IF NOT EXISTS products (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  title TEXT NOT NULL,
  price REAL NOT NULL,
  url TEXT UNIQUE,
  scraped_at DATETIME DEFAULT CURRENT_TIMESTAMP
)`);

// Insert
await sqlite.execute(
  "INSERT INTO products (title, price, url) VALUES (?, ?, ?)",
  ["Widget", 29.99, "https://example.com/widget"]
);

// Query
const { rows } = await sqlite.execute(
  "SELECT * FROM products WHERE price < ? ORDER BY scraped_at DESC",
  [50]
);
Enter fullscreen mode Exit fullscreen mode

Blob Storage

import { blob } from "https://esm.town/v/std/blob";

// Store data
await blob.setJSON("latest-scrape", { products, scrapedAt: new Date() });

// Retrieve
const data = await blob.getJSON("latest-scrape");

// Store files
await blob.set("export.csv", csvContent);
Enter fullscreen mode Exit fullscreen mode

Email Built-In

import { email } from "https://esm.town/v/std/email";

await email({
  to: "user@example.com",
  subject: "Your scraping report",
  html: "<h1>Report</h1><p>1,234 products scraped.</p>",
});
Enter fullscreen mode Exit fullscreen mode

Import Any npm Package

import Anthropic from "npm:@anthropic-ai/sdk";
import { parse } from "npm:node-html-parser";

const client = new Anthropic();
const html = await fetch("https://example.com").then(r => r.text());
const doc = parse(html);
Enter fullscreen mode Exit fullscreen mode

Quick scraping prototypes? My Apify tools for production, Val Town for experiments.

Custom cloud functions? Email spinov001@gmail.com

Top comments (0)