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
- You provide your OpenAPI spec
- Yak injects it as context to the LLM
- The AI generates requests based on user queries
- 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.