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

# Writing APIs

> How to create API endpoints using Stormkit. API endpoints will be deployed to AWS Lambda.

## Overview

You can create Node.js/TypeScript APIs using Stormkit. During deployment, your API functions are automatically packaged and deployed to AWS Lambda with filesystem-based routing.

<Frame>
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/stormkit-io-stormkit-io/assets/docs/features/api-hello-world.gif" alt="API Hello World example" />
</Frame>

<Info>
  Function timeouts are set at 15 seconds by default. If you require a different timeout, please inform us, and we can adjust it to suit your workflow.
</Info>

## How It Works

During build time, Stormkit:

1. Checks if there is a `.stormkit/api` folder
2. When found, uploads the folder to a Lambda function
3. The [entry file](https://github.com/stormkit-io/serverless/blob/main/src/utils/callbacks/api.ts#L44) takes the `Request` and calls the relevant file based on filesystem routing
4. Returns 404 if no matching route is found

## Write and Deploy Your API

<Steps>
  <Step title="Create API directory">
    Create an `/api` folder in the top level of your repository
  </Step>

  <Step title="Create endpoint file">
    Create an `/index.ts` file in the `/api` folder
  </Step>

  <Step title="Export handler function">
    Each file must export a default function with the signature shown below
  </Step>

  <Step title="Deploy">
    Deploy your application. Stormkit will automatically build and deploy your API
  </Step>
</Steps>

### Basic Example

```typescript api/index.ts theme={null}
import http from 'http'

export default (req: http.IncomingMessage, res: http.ServerResponse) => {
  res.write('Function endpoint: /api')
  res.end()
}
```

```typescript api/user/subscribe.ts theme={null}
import http from 'http'

export default (req: http.IncomingMessage, res: http.ServerResponse) => {
  res.write('Function endpoint: /api/user/subscribe')
  res.end()
}
```

## Filesystem Routing

The table below shows how the API routing works:

```
+ /api
  - index.ts        // /api
  + /users
    - index.ts      // /api/users
    - subscribe.ts  // /api/users/subscribe
    - create.ts     // /api/users/create
    + /[id]
      - remove.ts   // /api/users/:id/remove (where :id is a placeholder for dynamic values)
```

<Info>
  For more details on how the filesystem routing works, check the [source code](https://github.com/stormkit-io/serverless/blob/main/src/utils/filesys.ts#L32) of the matchPath function.
</Info>

Now go ahead and [deploy](/deployments/overview) your application. When Stormkit detects an `/api` source folder, it checks whether it is already built or not. If the `/api` folder is not yet built, Stormkit tries to build your API using Webpack and then deploys the output to the lambda function. This process is automatic.

## Routing Features

### Dynamic Routes

Use square brackets for dynamic segments:

```
/api/users/[id]/index.ts       // Matches /api/users/123
/api/posts/[slug]/comments.ts  // Matches /api/posts/hello-world/comments
```

```typescript api/users/[id]/index.ts theme={null}
import http from 'http'

export default (req: http.IncomingMessage, res: http.ServerResponse) => {
  // Extract ID from URL
  const id = req.url?.split('/')[3]; // /api/users/:id
  res.write(`User ID: ${id}`)
  res.end()
}
```

### Matching by Request Method

By default, files are matched through all requests. If you want to restrict certain endpoints with a request method, you can specify the method in the file name, right before the extension:

```
+ /api
  - index.ts            // ALL /api
  + /users
    - index.get.ts      // GET /api/users
    - index.post.ts     // POST /api/users
    - subscribe.ts      // ALL /api/users/subscribe
    + /[id]
      - index.delete.ts // DELETE /api/users/:id
```

<CardGroup cols={2}>
  <Card title="GET Requests" icon="arrow-down">
    `index.get.ts` - Only handles GET requests
  </Card>

  <Card title="POST Requests" icon="arrow-up">
    `index.post.ts` - Only handles POST requests
  </Card>

  <Card title="PUT Requests" icon="pen">
    `index.put.ts` - Only handles PUT requests
  </Card>

  <Card title="DELETE Requests" icon="trash">
    `index.delete.ts` - Only handles DELETE requests
  </Card>
</CardGroup>

### Ignore Certain Files

If a file name starts with an underscore (`_`), the file won't be matched. If the directory starts with an underscore (`_`), the whole subdirectory tree will be ignored. This is useful to organize helper methods in different files.

```
+ /api
  - index.ts
  - _helpers.ts          // Ignored
  + /_utils              // Entire directory ignored
    - validation.ts
    - auth.ts
  + /users
    - index.ts
    - _user-model.ts     // Ignored
```

## Working with Request Data

### Reading Request Body

```typescript api/users/create.post.ts theme={null}
import http from 'http'

export default (req: http.IncomingMessage, res: http.ServerResponse) => {
  let body = '';
  
  req.on('data', chunk => {
    body += chunk.toString();
  });
  
  req.on('end', () => {
    const data = JSON.parse(body);
    // Process data
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.write(JSON.stringify({ success: true, data }));
    res.end();
  });
}
```

### Query Parameters

```typescript api/search.ts theme={null}
import http from 'http'
import { URL } from 'url'

export default (req: http.IncomingMessage, res: http.ServerResponse) => {
  const url = new URL(req.url || '', `http://${req.headers.host}`);
  const query = url.searchParams.get('q');
  
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.write(JSON.stringify({ query }));
  res.end();
}
```

## Custom Builds

If your source code contains more complex use cases and Stormkit fails to build, you can build the source code yourself. Here's the `webpack` config Stormkit uses to build the API. You can copy this and extend it based on your needs.

```typescript webpack.config.ts theme={null}
import type { Configuration } from 'webpack'
import * as webpack from 'webpack'
import * as path from 'path'
import * as dotenv from 'dotenv'
import { glob } from 'glob'

const config: Configuration = {
  mode: 'production',
  target: 'node',

  // Iterate over the `api` subfolder and create an entry file
  // for each `.ts` file. This will tell webpack to create a bundle
  // for each function.
  entry: glob.sync('./api/**/*.{js,ts,tsx}').reduce((acc, file) => {
    acc[file.replace(/^\.?\/api\//, '').split('.ts')[0]] = file
    return acc
  }, {}),

  output: {
    filename: '[name].js',
    // Build into `.stormkit/api` - Stormkit will take care of the rest.
    path: path.resolve(__dirname, '.stormkit/api'),
    // We need to use commonjs so that webpack exports the functions.
    library: {
      type: 'commonjs',
    },
  },

  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: 'ts-loader',
        options: {
          compilerOptions: {
            noEmit: false,
          },
        },
      },
    ],
  },

  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
  },

  // Inject .env variables into the bundles.
  plugins: [
    new webpack.DefinePlugin(
      Object.keys(dotenv.config() || {}).reduce((obj, key) => {
        obj[`process.env.${key}`] = JSON.stringify(process.env[key])
        return obj
      }, {})
    ),
  ],
}

export default config
```

## Testing Locally

In order to test the API locally, install the [`@stormkit/cli`](https://www.github.com/stormkit-io/stormkit-cli) package.

<Steps>
  <Step title="Install CLI">
    ```bash theme={null}
    npm i -D @stormkit/cli
    ```
  </Step>

  <Step title="Update package.json">
    ```json package.json theme={null}
    {
      "scripts": {
        "dev:api": "stormkit api"
      }
    }
    ```
  </Step>

  <Step title="Run development server">
    ```bash theme={null}
    npm run dev:api
    ```
  </Step>

  <Step title="Access API">
    You can access the API from [http://localhost:9090/api](http://localhost:9090/api)
  </Step>
</Steps>

## API in Action

If you wish to see the API in action promptly, take a look at our [template project](https://github.com/stormkit-io/monorepo-template-react), utilizing Vite.js as the build tool. This project encapsulates server-side rendering (SSR), API functionality, and a single-page application.

## Best Practices

* **Use TypeScript** - Type safety helps catch errors early
* **Validate inputs** - Always validate request data
* **Handle errors** - Use try-catch blocks and return appropriate error codes
* **Keep functions focused** - Each endpoint should do one thing well
* **Use helper files** - Organize shared code in `_helpers.ts` files
* **Set proper headers** - Always set Content-Type and other relevant headers
* **Environment variables** - Use env vars for configuration and secrets
* **Test locally** - Use `@stormkit/cli` to test before deploying
