Nuxt.js and Vercel Functions without using `vercel dev`
Published: 2021-04-12 14:06:04

I'd recently being having issues using [Vercel's serverless functions](https://vercel.com/docs/serverless-functions/introduction) with SSG. Although I haven't been able to fix that just yet, I realised I could run vercel functions without using the dev proxy.

NOTE: I wasn't able to consistently get the correct data from the body of the request. Not sure why, but `res.read()` was skipping the first line of the request body when `toString()` was called. This means with my current code ONLY GET requests are supported. Shouldn't be hard to get it working with POST if you can spare the troubleshooting time.

## Add `@vercel/node`
You will need `@vercel/node` either globally or locally.  You don't need to use it directly, but the file we are copying will reference back to this package. 

## Nuxt `serverMiddleware` to the rescue. 
In production, Vercel uses serverless functions to handle the calls to the functions found at `/api`. These functions are not available using the standard `yarn dev`.

[serverMiddleware](https://nuxtjs.org/docs/2.x/configuration-glossary/configuration-servermiddleware/) allows any call to the dev server be intercepted. 

For us, that means allowing requests to captured and redirected to Vercel functions directly. The only issue there is pass over the request and response in a way that the functions expect. 

The `@vercel/node` package has the file `@vercel\node\dist\helpers.js` which contains the js that normally runs via the `vercel dev` command. 

## Putting it together
### `/middleware-server/vercel.ts`

`vercel.ts` is the `serverMiddleware` handler that intercepts the calls to any url under `/api`. 
The request and response have properties added to become a `VercelResponse` and a `VercelRequest`.
The api function is loaded using a require, but the require cache is cleared of the module first to make sure only the latest code is used.

```ts
// To convert to JS, remove the type imports and the type declarations
// e.g. : VercelRequest 
import { ServerMiddleware } from '@nuxt/types'
import { VercelResponse, VercelRequest, VercelApiHandler } from '@vercel/node'

const helpers = require('./helpers'); 

const vercel: ServerMiddleware = async (req, res, next) => {

    // const body = req.read(); - this should work, but it's being very strange. Leaving for now.
    const body = Buffer.from("");

    const apiNameRegex = /\/([\w-]+).*/g

    const matches = apiNameRegex.exec(req.url || "");

    if (!matches || !matches[1]) {
        res.statusCode = 404;
        res.end()
        return;
    }

    const apiName = matches[1];
    const moduleName = '../api/' + apiName;

    // allow dynamic code change reloads - possibly detect changes and remove that way
    const requestedApi = requireReload(moduleName).default as VercelApiHandler;

    const vercelRequest: VercelRequest = helpers.httpToVercelRequest(req, body);
    const vercelResponse: VercelResponse = helpers.httpToVercelResponse(req, res);

    try {
        requestedApi(vercelRequest, vercelResponse)
    } catch (err) {
        console.error(err)
        res.statusCode = 500;
        res.end()
    }
}

/// https://stackoverflow.com/a/58645175/59532
function requireReload(moduleName: string) {
    
    let mp = require.resolve(moduleName)
    if (require.cache[mp]) {
        delete require.cache[mp]
        console.log(`[clear] module: ${mp}`)
    }
    return require(moduleName);
}


export default vercel;
```

### `/middleware-server/helper.js`
`helper.js` is a copy of the file `@vercel\node\dist\helpers.js`, but some extra code at 795 to allow access to the surrounding methods. 

```ts 
// The file is a copy of @vercel\node\dist\helpers.js
// ADD THIS CODE AT LINE 795

function httpToVercelRequest (req, body) {
    setLazyProp(req, 'cookies', getCookieParser(req));
    setLazyProp(req, 'query', getQueryParser(req));
    setLazyProp(req, 'body', getBodyParser(req, body));
    return req;
  }
  
function httpToVercelResponse(req, res) {
    res.status = statusCode => status(res, statusCode);
    res.redirect = (statusOrUrl, url) => redirect(res, statusOrUrl, url);
    res.send = body => send(req, res, body);
    res.json = jsonBody => json(req, res, jsonBody);
    return res;
  }

  exports.httpToVercelRequest = httpToVercelRequest;
  exports.httpToVercelResponse = httpToVercelResponse;

```
Add the `serverMiddleware` to the `nuxt.config.js`
### `nuxt.config.js`
```ts
  // Added property:
  serverMiddleware: [
    { path: '/api', handler: '~/middleware-server/vercel' },
  ]
```

## Conclusion
When not running `vercel dev`, any calls to a url starting with `/api` should now be handled by nuxt, and will be redirected to the appropriate api function.

If running with `vercel dev`, or on a server, then the functions will be handled by `Vercel`, as it was before. 

If you are able to get the body part working, drop the solution back here. It would be interesting to see what the issue was.