# Server Functions

A **server function** is a function in your code-native integration that your app calls while a customer configures an instance. Use server functions for anything your configuration form needs from a third-party app: a list of record types, the fields of a record type, a preview of mapped data.

Server functions are the headless counterpart of [data sources](https://prismatic.io/docs/integrations/data-sources.md) in a config wizard. They run in Prismatic, alongside your integration's code and [connections](https://prismatic.io/docs/integrations/headless-configuration/connections.md), so your app never handles third-party credentials.

## Define a server function[​](#define-a-server-function "Direct link to Define a server function")

Define a server function with Spectral's `serverFunction()`. It takes an input schema, an output schema, and a `perform` function:

src/configuration.ts

```typescript
import { serverFunction } from "@prismatic-io/spectral";
import { z } from "zod";
import { listFields } from "./fake-crm";

export const listFieldsFunction = serverFunction({
  label: "List fields",
  description: "The fields of a Fake CRM record type",
  inputSchema: z.object({ recordType: z.string().min(1) }),
  outputSchema: z.array(
    z.object({ name: z.string(), label: z.string(), type: z.string() }),
  ),
  perform: async (context, { recordType }) => listFields(recordType),
});

```

| Property       | Required | Description                                                                                                                                                        |
| -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `inputSchema`  | Yes      | A zod or JSON Schema for the function's inputs. Prismatic validates inputs against it before running the function.                                                 |
| `outputSchema` | Yes      | A zod or JSON Schema for the function's result. Prismatic publishes it for your app but doesn't enforce it.                                                        |
| `perform`      | Yes      | The function. It receives a `context` and the validated inputs, and returns the result.                                                                            |
| `connections`  | No       | The connections the function needs, such as `["instance.slack"]`. See [Connections](https://prismatic.io/docs/integrations/headless-configuration/connections.md). |
| `label`        | No       | A display name for the function.                                                                                                                                   |
| `description`  | No       | A description of the function.                                                                                                                                     |

Then register it under a key in your configuration's `serverFunctions`. Your app calls the function by this key:

src/configuration.ts

```typescript
export const integrationConfiguration = configuration({
  instance: { schema: configurationSchema, version: "fake-crm-v1" },
  serverFunctions: {
    listRecordTypes: listRecordTypesFunction,
    listFields: listFieldsFunction,
    getSampleRecord: getSampleRecordFunction,
  },
});

```

## The server function context[​](#the-server-function-context "Direct link to The server function context")

A server function's `context` includes:

| Property                       | Description                                                                                                                                      |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `logger`                       | Writes to the instance's logs.                                                                                                                   |
| `connections`                  | The connections the function declared in `connections`, such as `context.connections.instance.slack`.                                            |
| `configuration`                | The instance's **saved** configuration. It may be empty or in an older shape while a customer is configuring.                                    |
| `userConfiguration`            | The current user's saved user-level configuration, if any.                                                                                       |
| `components`                   | Actions of the components in your integration's [component registry](https://prismatic.io/docs/integrations/code-native/existing-components.md). |
| `customer`, `instance`, `user` | Attributes of the customer, instance, and user.                                                                                                  |

## Pass unsaved form values as inputs[​](#pass-unsaved-form-values-as-inputs "Direct link to Pass unsaved form values as inputs")

While a customer fills in your form, their choices aren't saved yet, so `context.configuration` doesn't include them. Pass anything the function needs from the form as an input.

For example, the Fake CRM integration's `getSampleRecord` function takes the customer's unsaved field mapping and returns a sample record, mapped the same way the flow will map it. Your app shows the result as a live preview:

src/configuration.ts

```typescript
export const getSampleRecordFunction = serverFunction({
  label: "Get sample record",
  description:
    "A sample Fake CRM record and the Acme contact a mapping makes from it",
  inputSchema: z.object({
    recordType: z.string().min(1),
    fieldMapping: z.record(z.string(), z.string()).optional(),
  }),
  outputSchema: z.object({
    record: z
      .record(z.string(), z.union([z.string(), z.number(), z.null()]))
      .nullable(),
    acmeContact: z.record(z.string(), z.string()),
  }),
  perform: async (_context, { recordType, fieldMapping }) => {
    const [record] = listRecords(recordType);
    if (!record) return { record: null, acmeContact: {} };
    // The same function the flow uses, so the preview matches what's sent
    return { record, acmeContact: toAcmeContact(record, fieldMapping ?? {}) };
  },
});

```

## Call a server function from your app[​](#call-a-server-function-from-your-app "Direct link to Call a server function from your app")

Your app calls a server function through the configuration it belongs to. In React, use the `useServerFunction` hook:

```tsx
const configuration = useConfiguration({ instanceId });
const listFields = useServerFunction<{ recordType: string }, Field[]>(
  configuration,
  "listFields",
);

const result = await listFields.execute({ inputs: { recordType: "Contact" } });
if (result.status === "success") {
  setFields(result.data);
}

```

A server function runs against the integration version its configuration is for. When a customer reviews an update to a new version, your app calls the new version's server functions before the instance moves to it.

See [Building configuration UIs with Solis React](https://prismatic.io/docs/embed/headless/react.md#calling-server-functions) for details.

## Test server functions[​](#test-server-functions "Direct link to Test server functions")

A server function's `perform` is a plain async function, so you can unit test it directly:

src/configuration.test.ts

```typescript
import { listFieldsFunction } from "./configuration";

test("lists the fields of a record type", async () => {
  const fields = await listFieldsFunction.perform({} as never, {
    recordType: "Contact",
  });
  expect(fields.map(({ name }) => name)).toContain("AccountName");
});

```

If your function reads from `context`, pass the properties it uses instead of an empty object.
