Interacting with API

Almost all of the web applications relies on RESTful APIs. Enabling LLM to interact with them expand its practical utility.

This tutorial showcases how LLM can be used to make API calls through tool calling.

Prerequisite - Sample Event Management Server

We are going to use a simple Event Management server, and showcase how to interact with it.

const express = require('express');
const { v4: uuidv4 } = require('uuid');

const app = express();
const PORT = process.env.PORT || 5566;

// Middleware
app.use(express.json());

// Fake database - in-memory storage
let events = [
  {
    id: '1',
    name: 'Tech Conference 2024',
    date: '2024-06-15T09:00:00Z',
    location: 'San Francisco, CA'
  },
  {
    id: '2',
    name: 'Music Festival',
    date: '2024-07-20T18:00:00Z',
    location: 'Austin, TX'
  },
  {
    id: '3',
    name: 'Art Exhibition Opening',
    date: '2024-05-10T14:00:00Z',
    location: 'New York, NY'
  },
  {
    id: '4',
    name: 'Startup Networking Event',
    date: '2024-08-05T17:30:00Z',
    location: 'Seattle, WA'
  },
  {
    id: '5',
    name: 'Food & Wine Tasting',
    date: '2024-09-12T19:00:00Z',
    location: 'Napa Valley, CA'
  }
];

// Helper function to validate event data
const validateEvent = (eventData) => {
  const required = ['name', 'date', 'location'];
  const missing = required.filter(field => !eventData[field]);
  
  if (missing.length > 0) {
    return { valid: false, message: `Missing required fields: ${missing.join(', ')}` };
  }
  
  // Basic date validation
  const dateRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?$/;
  if (!dateRegex.test(eventData.date)) {
    return { valid: false, message: 'Date must be in ISO 8601 format (YYYY-MM-DDTHH:mm:ssZ)' };
  }
  
  return { valid: true };
};

// GET /events - List all events
app.get('/events', (req, res) => {
  res.status(200).json(events);
});

// POST /events - Create a new event
app.post('/events', (req, res) => {
  const validation = validateEvent(req.body);
  
  if (!validation.valid) {
    return res.status(400).json({ error: validation.message });
  }
  
  const newEvent = {
    id: req.body.id || uuidv4(),
    name: req.body.name,
    date: req.body.date,
    location: req.body.location
  };
  
  events.push(newEvent);
  res.status(201).json(newEvent);
});

// GET /events/{id} - Retrieve an event by ID
app.get('/events/:id', (req, res) => {
  const event = events.find(e => e.id === req.params.id);
  
  if (!event) {
    return res.status(404).json({ error: 'Event not found' });
  }
  
  res.status(200).json(event);
});

// DELETE /events/{id} - Delete an event by ID
app.delete('/events/:id', (req, res) => {
  const eventIndex = events.findIndex(e => e.id === req.params.id);
  
  if (eventIndex === -1) {
    return res.status(404).json({ error: 'Event not found' });
  }
  
  events.splice(eventIndex, 1);
  res.status(204).send();
});

// PATCH /events/{id} - Update an event's details by ID
app.patch('/events/:id', (req, res) => {
  const eventIndex = events.findIndex(e => e.id === req.params.id);
  
  if (eventIndex === -1) {
    return res.status(404).json({ error: 'Event not found' });
  }
  
  const validation = validateEvent(req.body);
  
  if (!validation.valid) {
    return res.status(400).json({ error: validation.message });
  }
  
  // Update the event
  events[eventIndex] = {
    ...events[eventIndex],
    name: req.body.name,
    date: req.body.date,
    location: req.body.location
  };
  
  res.status(200).json(events[eventIndex]);
});

// Error handling middleware
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ error: 'Something went wrong!' });
});

// 404 handler
app.use((req, res) => {
  res.status(404).json({ error: 'Endpoint not found' });
});

// Start the server
app.listen(PORT, () => {
  console.log(`Event Management API server is running on port ${PORT}`);
  console.log(`Available endpoints:`);
  console.log(`  GET    /events      - List all events`);
  console.log(`  POST   /events      - Create a new event`);
  console.log(`  GET    /events/{id} - Get event by ID`);
  console.log(`  PATCH  /events/{id} - Update event by ID`);
  console.log(`  DELETE /events/{id} - Delete event by ID`);
});

module.exports = app; 

Request Tools

There are 4 Request tools that can be used. This allows LLM to call the GET, POST, PUT, DELETE tools when necessary.

Step 1: Add the Start Node

The Start node is the entry point of your flow

Step 2: Add the Agent Node

Next, add an Agent node. In this setup, the agent is configured with four main tools: GET, POST, PUT, and DELETE. Each tool is set up to perform a specific type of API request.

Tool 1: GET (Retrieve Events)

  • Purpose: Fetch a list of events or a specific event from the API.

  • Configuration Inputs:

    • URL: http://localhost:5566/events

    • Name: get_events

    • Description: Describe when to use this tool. For example: Use this when you need to get events

    • Headers: (Optional) Add any required HTTP headers.

    • Query Params Schema: A JSON schema of the API which allows LLM to know about the URL structure, which path and query parameters to generate. For instance:

      {
        "id": {
          "type": "string",
          "in": "path",
          "description": "ID of the item to get. /:id"
        },
        "limit": {
          "type": "string",
          "in": "query",
          "description": "Limit the number of items to get. ?limit=10"
        }
      }

Tool 2: POST (Create Event)

  • Purpose: Create a new event in the system.

  • Configuration Inputs:

    • URL: http://localhost:5566/events

    • Name: create_event

    • Description: Use this when you want to create a new event.

    • Headers: (Optional) Add any required HTTP headers.

    • Body: Hard-coded body object that will override the body generated by LLM

    • Body Schema: A JSON schema of the API request body which allows LLM to know how to automatically generate the correct JSON body. For instance:

      {
        "name": {
          "type": "string",
          "required": true,
          "description": "Name of the event"
        },
        "date": {
          "type": "string",
          "required": true,
          "description": "Date of the event"
        },
        "location": {
          "type": "string",
          "required": true,
          "description": "Location of the event"
        }
      }

Tool 3: PUT (Update Event)

  • Purpose: Update an existing event’s details.

  • Configuration Inputs:

    • URL: http://localhost:5566/events

    • Name: update_event

    • Description: Use this when you want to update an event.

    • Headers: (Optional) Add any required HTTP headers.

    • Body: Hard-coded body object that will override the body generated by LLM

    • Body Schema: A JSON schema of the API request body which allows LLM to know how to automatically generate the correct JSON body. For instance:

      {
        "name": {
          "type": "string",
          "required": true,
          "description": "Name of the event"
        },
        "date": {
          "type": "string",
          "required": true,
          "description": "Date of the event"
        },
        "location": {
          "type": "string",
          "required": true,
          "description": "Location of the event"
        }
      }

Tool 4: DELETE (Delete Event)

  • Purpose: Remove an event from the system.

  • Configuration Inputs:

    • URL: http://localhost:5566/events

    • Name: delete_event

    • Description: Use this when you need to delete an event.

    • Headers: (Optional) Add any required HTTP headers.

    • Query Params Schema: A JSON schema of the API which allows LLM to know about the URL structure, which path and query parameters to generate. For instance:

      {
        "id": {
          "type": "string",
          "required": true,
          "in": "path",
          "description": "ID of the item to delete. /:id"
        }
      }

How the Agent Uses These Tools

  • The agent can dynamically select which tool to use based on the user’s request or the flow’s logic.

  • Each tool is mapped to a specific HTTP method and endpoint, with clearly defined input schemas.

  • The agent leverages the LLM to interpret user input, fill in the required parameters, and make the appropriate API call.

Certainly! Here are some Example Interactions for your flow, including sample user queries and the expected behavior for each, mapped to the corresponding tool (GET, POST, PUT, DELETE):

Example Interactions

1. Retrieve Events (GET)

Sample Query:

"Show me all upcoming events."

Expected Behavior:

  • The agent selects the GET tool.

  • It sends a GET request to http://localhost:5566/events.

  • The agent returns a list of all events to the user.


Sample Query:

"Get the details for event with ID 12345."

Expected Behavior:

  • The agent selects the GET tool.

  • It sends a GET request to http://localhost:5566/events/12345.

  • The agent returns the details for the event with ID 12345.


2. Create a New Event (POST)

Sample Query:

"Create a new event called 'AI Conference' on 2024-07-15 at Tech Hall."

Expected Behavior:

  • The agent selects the POST tool.

  • It sends a POST request to http://localhost:5566/events with the body:

    {
      "name": "AI Conference",
      "date": "2024-07-15",
      "location": "Tech Hall"
    }
  • The agent confirms the event was created and may return the new event’s details.


3. Update an Event (PUT)

Sample Query:

"Change the location of the event 'AI Conference' on 2024-07-15 to 'Main Auditorium'."

Expected Behavior:

  • The agent selects the PUT tool.

  • It sends a PUT request to http://localhost:5566/events with the updated event details:

    {
      "name": "AI Conference",
      "date": "2024-07-15",
      "location": "Main Auditorium"
    }
  • The agent confirms the event was updated.


4. Delete an Event (DELETE)

Sample Query:

"Delete the event with ID 12345."

Expected Behavior:

  • The agent selects the DELETE tool.

  • It sends a DELETE request to http://localhost:5566/events/12345.

  • The agent confirms the event was deleted.

Complete Flow


OpenAPI Toolkit

The 4 Requests tools work great if you have a couple of APIs, but imagine having tens or hundreds of APIs, this could become hard to maintain. To solve this problem, Flowise provides an OpenAPI toolkit which is able to take in an OpenAPI YAML file, and parse each API into a tool. The OpenAPI Specification (OAS) is a universally accepted standard for describing the details of RESTful APIs in a format that machines can read and interpret.

Using the Event Management API, we can generate an OpenAPI YAML file:

openapi: 3.0.0
info:
  version: 1.0.0
  title: Event Management API
  description: An API for managing event data

servers:
  - url: http://localhost:5566
    description: Local development server

paths:
  /events:
    get:
      summary: List all events
      operationId: listEvents
      responses:
        '200':
          description: A list of events
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Event'
    
    post:
      summary: Create a new event
      operationId: createEvent
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EventInput'
      responses:
        '201':
          description: The event was created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Event'
        '400':
          description: Invalid input
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /events/{id}:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: The event ID
    
    get:
      summary: Retrieve an event by ID
      operationId: getEventById
      responses:
        '200':
          description: The event
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Event'
        '404':
          description: Event not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    
    patch:
      summary: Update an event's details by ID
      operationId: updateEventDetails
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EventInput'
      responses:
        '200':
          description: The event's details were updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Event'
        '400':
          description: Invalid input
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Event not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    
    delete:
      summary: Delete an event by ID
      operationId: deleteEvent
      responses:
        '204':
          description: The event was deleted
        '404':
          description: Event not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

components:
  schemas:
    Event:
      type: object
      properties:
        id:
          type: string
          description: The unique identifier for the event
        name:
          type: string
          description: The name of the event
        date:
          type: string
          format: date-time
          description: The date and time of the event in ISO 8601 format
        location:
          type: string
          description: The location of the event
      required:
        - name
        - date
        - location
    
    EventInput:
      type: object
      properties:
        name:
          type: string
          description: The name of the event
        date:
          type: string
          format: date-time
          description: The date and time of the event in ISO 8601 format
        location:
          type: string
          description: The location of the event
      required:
        - name
        - date
        - location
    
    Error:
      type: object
      properties:
        error:
          type: string
          description: Error message

Step 1: Add the Start Node

Step 2: Add the Agent Node

Next, add an Agent node. In this setup, the agent is configured with only 1 tool - OpenAPI Toolkit

Tool: OpenAPI Toolkit

  • Purpose: Fetch the list of APIs from YAML file and turn every APIs into list of tools

  • Configuration Inputs:

    • YAML File: The OpenAPI YAML file

    • Return Direct: Whether to return the response from API directly

    • Headers: (Optional) Add any required HTTP headers.

    • Remove null parameters: Remove all keys with null values from the parsed arguments

    • Custom Code: Customize how response is being returned

Example Interactions:

We can use the same sample queries from previous example to test it out:


Calling API Sequentially

From the examples above, we’ve seen how the Agent can dynamically call tools and interact with APIs. In some cases, it may be necessary to call an API sequentially before or after certain actions. For instance, you might fetch a customer list from a CRM and pass it to an Agent. In such cases, you can use the HTTP node.

Best Practices

  • Interacting with APIs is typically used when you want an agent to fetch the most up-to-date information. For example, an agent might retrieve your calendar availability, project status, or other real-time data.

  • It is often helpful to explicitly include the current time in the system prompt. Flowise provides a variable called {{current_date_time}}, which retrieves the current date and time. This allows the LLM to be aware of the present moment, so if you ask about your availability for today, the model can reference the correct date. Otherwise, it may rely on its last training cutoff date, which would return outdated information. For example:

You are helpful assistant.

Todays date time is {{current_date_time }}

Last updated