lil.dev
Published on

๐ŸŽ‰ ์ปฌ๋Ÿฌ๋ฆฌ์ŠคํŠธ ํ”„๋กœ์ ํŠธ #9 api ์š”์ฒญ ํ™•์ธ

๊ธ€์“ด์ด

    ๐Ÿ“Œ ๋ชฉ์ฐจ

    Welcome

    โœจ ์ปฌ๋Ÿฌ๋ฆฌ์ŠคํŠธ ์‚ฌ์ดํŠธ(์•„์ง ์—†์Œ

    ๐Ÿ’๐Ÿป

    1. TestForm์—์„œ article์„ form์œผ๋กœ ๊ฐ์‹ธ๊ธฐ
    2. Pallete.tsx์—์„œ button ํƒ€์ž… button์œผ๋กœ ์„ค์ •
    3. input์— ์„œ๋ฒ„์—์„œ ์ •ํ•ด์ค€ name, type ์„ค์ •
    4. data ์ „์ฒ˜๋ฆฌ ํ”„๋กœ์„ธ์‹ฑ
    5. type assumption - global.d.ts
    6. api.ts๋ฅผ ๋งŒ๋“ค์–ด postํ•จ์ˆ˜๋ฅผ ์บก์Šํ™”ํ•˜๊ธฐ

    1. TestForm์—์„œ article์„ form์œผ๋กœ ๊ฐ์‹ธ๊ธฐ

    TestForm์—์„œ ์ž…๋ ฅํ•˜๋Š” ๊ฐ’๋“ค์„ ํ•œ๋ฒˆ์— ๋ณด๋‚ด์ฃผ๊ธฐ ์œ„ํ•ด form์œผ๋กœ TestForm์•ˆ์˜ ์š”์†Œ๋“ค์„ ๊ฐ์‹ธ์ค๋‹ˆ๋‹ค.

    <form
            onSubmit={(event) => {
              event.preventDefault();
              const rawData = new FormData(event.target as HTMLFormElement);
    
              const colors = rawData.get("colors");
              if (colors !== null) {
                // ์ „์ฒ˜๋ฆฌ, preprocess
                const data = [
                  {
                    jubogang: {
                      ju: rawData.get("ju"),
                      bo: rawData.get("bo"),
                      gang: rawData.get("gang"),
                    },
                    box: JSON.parse(colors as string),
                    answer: rawData.get("answer"),
                  },
                ];
                saveColors(data as MyColors[]);
              }
            }}
          >
    

    2. Pallete์—์„œ button์„ ๋ˆŒ๋ €์„๋•Œ ๋ฐ”๋กœ ์ œ์ถœ๋˜์ง€ ์•Š๋„๋ก type์„ button์œผ๋กœ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค.

    ;<Tabs.List aria-label="select pallete type">
      {/* ํŒ”๋ ˆํŠธ์˜ ํƒ€์ž…๋งˆ๋‹ค Tabs.Trigger๋ฅผ ๋งŒ๋“ค์–ด์ค€๋‹ค*/}
      {palleteTypes.map((value) => (
        <Tabs.Trigger key={value} value={value} className="bg-yellow-200" type="button">
          {value}
        </Tabs.Trigger>
      ))}
    </Tabs.List>
    {
      /* ["base", "deep"]*/
    }
    {
      /* ํŒ”๋ ˆํŠธ์˜ ํƒ€์ž…๋งˆ๋‹ค Tabs.Content๋ฅผ ๋งŒ๋“ค์–ด์ค€๋‹ค*/
    }
    {
      palleteTypes.map((value) => (
        <Tabs.Content key={value} value={value}>
          <div id="pallete" className="flex flex-row flex-wrap">
            {/* 4๋ฒˆ - pallete๋„ ๊ฐ’์ด ์—ฌ๋Ÿฌ ๊ฐœ์ด๋ฏ€๋กœ map์„ ์‚ฌ์šฉํ•œ๋‹ค. */}
            {allPallete[value].map(({ hex, colorName }, index) => (
              <Tooltip.Root>
                <Tooltip.Trigger asChild>
                  <button
                    type="button"
                    key={index}
                    onClick={() => addSelected(hex)}
                    className="roundButton"
                    style={{ backgroundColor: hex }}
                  >
                    {colorName}
                  </button>
                </Tooltip.Trigger>
                <Tooltip.Content className="tooltip-content">
                  {hex}
                  <Tooltip.Arrow className="tooltip-arrow" width="20" height="10" />
                </Tooltip.Content>
              </Tooltip.Root>
            ))}
          </div>
        </Tabs.Content>
      ))
    }
    

    3. ์„œ๋ฒ„ api ์Šคํ‚ค๋งˆ์—์„œ ์ •ํ•ด์ค€๋Œ€๋กœ TestForm์—์„œ input์—๋Š” type,name์„ textarea์—๋Š” name์„ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค.

    <p id="allColor">์ฃผ๋ณด๊ฐ• ๊ธฐ์ž…</p>
            <label className="color-label" htmlFor="main-color">
              ์ฃผ์กฐ์ƒ‰
            </label>
            <input
              id="color-selection"
              placeholder="์ฃผ์กฐ์ƒ‰:"
              value={mainColor}
              // change event์˜ target์ธ textarea์˜ ์ƒˆ๋กœ ๋ณ€๊ฒฝ๋œ ๊ฐ’์„
              // react์˜ mainColor ์ƒํƒœ์— ์„ธํŒ…
              // ๊ฐ’์„ ๋™๊ธฐํ™”ํ•ด์ฃผ๋Š” ๊ฑฐ์—์š”.
              // https://beta.reactjs.org/learn/reacting-to-input-with-state
              onChange={(event) => setMainColor(event.target.value)}
            />
            <label className="color-label" htmlFor="sub-color">
              ๋ณด์กฐ์ƒ‰
            </label>
            <input
              id="color-selection"
              placeholder="๋ณด์กฐ์ƒ‰:"
              value={subColor}
              onChange={(event) => setSubColor(event.target.value)}
            />
            <label className="color-label" htmlFor="point-color">
              ๊ฐ•์กฐ์ƒ‰
            </label>
            <input
              id="color-selection"
              placeholder="๊ฐ•์กฐ์ƒ‰:"
              value={pointColor}
              onChange={(event) => setPointColor(event.target.value)}
            />
            <label className="color-label" htmlFor="explanation" id="explanation">
              ๋ฐฐ์ƒ‰ ์„ค๋ช…
            </label>
            <textarea
              id="explanation"
              placeholder={"์ปจ์…‰:\n์ฃผ์กฐ์ƒ‰:\n๋ณด์กฐ์ƒ‰:\n๊ฐ•์กฐ์ƒ‰:\n๋ฐฐ์ƒ‰ ๊ธฐ๋ฒ•:"}
              value={explanation}
              onChange={(event) => setExplanation(event.target.value)}
            />
            <p id="allColor">์ฃผ๋ณด๊ฐ• ๊ธฐ์ž…</p>
            <label className="color-label" htmlFor="main-color">
              ์ฃผ์กฐ์ƒ‰
            </label>
            <input
              id="color-selection"
              type="text"
              name="ju"
              placeholder="์ฃผ์กฐ์ƒ‰:"
              value={mainColor}
              onChange={(event) => setMainColor(event.target.value)}
            />
            <label className="color-label" htmlFor="sub-color">
              ๋ณด์กฐ์ƒ‰
            </label>
            <input
              id="color-selection"
              type="text"
              name="bo"
              placeholder="๋ณด์กฐ์ƒ‰:"
              value={subColor}
              onChange={(event) => setSubColor(event.target.value)}
            />
            <label className="color-label" htmlFor="point-color">
              ๊ฐ•์กฐ์ƒ‰
            </label>
            <input
              id="color-selection"
              type="text"
              name="gang"
              placeholder="๊ฐ•์กฐ์ƒ‰:"
              value={pointColor}
              onChange={(event) => setPointColor(event.target.value)}
            />
            <label className="color-label" htmlFor="explanation" id="explanation">
              ๋ฐฐ์ƒ‰ ์„ค๋ช…
            </label>
            <textarea
              id="explanation"
              name="answer"
              placeholder={"์ปจ์…‰:\n์ฃผ์กฐ์ƒ‰:\n๋ณด์กฐ์ƒ‰:\n๊ฐ•์กฐ์ƒ‰:\n๋ฐฐ์ƒ‰ ๊ธฐ๋ฒ•:"}
              value={explanation}
              onChange={(event) => setExplanation(event.target.value)}
            />
    
    

    4. data ์ „์ฒ˜๋ฆฌ ํ”„๋กœ์„ธ์‹ฑ

    FormData๋ฅผ rawData๋กœ ๊ฐ€์ ธ์™€์„œ
    ๋ฐฑ์—”๋“œ ์„œ๋ฒ„์— ๊ฐ€์ ธ๊ฐˆ ํฌ๋งท์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์ฒ˜๋ฆฌ ํ”„๋กœ์„ธ์‹ฑํ•ด์„œ data์— ๋„ฃ์–ด์ค๋‹ˆ๋‹ค.

    const rawData = new FormData(event.target as HTMLFormElement)
    
    const colors = rawData.get('colors')
    if (colors !== null) {
      // ์ „์ฒ˜๋ฆฌ, preprocess
      const data = [
        {
          jubogang: {
            ju: rawData.get('ju'),
            bo: rawData.get('bo'),
            gang: rawData.get('gang'),
          },
          box: JSON.parse(colors as string),
          answer: rawData.get('answer'),
        },
      ]
      saveColors(data as MyColors[])
    }
    

    5. type assumption - global.d.ts

    form์— ๊ฐ€์ ธ๊ฐˆ ๋ฐ์ดํ„ฐ type๋“ค์€ ์—ฌ๋Ÿฌ ํŒŒ์ผ์— ์“ฐ์ด๋ฏ€๋กœ global.d.tsํŒŒ์ผ์— type์„ ์„ค์ •ํ•ด์ค๋‹ˆ๋‹ค.

    type MyColors = {
      jubogang: {
        ju: string
        bo: string
        gang: string
      }
      box: Array<{ color: string; width: number }>
      answer: string
    }
    

    6. api.ts๋ฅผ ๋งŒ๋“ค์–ด postํ•จ์ˆ˜๋ฅผ ์บก์Šํ™”ํ•˜๊ธฐ

    ์„œ๋ฒ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด์ฃผ๊ธฐ์œ„ํ•ด api.ts๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

    ์„œ๋ฒ„์—์„œ ๋ฐ›์„ ์ฃผ์†Œ๋ฅผ Host๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

    const HOST = 'http://localhost:8000'
    

    ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๋Š” ํ•จ์ˆ˜ saveColors๋ฅผ ๋งŒ๋“ค์–ด exportํ•ด์ค๋‹ˆ๋‹ค.

    export function saveColors(data: MyColors[]) {
      return post('/colors', data)
    }
    

    ์—ฌ๊ธฐ์— ํฌํ•จ๋˜๋Š” postํ•จ์ˆ˜๋Š” ๋‹ค๋ฅธ ํ•จ์ˆ˜์—๋„ ์“ฐ์ผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋”ฐ๋กœ ๋–ผ์–ด ์ถ”์ƒํ™”, ์บก์Šํ™”ํ•ด์ค๋‹ˆ๋‹ค.

    function post<T>(path: string, data: T) {
      return fetch(HOST + path, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(data),
      })
    }
    

    ์ด๋ ‡๊ฒŒ ํ•จ์ˆ˜๋ฅผ ์บก์Šํ™”ํ•ด์ค„ ๊ฒฝ์šฐ

    1. ์“ฐ๊ธฐ ์‰ฝ๋‹ค
    2. ๋‚˜์ค‘์— ๊ต์ฒดํ•˜๊ธฐ ์‰ฝ๋‹ค
    3. ์‹ค์ˆ˜ํ•˜๊ธฐ ์–ด๋ ต๋‹ค ๋Š” ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.