---
sidebar_position: 1
title: Basic Usage
---
# Basic Usage

Applications developed with Modern.js can define API functions in the `api/` directory, which can be called by the front-end to send requests without writing front and back-end glue layer code, At the same time, it ensures the type safety of the front and back end

## Enable BFF

import EnableBFF from "@site-docs-en/components/enable-bff"

<EnableBFF/>

## BFF Function

The functions that are allowed to be called through integration are called **BFF functions**. Here is the simplest BFF function to write, creating an `api/hello.ts` file:

```ts title="api/hello.ts"
export const get = async () => 'Hello Modern.js';
```

Then directly import the function in `src/App.tsx` and call:

```tsx title=src/App.tsx
import { useState, useEffect } from 'react';
import { get as hello } from '@api/hello';

export default () => {
  const [text, setText] = useState('');

  useEffect(() => {
    hello().then(setText);
  }, []);
  return <div>{text}</div>;
};
```

:::info
Modern.js generator has already configured the `@api` alias in tsconfig.json, so you can import functions directly by aliases.

:::

The functions import in `src/App.tsx` will be automatically converted into interface calls, so there is no need to call the interface through fetch.

Execute `pnpm run dev`, then open `http://localhost:8080/` to see that the page has displayed the content returned by the BFF function. In Network, you can see that the page sent a request to `http://localhost:8080/api/hello`.

![Network](https://p6-piu.byteimg.com/tos-cn-i-8jisjyls3a/fd41750f8d414179a9b4ecb519919b36~tplv-8jisjyls3a-3:0:0:q75.png)

## API Routes

In Modern.js, the BFF function routing system is implemented based on the file system, and it is also a conventional routing system.

In **Function Mode**, All files under `api/` will map to an interface. In **Framework Mode**, All files under `api/lambda` will map to an interface

:::note
Function Mode & Framework Mode will introduce soon.

:::

All routes generated by BFF functions have a prefix, and the default value is `/api`. The prefix can be set through [bff.prefix](/configure/app/bff/prefix).

Several routing conventions are described as follow.

### Default Route

Files named `index.[jt]s` are mapped to the previous directory.

- `api/index.ts` -> `{prefix}/`
- `api/user/index.ts` -> `{prefix}/user`

### Multi-layer Routing

Supports parsing nested files, if you create a nested folder structure, the files will still automatically parse routes in the same way.

- `api/hello.ts` -> `{prefix}/hello`
- `api/user/list.ts` -> `{prefix}/user/list`

### Dynamic Routing

Create folders or files named with `[xxx]` to support dynamic named routing parameters.

- `api/user/[username]/info.ts` -> `{prefix}/user/:username/info`
- `api/user/username/[action].ts` -> `{prefix}/user/username/:action`

### Allow List

By default, all files in the'api/'directory will be parsed as BFF function files, but the following files will not be parsed:

- file name start with `_`, for example `_utils.ts`.
- files in directory which name start with `_`, for example `_utils/index.ts`、`_utils/cp.ts`.
- test files, for example `foo.test.ts`.
- type files, for example `hello.d.ts`.
- files in `node_module`.

## RESTful API

Modern.js BFF functions need to be defined according to the RESTful API standard, follow the HTTP Method specification, and do not allow free parameter definition.

:::info
Assuming that the function allows free definition of parameters, the resulting route must be called by the **private protocol** (the reason is that the request parameters cannot be distinguished from the request body), and cannot implement any RESTful API.

If the service is only used for the application itself, there is no problem. but its **non-standard interface definition** cannot be integrated into the larger system. In the case of multiple systems working together (such as BFF low-code construction), other systems also need to follow the **private protocol**.

:::

### Function Named Export

Modern.js the export name of the BFF function determines the Method of the corresponding interface of the function, such as `get`, `post` and so on.

For example, following the example, a `GET` interface can be exported.

```ts
export const get = async () => {
  return {
    name: 'Modern.js',
    desc: 'Web engineering system',
  };
};
```

Following the example below, a `POST` interface can be exported.

```ts
export const post = async () => {
  return {
    name: 'Modern.js',
    desc: 'Web engineering system',
  };
};
```

- Modern.js supports 9 definitions for HTTP Method: `GET`、`POST`、`PUT`、`DELETE`、`CONNECT`、`TRACE`、`PATCH`、`OPTIONS`、`HEAD`, can be exported using these methods as functions.

- The name is size insensitive, if `GET`, can write `get`、`Get`、`GEt`、`GET`, can be accurately identified. But default export as `export default xxx` will be map to `Get`.

- Multiple functions of different Methods can be defined in one file, but if multiple functions of the same Method are defined, only the first will take effect.

:::info
It should be noted that the defined functions should all be asynchronous, which is related to the type when the function is called, which will be mentioned later.

:::

### Function Parameter Rule

As mentioned above, in order to meet the design criteria of RESTful APIs, the BFF function in Modern.js needs to follow certain imported parameter rules.

The function parameters are divided into two parts, the dynamic part in the request path and the request option `RequestOption`.

#### Dynamic Path

Dynamic routing will be used as imported parameters in the first part of the function, and each imported parameter corresponds to a dynamic route. For example, in the following example, uid will be passed into the function as the first two parameters:

```ts title="api/[level]/[id].ts"
export default async (level: number, id: number) => {
  const userData = await queryUser(level, uid);
  return userData;
};
```

Pass dynamic parameters directly when calling:

```ts title="App.tsx"
import { useState, useEffect } from 'react';
import { get as getUser } from '@api/[level]/[id]';

export default () => {
  const [name, setName] = useState('');

  useEffect(() => {
    getUser(6, 001).then(userData => setName(userData.name));
  }, []);

  return <div>{name}</div>;
};
```

#### RequestOption

The parameter after Dynamic Path is the object `RequestOption` containing querystring and request body, which is used to define the types of `data` and `query`.

In normal functions without dynamic routing, the incoming `data` and `query` can be obtained from the first imported parameter, for example:

```ts title="api/hello.ts"
import type { RequestOption } from '@modern-js/runtime/server';

export async function post({
  query,
  data,
}: RequestOption<Record<string, string>, Record<string, string>>) {
  // do somethings
}
```

When a function file uses dynamic routing rules, dynamic routing before the `RequestOption` parameter.

```ts title="api/[sku]/[id]/item.ts"
export async function post(
  sku: string,
  id: string,
  {
    data,
    query,
  }: RequestOption<Record<string, string>, Record<string, string>>,
) {
  // do somethings
}
```

Also pass in the parameters according to the function definition:

```ts title="App.tsx"
import { post } from '@api/[sku]/[id]/item';

export default () => {
  const addSku = () => {
    post('0001' /* sku */, '1234' /* id */, {
      query: {
        /* ... */
      },
      data: {
        /* ... */
      },
    });
  };

  return <div onClick={addSku}>添加 SKU</div>;
};
```

As mentioned earlier, the defined functions should be asynchronous because they are automatically converted to HTTP interface calls when called by the front end.

so in order to keep the type definition consistent with the actual calling, it is necessary to set the BFF function to asynchronous when defining it.
