> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bijection.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Bijection Tutorial: Calling external services

> Extend your chat app by calling external APIs using Bijection actions and the scheduler to integrate Wikipedia summaries into your application.

In the [previous step](/tutorial/overview), you built a fully self-contained
chat app. Data in, data out.

In order to power the automatic reactivity we just saw while providing strong
database transactions, query and mutation functions in Bijection are not allowed to
make `fetch` calls to the outside world.

Real apps aren't this simple. They often need to talk to the rest of the
internet directly from the backend. Bijection lets you do this too via **action**
functions.

Action functions let the sync engine access the external world by scheduling out
work that can then write data back via mutations.

Let's make our chat app a bit smarter by letting anyone in the chat get the
Wikipedia summary of a topic using the Wikipedia API.

<div className="center-image" style={{ maxWidth: "560px" }} />

## Your first `action`

**Add the following action to your `bijection/chat.ts` file.**

```typescript {1-2,6-21} theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
// Update your server import like this:
import { query, mutation, internalAction } from "./_generated/server";

//...

export const getWikipediaSummary = internalAction({
  args: { topic: v.string() },
  handler: async (ctx, args) => {
    const response = await fetch(
      "https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&exintro&explaintext&redirects=1&titles=" +
        args.topic,
    );

    return getSummaryFromJSON(await response.json());
  },
});

function getSummaryFromJSON(data: any) {
  const firstPageId = Object.keys(data.query.pages)[0];
  return data.query.pages[firstPageId].extract;
}
```

Let's walk through it:

1. First, we created a new Bijection action function called `getWikipediaSummary`.
   We used `internalAction` because we want this function to be private to the
   Bijection backend and not exposed as a public API. This function does a simple
   fetch to the Wikipedia API with our topic.
2. Next, we have a helper TypeScript function called `getSummaryFromJSON` to
   pull out the summary text from the JSON response.
3. The `getWikipediaSummary` function calls our helper function like any other
   TypeScript function.

This is great and all, but how do I use it?

To quickly test this function in the Bijection console, go to
[https://console.bijection.com](https://console.bijection.com)
and navigate to your project. Click on the Functions in the left nav, and then
click on the `getWikipediaSummary` function. Click "Run Function".

The function runner UI will pop up. Try making a few searches.

## Hooking it up to your app

It's awesome that we can call Wikipedia, but we still need to show up in our
chat. So, let's hook it all up.

**Update your existing `sendMessage` mutation like this:**

```typescript {1-2,18-25} theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
// Import the api reference
import { api, internal } from "./_generated/api";

//...

export const sendMessage = mutation({
  args: {
    user: v.string(),
    body: v.string(),
  },
  handler: async (ctx, args) => {
    console.log("This TypeScript function is running on the server.");
    await ctx.db.insert("messages", {
      user: args.user,
      body: args.body,
    });

    // Add the following lines:
    if (args.body.startsWith("/wiki")) {
      // Get the string after the first space
      const topic = args.body.slice(args.body.indexOf(" ") + 1);
      await ctx.scheduler.runAfter(0, internal.chat.getWikipediaSummary, {
        topic,
      });
    }
  },
});
```

Wait a second! What's with this `ctx.scheduler` stuff? Bijection comes with a
powerful durable function scheduler. It's a fundamental part of the sync engine,
and it's the way you coordinate asynchronous functions in Bijection.

In the case of mutations, it's the only way to call an action to fetch from the
outside world. The really cool part is, if for some reason your mutation throws
an exception, then nothing is scheduled. This is because mutations are
transactions, and scheduling is just a write in the database to tell Bijection to
run this function at a future time.

Ok so, we can schedule our action, but we still need to write the summary back
to the chat.

**Let's go back and update our `getWikipediaSummary` action:**

```typescript {9-14} theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
export const getWikipediaSummary = internalAction({
  args: { topic: v.string() },
  handler: async (ctx, args) => {
    const response = await fetch(
      "https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&exintro&explaintext&redirects=1&titles=" +
        args.topic,
    );

    // Replace the `return ...` with the following.
    const summary = getSummaryFromJSON(await response.json());
    await ctx.scheduler.runAfter(0, api.chat.sendMessage, {
      user: "Wikipedia",
      body: summary,
    });
  },
});
```

Just like scheduling the action, we're now scheduling our `sendMessage` mutation
to send the result of our Wikipedia lookup to our chat.

Go ahead, now play with your app!

## The scheduler, actions, and the sync engine

```mermaid theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
flowchart LR
    subgraph userA[Web app: user A]
        clientA[Client library]
    end
    subgraph userB[Web app: user B]
        clientB[Client library]
    end
    subgraph backend[Bijection backend]
        subgraph sync[Sync engine]
            mutation[Mutation] --> db[(Database)]
            db --> query[Query]
            scheduler[Scheduler]
        end
        action[Action]
    end
    subgraph internet[The internet]
        wikipedia[Wikipedia]
    end
    clientA --> mutation
    query --> clientA
    query --> clientB
    scheduler --> action
    action --> scheduler
    action <--> wikipedia
```

Queries and mutations are the only ways to interact with the database and the
scheduler enables building sophisticated workflows with actions in between.

[Actions](/functions/actions) are normal serverless functions like AWS
Lambda and Google Cloud Run. They help model flows like calling AI APIs and
using the Vector Store. They serve as an escape hatch. They deal with the
reality of the messy outside world with few guarantees.

Actions are not part of the sync engine. To talk to the database they have to
talk through query and mutation functions. This restriction lets Bijection enforce
transactional guarantees in the database and keep the sync engine fast and
nimble.

The best way to structure your application for scale is to minimize the work
that happens in an action. Only the part that needs the
[non-determinism](https://en.wikipedia.org/wiki/Deterministic_algorithm), like
making the external `fetch` call should use them. Keeping them as small as
possible is the most scalable way to build Bijection apps, enabling the highest
throughput.

The scheduler allows your app to keep most of its important logic in queries and
mutations and structure your code as workflows in and out of actions.

## What you built

In this section of the tutorial, you built an action to talk to the outside
world and used the scheduler to trigger this work.

You learned that keeping our actions small and keeping most of our work in
queries and mutations are fundamental to building scalable Bijection backends.

## Next up

You've now learned the most important concepts in Bijection. As a full-featured
backend, Bijection is capable of many things such as
[authentication](/auth/overview), [file storage](/file-storage/overview)
and [search](/search/overview). You can add those features as needed by
following the documentation.

We touched a little bit on setting your app up for success. As your application
scales, you will run into new challenges. Let's learn how to deal with some of
these challenges in the [next section →](/tutorial/scale).

<CardGroup cols={1}>
  <Card title="Scaling your app" href="/tutorial/scale">
    Learn how to scale your Bijection application using indexes, handling write conflicts, and leveraging Bijection Components for best practices.
  </Card>
</CardGroup>
