Configuration

Agrume is designed to be as simple as possible. It doesn’t need any configuration to work. However, you can configure it to suit your needs.

prefix

By default, Agrume will prefix all your routes with /api. You can change this prefix by passing the prefix option to the plugin:

// ...

export default defineConfig({
  plugins: [
    agrume({
      prefix: '/my-api/'
    })
    // ...
  ]
})

baseUrl

By default, Agrume will make requests to the same host as the frontend. However, you can change this by passing the baseUrl option to the plugin:

// ...

export default defineConfig({
  plugins: [
    agrume({
      baseUrl: 'http://localhost:3000/'
    })
    // ...
  ]
})

Note

It can be useful if you host your frontend and backend on different servers or different processes.

Note

The difference between prefix and baseUrl is that prefix will impact both the transformation step (the frontend) and the registration step (the backend), while baseUrl will only impact the transformation step (the frontend).

useMiddleware

By default, Agrume will use the Vite server to serve your API. However, you can use your own server by passing the useMiddleware option to the plugin:

// ...
import { server } from './server'

export default defineConfig({
  plugins: [
    agrume({
      useMiddleware: server.use.bind(server),
    })
    // ...
  ]
})

The useMiddleware option takes a function that takes a Connect-like middleware as an argument. Here is an example of a Connect-like server:

import { createServer } from "node:http"
import connect from "connect"

const app = connect()
const server = createServer(app)

server.listen(3000)

export { app as server }

Many backend frameworks can use Connect-like middleware. For example, Express can use Connect-like middleware. You can use it as a server:

import express from 'express'

const app = express()
const server = app.listen(3000)

export { app as server }

But please, don’t use Express. See “Why you should drop ExpressJS” by Romain Lanz.

logger

By default, Agrume does not log anything. However, you can pass a logger to the plugin to log the requests:

// ...

export default defineConfig({
  plugins: [
    agrume({
      logger: {
        info: console.info,
        error: console.error,
      }
    })
    // ...
  ]
})

You can use fs.writeFileSync instead of console.log to log the requests to a file.

// ...

export default defineConfig({
  plugins: [
    agrume({
      logger: {
        info: (...args) => fs.writeFileSync('info.log', args.join(' ') + '\n', { flag: 'a' }),
        error: (...args) => fs.writeFileSync('error.log', args.join(' ') + '\n', { flag: 'a' }),
      }
    })
    // ...
  ]
})

tunnel

Agrume has built-in support for tunnels. You can opt-in to use a tunnel by passing the tunnel option to the plugin:

// ...

export default defineConfig({
  plugins: [
    agrume({
      tunnel: { type: 'Bore', connectionArgs: {} }
    })
    // ...
  ]
})

Note

You may want to use the Agrume CLI to start the tunnel easily. See the CLI section.

ngrok

Ngrok is the most popular of all the options. However, it have some prerequisites:

  1. Create an account on ngrok.com.
  2. Go to the auth token page and copy your auth token.
  3. Set the NGROK_AUTHTOKEN environment variable to your auth token.
echo "export NGROK_AUTHTOKEN=your-auth-token" >> ~/.zshrc # or ~/.bashrc or any other shell configuration file
  1. Create a free static subdomain on ngrok.com.
  2. Set the ngrokDomain option to your subdomain.

        1. with the CLI:

agrume --tunnel ngrok --ngrok-domain your-subdomain

        2. with the plugin:

// ...
export default defineConfig({
  // ...
  tunnel: {
    type: 'Ngrok',
    connectionArgs: {
      accessToken: process.env.NGROK_AUTHTOKEN, // This is optional, it will use the NGROK_AUTHTOKEN environment variable by default.
    },
    tunnelDomain: 'your-ngrok-domain',
  }
})

pinggy

Pinggy is a stable and cheaper alternative to Ngrok.

  1. Create an account on pinggy.io.
  2. Go to the subscriptions page and upgrade to a paid plan (3$/month).
  3. Go to the subdomains page and create a static subdomain.
  4. Set the pinggySubdomain and pinggyToken options to your subdomain and your token.

        1. with the CLI:

agrume --tunnel pinggy --pinggy-subdomain your-subdomain --pinggy-token your-token

Note

Ideally, you should set the PINGGY_TOKEN environment variable to your token and use this variable in the command.

        2. with the plugin:

// ...
export default defineConfig({
  // ...
  tunnel: {
    type: 'Pinggy',
    connectionArgs: {
      accessToken: process.env.PINGGY_TOKEN,
    },
    tunnelSubdomain: 'your-subdomain',
  },
})

bore

Bore is a free and open-source tunnel. However, it doesn’t support HTTPS and works with ports (anybody can reserve a port, so the determined URL can be taken by someone else).

  1. Install the bore CLI (read the installation instructions).
  2. Use bore as the tunnel type.

localtunnel

Localtunnel is a free and open-source tunnel. However, the service is not very stable. It doesn’t need any installation.

  1. Use localtunnel as the tunnel type.

getClient

By default, Agrume will use the client written at packages/client/src/get-client.ts. However, you can pass your own client to the plugin:

export default defineConfig({
  plugins: [
    agrume({
      getClient: (requestOptions) => {
        // Your client
      }
    })
    // ...
  ]
})

If you want to modify the type of the client compared to the default client, you can do as follows:

// ...
import type { createRoute } from 'agrume'
import type { AnyRoute, RequestOptions, RouteTypes } from '@agrume/types'

function getClient<RT extends RouteTypes<AnyRoute>>(
  requestOptions: RequestOptions,
  _?: RT
) {
  type Parameters = createRoute.Helpers.InferRouteTypes.Parameters<RT> // you can modify the parameters your client will take (for example, add a token parameter)
  // For example, if you want to add a token parameter:
  // type Parameters = [...createRoute.Helpers.InferRouteTypes.Parameters<RT>, { token: string }]

  type ReturnType = createRoute.Helpers.InferRouteTypes.ReturnType<RT> // you can modify the return type of your client
  return async (...parameters: Parameters): Promise<ReturnType> => {
    // Your client
  }
}

export default defineConfig({
  plugins: [
    agrume({
      getClient,
    }),
    // ...
  ]
})

declare module '@agrume/types' {
  export interface CustomClient<R> {
    getClient: typeof getClient<RouteTypes<R>>
  }
}

Important

Make sure that the declare module is in a file included in your tsconfig.json. If you don’t want to include your build tool’s configuration file, you can put the getClient and the declare module in a separate file that is included in your tsconfig.json.