deno
axios
mongoDB
error log

에러로그: deno, axios, mongoDB 에러 미제사건 왜 mongoDB는 POST만 허용하는가?

deno 런타임에서 axios로 mongoDB랑 통신하는데 에러가 계속됩니다. mongoDB API 문서를 잘 숙지하지 않고 있어서 발생하는 문제 같습니다.

문제: 튜토리얼 보고 배우기

  • flash-card-backend 프로젝트를 진행하는 중간 발생했습니다.
  • deno 런타임에서 mongoDB 통신하는데 axios가 작동하지 않습니다.
    • 특이하게 post 요청에는 문제가 없습니다.
    • 하지만 get 요청은 정상동작하지 않습니다.
  • Getting Started with Deno & MongoDB - MongoDB 이 튜토리얼을 보고 따라 했습니다. 여기서는 모든 요청이 post이고 fetch로 통신했습니다.
    • 가독성이 너무 떨어지는 코드였습니다. 그래서 axios를 싱글튼 패턴으로 만들어서 DB에 요청하도록 변경을 시도하고 있었습니다.

시도: axios 싱글튼

전체 코드

import { config } from 'https://deno.land/x/dotenv@v3.2.2/mod.ts';
import axios from 'https://deno.land/x/redaxios@0.5.1/mod.ts';

// axios 싱글튼
const { APP_ID, CARD_API_KEY } = config();
const baseURL = `https://us-west-2.aws.data.mongodb-api.com/app/${APP_ID}/endpoint/data/v1/action`; // /action

type Card = {
  question: string;
  answer: string;
  submitDate: string;
  stackCount: number;
};

class AxiosAPI {
  private static instance: AxiosAPI;
  private axiosConfig;
  private query: {
    dataSource: string;
    database: string;
    collection: string;
    document?: Card;
  };

  private constructor() {
    this.axiosConfig = axios.create({
      baseURL,
      headers: {
        'Content-Type': 'application/json',
        'api-key': CARD_API_KEY,
      },
      method: 'POST',
    });
    this.query = {
      dataSource: 'Cluster0',
      database: 'cards_db',
      collection: 'cards',
    };
  }

  static getInstance(): AxiosAPI {
    if (!AxiosAPI.instance) {
      AxiosAPI.instance = new AxiosAPI();
    }
    return AxiosAPI.instance;
  }

  async getCards() {
    const body = JSON.stringify({});
    return await this.axiosConfig.post('/find', {
      body: JSON.stringify({
        dataSource: 'Cluster0',
        database: 'cards_db',
        collection: 'cards',
      }),
    });
  }

  async postCards(payload: Card) {
    this.query.document = payload;
    return await this.axiosConfig.post('/insertOne', this.query);
  }

  async patchCards() {}
  async deleteCards() {}
  async singin() {}
  async singup() {}
}

const axiosLog = AxiosAPI.getInstance();

try {
  console.log(await axiosLog.getCards());
} catch (error) {
  console.log(error);
}

export default AxiosAPI;

이것이 전체 코드입니다.

반환하는 에러 메시지는 다음입니다.

"Invalid parameter(s) specified: body"

요청을 보낼 때 body 문제라는 것은 파악할 수 있습니다. 하지만 body에 어떻게 변형해도 답을 얻을 수 없었습니다.

해결: fetch 싱글튼

import { config } from 'https://deno.land/x/dotenv@v3.2.2/mod.ts';
import CardRecord from '../model/cards.ts';

const { APP_ID, CARD_API_KEY } = config();

class MongoAPI {
  private static instance: MongoAPI;
  private baseURL: string;
  private options: {
    method: string;
    headers: { 'Content-Type': string; 'api-key': string };
    body: BodyInit;
  };
  private constructor() {
    this.baseURL = `https://us-west-2.aws.data.mongodb-api.com/app/${APP_ID}/endpoint/data/v1/action`;
    this.options = {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'api-key': CARD_API_KEY,
      },
      body: JSON.stringify({
        dataSource: 'Cluster0',
        database: 'cards_db',
        collection: 'cards',
      }),
    };
  }

  static getInstance(): MongoAPI {
    if (!MongoAPI.instance) {
      MongoAPI.instance = new MongoAPI();
    }
    return MongoAPI.instance;
  }

  async getCards() {
    return await fetch(`${this.baseURL}/find`, this.options);
  }

  async postCards(document: CardRecord) {
    return await fetch(`${this.baseURL}/insertOne`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'api-key': CARD_API_KEY,
      },
      body: JSON.stringify({
        dataSource: 'Cluster0',
        database: 'cards_db',
        collection: 'cards',
        document,
      }),
    });
  }
}

const mongoAPI = MongoAPI.getInstance();

try {
  const card = new CardRecord(
    '순수 함수를 활용합니다.',
    '부작용이 없습니다.',
    new Date(),
    2,
    '1',
    '646a089f1c75ae5b5752d35d'
  );
  console.log(await mongoAPI.patchCards(card));
} catch (error) {
  console.log(error);
}

export default MongoAPI;
  • fetch로 다시 작성해보니까 모두 정상동작했습니다.
  • MongoDB에는 POST가 기본인 것 같습니다.
  • 다른 PATCH, DELETE 동작이 POST로 설정하면 모두 동작했습니다.

학습: 왜 Post인가?

  • mongoDB를 fetch로 요청할 때는 모든 것이 Post입니다.
    • 의문인 것은 왜 모든 요청이 Post인가? 아직 답을 모르겠습니다.