apiai

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 3, 2025 License: MIT Imports: 10 Imported by: 0

README

openapi-openai-go

A Go library that converts OpenAPI 3.0 specifications to OpenAI function calling schemas and executes them with the official OpenAI Go SDK. This library enables seamless integration between REST APIs described in OpenAPI format and OpenAI's function calling capabilities.

Features

  • OpenAPI 3.0 Support: Parse OpenAPI 3.0 specifications from JSON or YAML files/URLs
  • Function Schema Generation: Convert OpenAPI operations to OpenAI function definitions automatically
  • Schema Transformation: Automatic conversion of complex data types, enums, and validation rules
  • Multiple Authentication Methods: Support for Basic, Bearer, API Key, OAuth2, and Cookie authentication
  • HTTP Client Integration: Execute function calls using configurable HTTP clients with authentication
  • OpenAI SDK Integration: Seamless integration with OpenAI's function calling tools API
  • Reference Resolution: Handle $ref parameters in OpenAPI components
  • Auto-format Detection: Automatically detect and parse JSON or YAML OpenAPI specs
  • Comprehensive Examples: Complete examples demonstrating various use cases

Installation

go get github.com/covrom/openapi-openai-go

Quick Start

Basic Usage
package main

import (
    "encoding/json"
    "log"
    
    apiai "github.com/covrom/openapi-openai-go"
)

func main() {
    // Example OpenAPI spec
    specJSON := `{
        "openapi": "3.0.0",
        "info": {
            "title": "Pet Store API",
            "version": "1.0.0"
        },
        "paths": {
            "/pets": {
                "get": {
                    "summary": "List all pets",
                    "parameters": [
                        {
                            "name": "limit",
                            "in": "query",
                            "description": "Maximum number of pets to return",
                            "required": false,
                            "schema": {
                                "type": "integer",
                                "format": "int32"
                            }
                        }
                    ]
                }
            }
        }
    }`

    var spec apiai.OpenAPISpec
    if err := json.Unmarshal([]byte(specJSON), &spec); err != nil {
        log.Fatal(err)
    }

    // Convert to OpenAI functions
    functions := apiai.ConvertOpenAPIToFunctions(&spec)

    // Create API client
    client, err := apiai.NewAPIClient("https://petstore.swagger.io/v2", nil)
    if err != nil {
        log.Fatal(err)
    }

    // Execute function
    result, err := apiai.ExecuteFunction(client, functions["get_pets"], map[string]interface{}{"limit": 10})
    if err != nil {
        log.Fatal(err)
    }
    println(result)
}
Using with OpenAI SDK
package main

import (
    "context"
    "encoding/json"
    "log"
    
    apiai "github.com/covrom/openapi-openai-go"
    "github.com/openai/openai-go/v3"
)

func main() {
    // Load and convert OpenAPI spec
    spec := loadOpenAPISpec() // Your OpenAPI spec loading logic
    functions := apiai.ConvertOpenAPIToFunctions(spec)

    // Create API client
    apiClient, err := apiai.NewAPIClient("https://api.example.com", nil)
    if err != nil {
        log.Fatal(err)
    }

    // Setup OpenAI client
    openaiClient := openai.NewClient()
    ctx := context.Background()

    // Prepare tools for OpenAI
    var tools []openai.ChatCompletionToolUnionParam
    for _, fn := range functions {
        tools = append(tools, openai.ChatCompletionFunctionTool(openai.FunctionDefinitionParam{
            Name:        fn.Name,
            Description: openai.String(fn.Description),
            Parameters: openai.FunctionParameters{
                "type":       fn.Parameters.Type,
                "properties": fn.Parameters.Properties,
                "required":   fn.Parameters.Required,
            },
        }))
    }

    // Make request to OpenAI
    completion, err := openaiClient.Chat.Completions.New(
        ctx,
        openai.ChatCompletionNewParams{
            Model: openai.ChatModelGPT4o,
            Messages: []openai.ChatCompletionMessageParamUnion{
                openai.UserMessage("List all pets with limit 5"),
            },
            Tools: tools,
        },
    )
    if err != nil {
        log.Fatal(err)
    }

    // Handle tool calls
    toolCalls := completion.Choices[0].Message.ToolCalls
    if len(toolCalls) > 0 {
        for _, toolCall := range toolCalls {
            var args map[string]interface{}
            json.Unmarshal([]byte(toolCall.Function.Arguments), &args)
            
            fn := functions[toolCall.Function.Name]
            result, err := apiai.ExecuteFunction(apiClient, fn, args)
            if err != nil {
                log.Printf("Error executing function: %v", err)
                continue
            }
            
            // Send result back to OpenAI for final response
            // ... handle tool message and get final completion
        }
    }
}

Authentication

The library supports multiple authentication methods:

Basic Authentication
authConfig := &apiai.AuthConfig{
    Type:     apiai.AuthTypeBasic,
    Username: "admin",
    Password: "secret",
}

client, err := apiai.NewAPIClient("https://api.example.com", authConfig)
API Key (Header)
authConfig := &apiai.AuthConfig{
    Type:        apiai.AuthTypeAPIKeyHeader,
    APIKeyName:  "X-API-Key",
    APIKeyValue: "your-api-key",
}

client, err := apiai.NewAPIClient("https://api.example.com", authConfig)
Bearer Token
authConfig := &apiai.AuthConfig{
    Type:  apiai.AuthTypeBearer,
    Token: "your-bearer-token",
}

client, err := apiai.NewAPIClient("https://api.example.com", authConfig)
OAuth2
import "golang.org/x/oauth2"

oauth2Config := &oauth2.Config{
    // Your OAuth2 configuration
}
tokenSource := oauth2Config.TokenSource(context.Background(), token)

authConfig := &apiai.AuthConfig{
    Type:        apiai.AuthTypeOAuth2,
    TokenSource: tokenSource,
}

client, err := apiai.NewAPIClient("https://api.example.com", authConfig)
authConfig := &apiai.AuthConfig{
    Type: apiai.AuthTypeCookie,
    Cookies: []*http.Cookie{
        {Name: "sessionid", Value: "abc123"},
        {Name: "csrftoken", Value: "xyz789"},
    },
}

client, err := apiai.NewAPIClient("https://api.example.com", authConfig)

Working with OpenAPI Specifications

Loading from JSON
specJSON := []byte(`{"openapi": "3.0.0", ...}`)
spec, err := apiai.UnmarshalOpenAPISpecFromJSON(specJSON)
if err != nil {
    log.Fatal(err)
}
Loading from YAML
specYAML := []byte(`
openapi: 3.0.0
info:
  title: My API
  version: 1.0.0
paths:
  /users:
    get:
      summary: List users
`)

spec, err := apiai.UnmarshalOpenAPISpecFromYAML(specYAML)
if err != nil {
    log.Fatal(err)
}
Auto-detection (JSON or YAML)
specData := []byte(...) // Your OpenAPI spec data
spec, err := apiai.UnmarshalOpenAPISpec(specData)
if err != nil {
    log.Fatal(err)
}
Handling References

The library automatically resolves $ref parameters in OpenAPI components:

specJSON := `{
    "openapi": "3.0.0",
    "components": {
        "parameters": {
            "offsetParam": {
                "name": "offset",
                "in": "query",
                "schema": {"type": "integer"}
            }
        }
    },
    "paths": {
        "/users": {
            "get": {
                "parameters": [
                    {"$ref": "#/components/parameters/offsetParam"}
                ]
            }
        }
    }
}`

functions := apiai.ConvertOpenAPIToFunctions(spec)
// The offset parameter will be automatically resolved

API Reference

Core Types
OpenAPISpec

Represents an OpenAPI 3.0 specification with paths, components, and metadata.

FunctionDefinition

Represents a function definition compatible with OpenAI's function calling API:

type FunctionDefinition struct {
    Name        string   `json:"name"`
    Description string   `json:"description"`
    Parameters  Schema   `json:"parameters"`
    OapiMethod  string   `json:"-"`      // Original HTTP method
    OapiPath    string   `json:"-"`      // Original OpenAPI path
    PathParams  []string `json:"-"`      // Path parameter names
    QueryParams []string `json:"-"`      // Query parameter names
}
APIClient

HTTP client for executing API calls with authentication:

type APIClient struct {
    BaseURL    *url.URL
    HTTPClient *http.Client
}
Main Functions
ConvertOpenAPIToFunctions(spec *OpenAPISpec) map[string]*FunctionDefinition

Converts OpenAPI operations to function definitions.

ExecuteFunction(client *APIClient, fn *FunctionDefinition, arguments map[string]any) (any, error)

Executes a function call against the target API.

NewAPIClient(baseURL string, authConfig *AuthConfig, opts ...func(*http.Client)) (*APIClient, error)

Creates a new API client with optional authentication.

UnmarshalOpenAPISpec(data []byte) (*OpenAPISpec, error)

Automatically detects and parses JSON or YAML OpenAPI specifications.

Examples

The repository includes several comprehensive examples:

1. Basic Example (cmd/example/main.go)

Demonstrates basic usage with OpenAI integration and function calling.

2. Tool Call Example (cmd/toolcall_example/tool_call_example.go)

Shows how to handle OpenAI tool calls with mock function execution.

3. YAML Example (cmd/yaml_example/main.go)

Illustrates loading OpenAPI specs from YAML and auto-detection.

Running Examples
# Basic example with OpenAI integration
go run cmd/example/main.go

# Tool calling example
go run cmd/toolcall_example/tool_call_example.go

# YAML parsing example
go run cmd/yaml_example/main.go

Testing

Run the test suite:

go test ./...

The tests cover:

  • OpenAPI spec parsing (JSON and YAML)
  • Function conversion
  • Parameter reference resolution
  • Auto-detection of formats

Requirements

  • Go 1.25.4 or later
  • OpenAI Go SDK v3.9.0+
  • golang.org/x/oauth2 v0.33.0+
  • gopkg.in/yaml.v3 v3.0.1+

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

Use Cases

This library is particularly useful for:

  • AI Agents: Enable AI agents to interact with REST APIs through natural language
  • API Integration: Quickly integrate existing REST APIs with OpenAI's function calling
  • Automation: Build automated workflows that can interact with multiple APIs
  • Chatbots: Create chatbots that can perform actions through API calls
  • Development Tools: Build developer tools that can interact with APIs intelligently

Documentation

Index

Constants

View Source
const (
	AuthTypeNone         AuthType = "none"
	AuthTypeBasic                 = "basic"
	AuthTypeAPIKeyHeader          = "apikey-header"
	AuthTypeAPIKeyCookie          = "apikey-cookie"
	AuthTypeBearer                = "bearer"
	AuthTypeOAuth2                = "oauth2"
	AuthTypeCookie                = "cookie"
)

Variables

This section is empty.

Functions

func ConvertOpenAPIToFunctions

func ConvertOpenAPIToFunctions(spec *OpenAPISpec) map[string]*FunctionDefinition

ConvertOpenAPIToFunctions converts OpenAPI spec to LLM function definitions

func ExecuteFunction

func ExecuteFunction(client *APIClient, fn *FunctionDefinition, arguments map[string]any) (any, error)

ExecuteFunction calls the registered function handler

func NewHTTPClient

func NewHTTPClient(config *AuthConfig, opts ...func(*http.Client)) *http.Client

NewHTTPClient creates an http.Client with the specified authentication. Usage examples

Example 1: Basic Auth

client1 := NewHTTPClient(&AuthConfig{
	Type:     AuthTypeBasic,
	Username: "admin",
	Password: "secret",
})

Example 2: API Key in header

client2 := NewHTTPClient(&AuthConfig{
	Type:        AuthTypeAPIKeyHeader,
	APIKeyName:  "X-API-Key",
	APIKeyValue: "12345-abcde",
})

Example 3: Bearer Token

client3 := NewHTTPClient(&AuthConfig{
	Type:  AuthTypeBearer,
	Token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
})

Example 4: OAuth2 with custom TokenSource oauth2Config := &oauth2.Config{...} ts := oauth2Config.TokenSource(context.Background(), token)

client4 := NewHTTPClient(&AuthConfig{
	Type:         AuthTypeOAuth2,
	TokenSource:  nil, // can pass oauth2.TokenSource
	Token:        "access_token_here", // fallback
})

Example 5: Cookie Auth

client5 := NewHTTPClient(&AuthConfig{
	Type: AuthTypeCookie,
	Cookies: []*http.Cookie{
		{Name: "sessionid", Value: "abc123"},
		{Name: "csrftoken", Value: "xyz789"},
	},
})

Use it resp, err := client1.Get("https://httpbin.org/basic-auth/admin/secret")

if err != nil {
	panic(err)
}

defer resp.Body.Close() fmt.Println("Status:", resp.Status)

Types

type APIClient

type APIClient struct {
	BaseURL    *url.URL
	HTTPClient *http.Client // change this to client with authenticate
}

APIClient handles HTTP requests to the API

func NewAPIClient

func NewAPIClient(baseURL string, authConfig *AuthConfig, opts ...func(*http.Client)) (*APIClient, error)

NewAPIClient creates a new API client

type AuthConfig

type AuthConfig struct {
	Type AuthType

	// Basic Auth
	Username string
	Password string

	// API Key
	APIKeyName  string // name of header or cookie
	APIKeyValue string

	// Bearer / OAuth2 / OpenID
	Token string

	// OAuth2 TokenSource (allows automatic token refresh)
	TokenSource oauth2.TokenSource

	// Cookie Auth: list of cookies (name=value)
	Cookies []*http.Cookie
}

AuthConfig contains the authentication configuration.

type AuthRoundTripper

type AuthRoundTripper struct {
	// contains filtered or unexported fields
}

AuthRoundTripper wraps http.RoundTripper and adds authentication.

func (*AuthRoundTripper) RoundTrip

func (art *AuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip implements the RoundTripper interface.

type AuthType

type AuthType string

AuthType defines the type of authentication.

type Components

type Components struct {
	Parameters map[string]Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"`
}

Components contains reusable objects

type FunctionDefinition

type FunctionDefinition struct {
	Name        string   `json:"name" yaml:"name"`
	Description string   `json:"description" yaml:"description"`
	Parameters  Schema   `json:"parameters" yaml:"parameters"`
	OapiMethod  string   `json:"-" yaml:"-"`
	OapiPath    string   `json:"-" yaml:"-"`
	PathParams  []string `json:"-" yaml:"-"`
	QueryParams []string `json:"-" yaml:"-"`
}

FunctionDefinition represents an LLM function definition

type Info

type Info struct {
	Title       string `json:"title" yaml:"title"`
	Description string `json:"description" yaml:"description"`
	Version     string `json:"version" yaml:"version"`
}

Info contains API metadata

type MediaType

type MediaType struct {
	Schema *Schema `json:"schema" yaml:"schema"`
}

MediaType represents media type in request/response body

type OpenAPISpec

type OpenAPISpec struct {
	OpenAPI    string              `json:"openapi" yaml:"openapi"`
	Paths      map[string]PathItem `json:"paths" yaml:"paths"`
	Info       Info                `json:"info" yaml:"info"`
	Components *Components         `json:"components,omitempty" yaml:"components,omitempty"`
}

OpenAPISpec represents an OpenAPI 3.x specification

func UnmarshalOpenAPISpec

func UnmarshalOpenAPISpec(data []byte) (*OpenAPISpec, error)

UnmarshalOpenAPISpec unmarshals OpenAPI spec from data, automatically detecting format (JSON or YAML)

func UnmarshalOpenAPISpecFromJSON

func UnmarshalOpenAPISpecFromJSON(data []byte) (*OpenAPISpec, error)

UnmarshalOpenAPISpecFromJSON unmarshals OpenAPI spec from JSON data

func UnmarshalOpenAPISpecFromYAML

func UnmarshalOpenAPISpecFromYAML(data []byte) (*OpenAPISpec, error)

UnmarshalOpenAPISpecFromYAML unmarshals OpenAPI spec from YAML data

type Operation

type Operation struct {
	Summary     string       `json:"summary" yaml:"summary"`
	Description string       `json:"description" yaml:"description"`
	Parameters  []Parameter  `json:"parameters,omitempty" yaml:"parameters,omitempty"`
	RequestBody *RequestBody `json:"requestBody,omitempty" yaml:"requestBody,omitempty"`
}

Operation represents an API operation

type Parameter

type Parameter struct {
	Name        string  `json:"name" yaml:"name"`
	In          string  `json:"in" yaml:"in"`
	Description string  `json:"description" yaml:"description"`
	Required    bool    `json:"required" yaml:"required"`
	Schema      *Schema `json:"schema" yaml:"schema"`
	Ref         string  `json:"$ref,omitempty" yaml:"$ref,omitempty"`
}

Parameter represents an API parameter

type PathItem

type PathItem struct {
	Get    *Operation `json:"get" yaml:"get"`
	Post   *Operation `json:"post" yaml:"post"`
	Put    *Operation `json:"put" yaml:"put"`
	Delete *Operation `json:"delete" yaml:"delete"`
	Patch  *Operation `json:"patch" yaml:"patch"`
}

PathItem represents a path in the OpenAPI spec

type RequestBody

type RequestBody struct {
	Content map[string]MediaType `json:"content" yaml:"content"`
}

RequestBody represents the request body definition

type Schema

type Schema struct {
	Type        string             `json:"type" yaml:"type"`
	Properties  map[string]*Schema `json:"properties,omitempty" yaml:"properties,omitempty"`
	Required    []string           `json:"required,omitempty" yaml:"required,omitempty"`
	Format      string             `json:"format,omitempty" yaml:"format,omitempty"`
	Description string             `json:"description,omitempty" yaml:"description,omitempty"`
}

Schema represents JSON Schema

Directories

Path Synopsis
cmd
example command
yaml_example command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL