Using Ollama Web Search API in Go
Source: Dev.to

Getting Started
Does Ollama have an official Go library for web search?
Ollama provides a REST API for web search that works with any Go HTTP client. While there’s no official Go SDK for web search yet, you can easily implement the API calls using the standard library.
- Create an API key from your Ollama account.
- Set the API key as an environment variable.
export OLLAMA_API_KEY="your_api_key"
On Windows PowerShell:
$env:OLLAMA_API_KEY = "your_api_key"
For a comprehensive reference on Ollama commands and usage, see the Ollama cheatsheet.
Project Setup
Create a new Go module:
mkdir ollama-search
cd ollama-search
go mod init ollama-search
Basic Web Search
How do I authenticate with Ollama’s web search API in Go?
Set the Authorization header with your API key as a Bearer token.
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
// Request/Response types for web_search
type WebSearchRequest struct {
Query string `json:"query"`
MaxResults int `json:"max_results,omitempty"`
}
type WebSearchResult struct {
Title string `json:"title"`
URL string `json:"url"`
Content string `json:"content"`
}
type WebSearchResponse struct {
Results []WebSearchResult `json:"results"`
}
func webSearch(query string, maxResults int) (*WebSearchResponse, error) {
apiKey := os.Getenv("OLLAMA_API_KEY")
if apiKey == "" {
return nil, fmt.Errorf("OLLAMA_API_KEY environment variable not set")
}
reqBody := WebSearchRequest{
Query: query,
MaxResults: maxResults,
}
jsonData, err := json.Marshal(reqBody)
if err != nil {
return nil, fmt.Errorf("failed to marshal request: %w", err)
}
req, err := http.NewRequest("POST", "https://ollama.com/api/web_search", bytes.NewBuffer(jsonData))
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+apiKey)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("API error (status %d): %s", resp.StatusCode, string(body))
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response: %w", err)
}
var searchResp WebSearchResponse
if err := json.Unmarshal(body, &searchResp); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &searchResp, nil
}
func truncate(s string, maxLen int) string {
if len(s) = 5 {
fmt.Printf(" ... and %d more\n", len(result.Links)-5)
break
}
fmt.Printf(" - %s\n", link)
}
}
Reusable Client Package
Create a reusable Ollama client package for cleaner code.
// ollama/client.go
package ollama
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"time"
)
type Client struct {
apiKey string
httpClient *http.Client
baseURL string
}
func NewClient() (*Client, error) {
apiKey := os.Getenv("OLLAMA_API_KEY")
if apiKey == "" {
return nil, fmt.Errorf("OLLAMA_API_KEY environment variable not set")
}
return &Client{
apiKey: apiKey,
httpClient: &http.Client{
Timeout: 30 * time.Second,
},
baseURL: "https://ollama.com/api",
}, nil
}
// Generic POST helper
func (c *Client) post(endpoint string, payload interface{}, out interface{}) error {
jsonData, err := json.Marshal(payload)
if err != nil {
return fmt.Errorf("marshal error: %w", err)
}
req, err := http.NewRequest("POST", c.baseURL+endpoint, bytes.NewBuffer(jsonData))
if err != nil {
return fmt.Errorf("request creation error: %w", err)
}
req.Header.Set("Authorization", "Bearer "+c.apiKey)
req.Header.Set("Content-Type", "application/json")
resp, err := c.httpClient.Do(req)
if err != nil {
return fmt.Errorf("request error: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("API error (status %d): %s", resp.StatusCode, string(body))
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("read error: %w", err)
}
if err := json.Unmarshal(body, out); err != nil {
return fmt.Errorf("unmarshal error: %w", err)
}
return nil
}
// WebSearch calls the /web_search endpoint
func (c *Client) WebSearch(query string, maxResults int) (*WebSearchResponse, error) {
req := WebSearchRequest{
Query: query,
MaxResults: maxResults,
}
var resp WebSearchResponse
if err := c.post("/web_search", req, &resp); err != nil {
return nil, err
}
return &resp, nil
}
// WebFetch calls the /web_fetch endpoint
func (c *Client) WebFetch(url string) (*WebFetchResponse, error) {
req := WebFetchRequest{URL: url}
var resp WebFetchResponse
if err := c.post("/web_fetch", req, &resp); err != nil {
return nil, err
}
return &resp, nil
}
You can now use the client in your applications:
package main
import (
"fmt"
"log"
"yourmodule/ollama"
)
func main() {
client, err := ollama.NewClient()
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
// Example: web search
searchRes, err := client.WebSearch("Ollama Go SDK", 3)
if err != nil {
log.Fatalf("Search error: %v", err)
}
for _, r := range searchRes.Results {
fmt.Printf("- %s (%s)\n", r.Title, r.URL)
}
// Example: fetch a page
fetchRes, err := client.WebFetch("https://ollama.com")
if err != nil {
log.Fatalf("Fetch error: %v", err)
}
fmt.Printf("\nFetched title: %s\n", fetchRes.Title)
}