Skip to main content
Glama
request-utils.ts5.12 kB
// We define our own PathOperation interface to avoid direct dependency on OAS implementation import type { z } from 'zod'; import type { PathOperation } from '../client.ts'; // Define interfaces for operating with the OAS library /** * Server variable interface for OpenAPI server variables */ export interface ServerVariable { default?: string; description?: string; enum?: string[]; } /** * Type for JSON values in parameters */ export type JsonValue = | string | number | boolean | null | undefined | JsonValue[] | { [key: string]: JsonValue }; /** * Type for JSON objects in parameters */ export type JsonObject = Record<string, JsonValue>; /** * Location where a parameter can be placed in an HTTP request */ export type BucketLocation = 'path' | 'query' | 'header' | 'cookie'; /** * Minimal interface for operations used by bucketArgs */ export interface BucketOperation { oas: { getParameters(): { name: string; in: 'path' | 'query' | 'header' | 'cookie' }[]; hasRequestBody(): boolean; getContentType(): string | null; }; } /** * Structured representation of request parameters by their location */ export interface BucketedArgs { body?: JsonValue; cookie?: Record<string, string>; formData?: FormData | URLSearchParams | null; // For form-urlencoded or multipart form data header?: Record<string, string>; path: Record<string, string>; query: Record<string, JsonValue>; server?: { selected: number; variables?: ServerVariable; }; } /** * Type for OpenAPI request arguments */ export type OasRequestArgs = z.objectOutputType<z.ZodRawShape, z.ZodTypeAny>; /** * Organizes operation arguments into their appropriate locations (path, query, header, etc.) * * @param operation - OpenAPI operation * @param args - Arguments to organize * @returns Organized arguments by location */ export function bucketArgs(operation: PathOperation, args: JsonObject): BucketedArgs { const values: BucketedArgs = { path: {}, query: {}, header: {}, cookie: {}, formData: null as FormData | URLSearchParams | null, // Directly include body from args if present body: args['body'], }; const consumed = new Set<string>(); for (const p of operation.getParameters()) { const val = args[p.name]; consumed.add(p.name); if (val === undefined) continue; (values[p.in as keyof BucketedArgs] as Record<string, unknown>)[p.name] = val; } const leftovers: JsonObject = {}; for (const [k, v] of Object.entries(args)) { if (consumed.has(k) || ['body', 'formData', 'auth', 'server'].includes(k)) continue; leftovers[k] = v; } if (!operation.hasRequestBody()) return values; const mime = operation.getContentType(); if (mime === 'application/x-www-form-urlencoded') { values.formData = createFormData(leftovers); } else { // JSON, XML, binary, multipart, custom, etc. if ( mime === 'application/json' && typeof values.body === 'object' && !Array.isArray(values.body) ) { // merge into existing JSON object values.body = { ...values.body, ...leftovers }; } else if (Object.keys(values.body ?? {}).length === 0) { values.body = Object.keys(leftovers).length ? leftovers : values.body; } } return values; } /** * Creates URLSearchParams from a record of key-value pairs * * @param input - Object containing parameter values * @param params - Optional existing URLSearchParams to add to * @returns URLSearchParams object with all parameters */ export function createSearchParams( input: Record<string, JsonValue>, params = new URLSearchParams(), ): URLSearchParams { for (const [key, value] of Object.entries(input)) { appendData(params, key, value); } return params; } /** * Creates form data from a record of key-value pairs * * @param input - Object containing form field values * @returns URLSearchParams object with form data */ export function createFormData(input: Record<string, JsonValue>): URLSearchParams { const params = new URLSearchParams(); for (const [key, value] of Object.entries(input)) { appendData(params, key, value); } return params; } /** * Appends data to form data or search params, handling nested objects and arrays * * @param formData - FormData or URLSearchParams to append to * @param key - Key for the parameter * @param input - Value to append */ export function appendData( formData: FormData | URLSearchParams, key: string, input: JsonValue, ): void { switch (typeof input) { case 'string': case 'number': case 'boolean': formData.append(key, String(input)); break; case 'object': if (input === null) { formData.append(key, ''); break; } if (Array.isArray(input)) { input.forEach((v) => { appendData(formData, key, v); }); } else { Object.entries(input).forEach(([k, v]) => { appendData(formData, `${key}[${k}]`, v); }); } break; default: formData.append(key, String(input)); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/wycats/mcpify'

If you have feedback or need assistance with the MCP directory API, please join our Discord server