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

# Tutorial: Simple app

> Build a minimal custom integration app from scratch.

In the tutorial we will implement the simplest app with token authentication. We will use NodeJS and Express framework, but you can use any other programming language. Find source code repository here:

[https://gitlab.com/fibery-community/integration-sample-apps](https://gitlab.com/fibery-community/integration-sample-apps)

To create simple app you need to implement following [Custom App: REST Endpoints](/guides/integrations/rest-endpoints):

* getting app information: `GET /`
* validate account: `POST /validate`
* getting synchronizer configuration: `POST /api/v1/synchronizer/config`
* getting schema: `POST /api/v1/synchronizer/schema`
* fetching data `POST /api/v1/synchronizer/data`

Let's implement them one by one. But first let's define dataset:

```javascript theme={null}
const users = {
  token1: {
    name: `Dad Sholler`,
    data: {
      flower: [
        {id: `47fd45cf-5a07-40aa-9ee4-a4258832154a`, name: `Rose`},
        {id: `4f3afc75-2fb9-4ff8-b26f-ab4bf2f470a3`, name: `Lily`},
        {id: `d7525fc1-1979-4cfb-ba32-0dfab9280b24`, name: `Tulip`},
      ],
      regionPrice: [
        {
          id: `56c50696-1d9f-4e4d-9678-448017d25474`,
          flowerId: `d7525fc1-1979-4cfb-ba32-0dfab9280b24`,
          price: 10,
          name: `Eastern Europe`,
        },
        {
          id: `503e5efb-7650-4c3a-85e9-f4ebc23adfd5`,
          name: `Western Europe`,
          flowerId: `d7525fc1-1979-4cfb-ba32-0dfab9280b24`,
          price: 15,
        },
        {
          id: `87ccd5ef-ed3f-49db-9bcc-c9d1daf91744`,
          name: `Eastern Europe`,
          price: 20,
          flowerId: `47fd45cf-5a07-40aa-9ee4-a4258832154a`,
        },
      ],
    },
  },
  token2: {
    name: `Ben Dreamer`,
    data: {
      flower: [
        {id: `4f3afc75-2fb9-4ff8-b26f-ab4bf2f470a3`, name: `Lily`},
        {id: `d7525fc1-1979-4cfb-ba32-0dfab9280b24`, name: `Tulip`},
      ],
      regionPrice: [
        {
          id: `c3352e8c-e62c-4e26-9a8b-852c1a3d2435`,
          flowerId: `d7525fc1-1979-4cfb-ba32-0dfab9280b24`,
          price: 10,
          name: `East Coast`,
        },
        {
          id: `7a581588-d5fc-46aa-a084-8e2b28f3d6e5`,
          name: `West Coast`,
          flowerId: `d7525fc1-1979-4cfb-ba32-0dfab9280b24`,
          price: 15,
        },
        {
          id: `6e510195-41e3-499b-9a76-9ad928720882`,
          name: `Asia`,
          price: 20,
          flowerId: `4f3afc75-2fb9-4ff8-b26f-ab4bf2f470a3`,
        },
      ],
    },
  },
};
```

## Getting app information

App information should have the structure described in [App configuration](/guides/integrations/app-configuration). Let's implement it. We can see that the app require token authentication and responsible for data synchronization.

```javascript theme={null}
app.get(`/`, (req, res) => {
  res.json({
    id: 'integration-sample-app',
    name: 'Integration Sample App',
    version: `1.0.0`,
    type: 'crunch',
    description: 'Integration sample app.',
    authentication: [
      {
        description: 'Provide Token',
        name: 'Token Authentication',
        id: 'token',
        fields: [
          {
            type: 'text',
            description: 'Personal Token',
            id: 'token',
          },
        ],
      },
    ],
    sources: [],
    responsibleFor: {
      dataSynchronization: true,
    },
  });
});
```

## **Validate account**

Since authentication is required we should run an authentication and return corresponding user name. You can find more information about the endpoint here.

```javascript theme={null}
app.post(`/validate`, (req, res) => {
  const user = users[req.body.fields.token];
  if (user) {
    return res.json({name: user.name});
  }

  res.status(401).json({message: `Unauthorized`});
});
```

## **Getting sync configuration**

This is basic a scenario and we don't need any dynamic. So we will return a static configuration with no filters.

```javascript theme={null}
app.post(`/api/v1/synchronizer/config`, (req, res) => {
  res.json({
    types: [
      {id: `flower`, name: `Flower`},
      {id: `regionPrice`, name: `Region Price`},
    ],
    filters: [],
  });
});
```

## Getting schema

We should provide schema for selected types.

```javascript theme={null}
const schema = {
  flower: {
    id: {name: `Id`, type: `id`},
    name: {name: `Name`, type: `text`},
  },
  regionPrice: {
    id: {name: `Id`, type: `id`},
    name: {name: `Name`, type: `text`},
    price: {name: `Price`, type: `number`},
    flowerId: {
      name: `Flower Id`,
      type: `text`,
      relation: {
        cardinality: `many-to-one`,
        name: `Flower`,
        targetName: `Region Prices`,
        targetType: `flower`,
        targetFieldId: `id`,
      },
    },
  },
};

app.post(`/api/v1/synchronizer/schema`, (req, res) => {
  res.json(
    req.body.types.reduce((acc, type) => {
      acc[type] = schema[type];
      return acc;
    }, {}),
  );
});
```

## **Fetching data**

The endpoint receives requested type, accounts, filter and set of selected types and should return actual data.

```javascript theme={null}
app.post(`/api/v1/synchronizer/data`, (req, res) => {
  const {requestedType, account} = req.body;

  return res.json({
    items: users[account.token].data[requestedType],
  });
});
```

And that's it! Our app is ready for use. See full example [here](https://gitlab.com/fibery-community/integration-sample-apps).
