Announcing Convex 0.9.0

HTTP endpoints are here! Convex 0.9.0 extends the platform by allowing you to build your HTTP API right within Convex.

The full list of changes in 0.9.0 is:

  • HTTP Endpoints
  • File Storage in the Dashboard
  • Breaking: API Changes in Actions
  • Breaking: runAt Now Uses Milliseconds

Details below.

HTTP Endpoints

You can now define HTTP endpoints right within Convex!

This enables you to build a HTTP API that interacts with all of your Convex data. This is useful for building a public API or receiving webhooks from external applications.

HTTP endpoints are defined with httpEndpoint. Endpoints receive the Request object; can call Convex functions with runQuery, runMutation, and runAction; and return a Response object.

To expose the endpoints, use httpRouter in convex/http.js or convex/http.ts. The endpoints will be available at https://<your deployment name>.convex.site. The convex.site domain signifies that these are your routes running under Convex, as opposed to convex.cloud which serves the Convex API.

Here’s an example of a router with a single endpoint:

import { httpRouter } from "convex/server";
import { httpEndpoint } from "./_generated/server";

const postMessage = httpEndpoint(async ({ runMutation }, request) => {
  const { author, body } = await request.json();

  await runMutation("sendMessage", `Sent via HTTP endpoint: ${body}`, author);
  return new Response(null, {
    status: 200,
  });
});

const http = httpRouter();

http.route({
  path: "/postMessage",
  method: "POST",
  handler: postMessage,
});

export default http;
convex/http.js

You can call this endpoint with:

export DEPLOYMENT_NAME=... # example: "tall-sheep-123"
curl -d '{ "author": "User 123", "body": "Hello world" }' \\
    -H 'content-type: application/json' "https://$DEPLOYMENT_NAME.convex.site/postMessage"

To learn more, read the docs!

File Storage in the Dashboard

We’ve added a new page to the dashboard for managing file storage. Now you can upload, view, and delete files from the dashboard. Check it out!

Breaking: API Changes in Actions

We’ve renamed two functions used in Convex actions:

  1. ActionCtx.mutationActionCtx.runMutation
  2. ActionCtx.queryActionCtx.runQuery

Now, actions should be defined like:

export default action(async ({ runMutation, runQuery }) => {
  // Action logic. Call `runMutation` and `runQuery` in here!
});

This change makes actions consistent with how HTTP endpoints call queries and mutations. It also differentiates calling a query or mutation (runQuery or runMutation) from defining a query or mutation (query or mutation).

Breaking: runAt Now Uses Milliseconds

We’ve changed the API for scheduling functions to run at a timestamp. Now scheduler.runAt accepts a timestamp in milliseconds since the epoch instead of seconds since the epoch. This is more consistent with runAfter which accepts delay in milliseconds and timestamps in Convex in general.