superfaceai / one-sdk-js

1️⃣ One Node.js SDK for all the APIs you want to integrate with
https://superface.ai
MIT License
46 stars 3 forks source link

[Compat] OneSDK fails to read .supr file with Next.js serverless functions on Vercel #209

Open jnv opened 2 years ago

jnv commented 2 years ago

This was originally reported on Discord server by Petr.

Expected Behavior

When using OneSDK in Next.js with API routes, I expect for them to work without any problem wherever I deploy the application, especially to Vercel.

Current Behavior

SDK throws an exception during initialization:

File referenced in super.json not found: /var/task/superface/grid/weather/current-city@1.0.2.supr

Possible Solution

Next.js on Vercel doesn't allow importing of files per documentation.

Possible workarounds include moving the API route from /pages/api to /api so it is executed in Node.js runtime (and hence not a subject to the bundling), but there may be other solutions as well.

Steps to Reproduce

Here is repro project: https://github.com/jnv/one-sdk-nextjs-vercel-repro It's a vanilla Next.js project with OneSDK and the additional /api/weather route (see here).

The route can be executed here: https://one-sdk-nextjs-vercel-repro.vercel.app/api/weather An error is thrown instead of successful perform.

Your Environment

freaz commented 2 years ago

Next.js supports output file tracing, which does static analysis of the code and includes files that are used.

Next.js uses for it https://github.com/vercel/nft, so we can look if we can refactor code to get data caught, but from dynamism of the configuration, it might be tough task.

This is where profiles and it's ASTs are loaded.

jnv commented 1 year ago

Update on the current status: OneSDK now works on Vercel with changes in v2.0, because we don't rely on access to local .supr files anymore.

However if you use superface/super.json file, it won't be included in the bundle by default, you must import it manually and pass it to OneSDK constructor:

import { SuperfaceClient } from '@superfaceai/one-sdk';
import superJson from './path/to/superface/super.json';

const sdk = new SuperfaceClient({
  superJson,
});

Furthermore, this only works for profiles published to registry, local .supr and .suma files are still not included (Vercel has no idea how to extract these from super.json). I'm trying a workaround for that.

jnv commented 1 year ago

I've tried to trick the underlying @vercel/nft package to include the whole superface/ directory. Good news is, that this can be easily done by putting readdir call into the code – it doesn't even need to be called. So I wrapped SDK into a stand-alone module in the root of my project like this:

import { SuperfaceClient } from '@superfaceai/one-sdk';
import { readdir } from 'fs';
import { resolve } from 'path';
import superJson from './superface/super.json';

const SUPERFACE_PATH = resolve(__dirname, 'superface');

// Trick @vercel/nft to include the whole superface/ dir
function noop() {
  try {
    readdir(SUPERFACE_PATH);
  } catch (e) {}
}

let sdk;

function getSdk() {
  if (sdk) {
    return sdk;
  }
  sdk = new SuperfaceClient({
    superJson,
    superfacePath: resolve(SUPERFACE_PATH, 'super.json'),
  });
  return sdk;
}

export default getSdk;

I've verified that this works by checking nft.json files in the output and also with the standalone option I saw superface directory in the standalone output. However, after deployment to Vercel I'm getting .supr extension found. error. I suspect the superface/ folder isn't included in the deployment in the end, and at this point I ran out of ideas.

Here is my test project if you'd like to play with it.