OpenAPI & Other Languages
Convex doesn’t have explicit support for many languages including Go, Java, and C++. However, you can generate OpenAPI specifications from your Convex deployment to create type-safe clients for languages that aren't currently supported. Under the hood, this uses our HTTP API. This means that your queries will not be reactive/real-time.
OAS generation is currently a beta feature. If you have feedback or feature requests, let us know on Discord!
Setup
- Install the Convex Helpers npm package
Install the
convex-helpers
package, which contains a CLI command to generate an Open API specification.npm install convex-helpers
- Run a command to generate an OpenAPI specification
Running this command will call into your configured Convex deployment and generate an
convex-spec.yaml
file based on it. You can see additional flags by passing--help
to the command.npx convex-helpers open-api-spec
- Generate a type-safe client
You can use a separate tools to generate a client from the
convex-spec.yaml
file. Some popular options are OpenAPI Tools and Swagger.# convex-spec.yaml
openapi: 3.0.3
info:
title: Convex App - OpenAPI 3.0
version: 0.0.0
servers:
- url: "{hostUrl}"
description: Convex App API
...
Example
Below are code snippets of what this workflow looks like in action. These snippets include two different files:
convex/load.ts
- contains Convex function definitionsconvex.go
- containsGo
code that uses a generated, type-safeHTTP
client. This client was generated by installing the OpenAPI Tools package and running the commandnpx openapi-generator-cli generate -i convex-spec.yaml -g go -o convex_client
import { v } from "convex/values";
import { query } from "./_generated/server";
import { LinkTable } from "./schema";
export const loadOne = query({
args: { normalizedId: v.string(), token: v.string() },
returns: v.union(
v.object({
...LinkTable.validator.fields,
_creationTime: v.number(),
_id: v.id("links"),
}),
v.null(),
),
handler: async (ctx, { normalizedId, token }) => {
if (token === "" || token !== process.env.CONVEX_AUTH_TOKEN) {
throw new Error("Invalid authorization token");
}
return await ctx.db
.query("links")
.withIndex("by_normalizedId", (q) => q.eq("normalizedId", normalizedId))
.first();
},
});
type Link struct {
Short string // the "foo" part of http://go/foo
Long string // the target URL or text/template pattern to run
Created time.Time
LastEdit time.Time // when the link was last edited
Owner string // user@domain
}
func (c *ConvexDB) Load(short string) (*Link, error) {
request := *convex.NewRequestLoadLoadOne(*convex.NewRequestLoadLoadOneArgs(short, c.token))
resp, httpRes, err := c.client.QueryAPI.ApiRunLoadLoadOnePost(context.Background()).RequestLoadLoadOne(request).Execute()
validationErr := validateResponse(httpRes.StatusCode, err, resp.Status) if
validationErr != nil { return nil, validationErr }
linkDoc := resp.Value.Get()
if linkDoc == nil {
err := fs.ErrNotExist
return nil, err
}
link := Link{
Short: linkDoc.Short,
Long: linkDoc.Long,
Created: time.Unix(int64(linkDoc.Created), 0),
LastEdit: time.Unix(int64(linkDoc.LastEdit), 0),
Owner: linkDoc.Owner,
}
return &link, nil
Limits
- Argument and return value validators are not required, but they will enrich
the types of your OpenAPI spec. Where validators aren't defined, we default to
v.any()
as the validator. - You cannot call internal functions from outside of your Convex deployment.
- We currently do not support
bigints
orbytes
.