Yak Docs
Tool Adapters

REST/OpenAPI Adapter

Provide your OpenAPI specification to Yak, and the AI generates appropriate REST requests. You handle execution against your API.

How It Works

  1. You provide your OpenAPI spec
  2. Yak injects it as context to the LLM
  3. The AI generates requests based on user queries
  4. Your handler executes the requests and returns results

Setup

import { YakProvider, YakWidget } from "@yak-io/nextjs/client";

const openAPISpec = {
  openapi: "3.0.0",
  paths: {
    "/users": {
      get: {
        summary: "List users",
        parameters: [
          { name: "limit", in: "query", schema: { type: "integer" } }
        ],
      },
    },
    "/users/{id}": {
      get: {
        summary: "Get user by ID",
        parameters: [
          { name: "id", in: "path", required: true, schema: { type: "string" } }
        ],
      },
    },
    "/orders": {
      post: {
        summary: "Create order",
        requestBody: {
          content: {
            "application/json": {
              schema: { type: "object" }
            }
          },
        },
      },
    },
  },
};

export default function App() {
  return (
    <YakProvider
      appId="your-app-id"
      getConfig={async () => ({
        schemaSources: [
          {
            name: "ordersApi",
            type: "openapi",
            spec: openAPISpec,
          },
        ],
      })}
      onRESTSchemaCall={async (schemaName, request) => {
        // schemaName = "ordersApi"
        // request = { method: "GET", path: "/users", query: {...}, body: {...} }
        const url = new URL(request.path, "https://api.example.com");
        
        if (request.query) {
          for (const [key, value] of Object.entries(request.query)) {
            url.searchParams.set(key, String(value));
          }
        }

        const res = await fetch(url, {
          method: request.method,
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${token}`,
          },
          body: request.body ? JSON.stringify(request.body) : undefined,
        });

        return res.json();
      }}
    >
      <YakWidget />
    </YakProvider>
  );
}

Multiple APIs

Route calls to different base URLs by schema name:

<YakProvider
  getConfig={async () => ({
    schemaSources: [
      { name: "orders", type: "openapi", spec: ordersSpec },
      { name: "inventory", type: "openapi", spec: inventorySpec },
    ],
  })}
  onRESTSchemaCall={async (schemaName, request) => {
    const baseUrls = {
      orders: "https://orders.api.example.com",
      inventory: "https://inventory.api.example.com",
    };
    const baseUrl = baseUrls[schemaName];
    
    const url = new URL(request.path, baseUrl);
    // Execute request...
  }}
/>

Best Practices

Keep Specs Focused

Provide only the relevant endpoints:

// Instead of your entire 500-endpoint spec,
// extract just the relevant portions
const relevantSpec = {
  openapi: "3.0.0",
  paths: {
    "/orders": ordersPaths["/orders"],
    "/orders/{id}": ordersPaths["/orders/{id}"],
  },
};

Validate Operations

Don't allow destructive operations without safeguards:

onRESTSchemaCall: async (schemaName, request) => {
  // Don't allow DELETE operations
  if (request.method === "DELETE") {
    throw new Error("DELETE operations are not permitted");
  }
  // Continue with request...
}

Use Descriptive Schema Names

// Good - clear what each API is for
{ name: "orderManagement", type: "openapi", spec: ordersSpec }
{ name: "userDirectory", type: "openapi", spec: usersSpec }

// Avoid
{ name: "api1", type: "openapi", spec: spec }

Handle Authentication

Always add authentication:

onRESTSchemaCall: async (schemaName, request) => {
  const res = await fetch(url, {
    headers: {
      Authorization: `Bearer ${getAuthToken()}`,
    },
    // ...
  });
}

Be careful about which endpoints you expose. Avoid including destructive operations (DELETE, dangerous POSTs) without proper authorization.

On this page