POSTメソッドを叩いたらエラーが出た

NestJSで作成したAPILambdaに乗せAPI Gatewayでエンドポイントを作成した。

フロントエンドはNextJSで作成し、Vercelにデプロイした。

で、無事画面表示とGetが成功し、得たいデータが表示された。

ただPOST APIを叩いた時

Access to fetch at 'https://xxxxxx.amazonaws.com/api/v1/login' from origin 'https://xxxxxxx.vercel.app' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

というエラーがでた。

CORSは有効にしている

上のエラーを読む限り、CORSに関するエラーということがわかる。

ただNestJSの方でCORSは有効にしている。

該当のソースは下記の通り。

  const app = await NestFactory.create(AppModule);
  await app.init();

  app.useGlobalPipes(new ValidationPipe());
  app.useGlobalFilters(new HttpExceptionFilter());

  // CORSの有効化
  app.enableCors();

  const expressApp = app.getHttpAdapter().getInstance();
  return serverlessExpress({ app: expressApp });

Getはできているし、CORSもきっと有効に出来ているに違いない。

じゃあ、なんでPOSTはできないの?

沼に落ちた。

解決方法

ちなみに同じ状況に陥った人のために先に解決方法を載せておくと、下記のようにawait app.init();の位置が肝だった。

const app = await NestFactory.create(AppModule);
app.enableCors()
app.useGlobalPipes(new ValidationPipe());
app.useGlobalFilters(new HttpExceptionFilter());
await app.init();
const expressApp = app.getHttpAdapter().getInstance();
return serverlessExpress({ app: expressApp });

理由はいまいちわからないので、ここには記載しない。

ここに至るまでの道のり(読むかは自己判断で)

上記の通りで解決するので後はただの蛇足。

ただ自分がどのように解決に至ったかをログとして残しておく。

見る価値があるかはわからない。

API GatewayでCORSを設定する

AWSのほうでも同様にCORSを設定する必要があるのか? という思いで設定した。

API Gateway > CORSで設定にいき、下記の通り設定した。

Access-Control-Allow-Origin*
Access-Control-Allow-Headerscontent-type,authorization
Access-Control-Allow-MethodsGET,POST,PUT,DELETE,OPTIONS

がエラーが変わらないので、ReactからCognitoで認証認可されたAPI Gatewayを呼び出すを参考に下記の通り変更した。

Access-Control-Allow-Originhttps://vote-for-name.vercel.app
Access-Control-Allow-Headerscontent-type,authorization
Access-Control-Allow-Methods*
Access-Control-Max-Age-1秒
Access-Control-Allow-Credentialstrue

に変更したが意味がなかった。

※ てかNestJSでCORSを設定しなくてもここで設定できる?(未確認)それならソースビルドしなくていいので負担が減りそう。いつか試してみたい。

## NestJS側でCORS有効化の書き方を変更してみる

  const app = await NestFactory.create(AppModule);
  await app.init();

  app.useGlobalPipes(new ValidationPipe());
  app.useGlobalFilters(new HttpExceptionFilter());

 app.use((req: any, res: any, next: any) => {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Headers', 'Content-Type,  Authorization');
    res.header('Access-Control-Allow-Methods', '*');
    next();
  });

  const expressApp = app.getHttpAdapter().getInstance();
  return serverlessExpress({ app: expressApp });

にしたみたけど変わらず、エラーが出続ける。

そもそも

 app.use((req: any, res: any, next: any) => {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Headers', 'Content-Type,  Authorization');
    res.header('Access-Control-Allow-Methods', '*');
    next();
  });

これを追加した時点で、

 app.enableCors()

を削除してるけど、これも必要なんじゃないかということで復活してみる。

が、変わらず無理のまま。

エラーでpreflightがどうこう言っているので、

if ('OPTIONS' == req.method) {
    res.send(204);
}
else {
    next();
}

CORS “It does not have HTTP ok status.”上記を追加してみた。

ができない。

同様に、上記サイトを参考にapp.options('*', cors())を追加し見たが、そんな型存在しないともっと前の段階で怒られた。

Githubで他の人のソースを探る

どうやら順番が違うことに気が付いて無事解決。

諦めずに取り組んで良かった。