Notice
Recent Posts
Recent Comments
Link
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
Tags
more
Archives
Today
Total
관리 메뉴

juni

Next.js / React ( 타입, json 응답 구조, 토큰, OAuth, postAPI, FormData, JSON 객체, expires ) 본문

CS

Next.js / React ( 타입, json 응답 구조, 토큰, OAuth, postAPI, FormData, JSON 객체, expires )

juni_shin 2024. 11. 11. 18:05
 

json 응답 구조

일반적인 응답 구조

REST API와 같은 일반적인 웹 서비스에서는 보통 다음과 같은 방식으로 응답이 이루어집니다:

  1. HTTP 상태 코드 (HTTP Status Code):
    • 클라이언트가 서버에 요청을 보내면, 서버는 응답과 함께 HTTP 상태 코드를 반환합니다.
    • 이 상태 코드는 응답의 성공 여부를 나타내며, 클라이언트는 이를 보고 요청이 성공했는지 실패했는지 판단할 수 있습니다.
    • 예시: 200 OK, 404 Not Found, 500 Internal Server Error 등.

 

  • HTTP 상태 코드는 항상 존재하지만, 이는 JSON 응답의 일부가 아니라 HTTP 응답 헤더에서 제공됩니다.
    • HTTP 응답 상태 코드(response.status)를 통해 요청 성공 여부를 확인할 수 있습니다.
  • statusCode 필드는 JSON 응답에 항상 포함되지 않으며, 서버가 이를 포함하도록 구현한 경우에만 볼 수 있습니다.

 

 

타입

1. 기본 사용 목적

  • interface: 주로 객체의 구조를 정의하는 데 사용됩니다. 객체의 프로퍼티와 그 타입을 설명할 때 많이 쓰입니다.
  • type: 객체뿐만 아니라 기본 타입(alias), 유니언(합집합), 교차 타입(교집합) 등 다양한 타입을 정의할 수 있습니다.

2. 확장성

  • interface는 확장 가능: 인터페이스는 상속을 통해 다른 인터페이스를 확장할 수 있습니다. 또한 동일한 이름의 인터페이스를 여러 번 선언하면 자동으로 병합됩니다.
interface Animal {
  name: string;
}

interface Animal {
  age: number;
}

// 위 두 개의 Animal 인터페이스가 병합됩니다.
const cat: Animal = { name: "Kitty", age: 2 };

 

  • type은 확장 불가: type은 같은 이름으로 여러 번 선언할 수 없으며, 타입 병합이 일어나지 않습니다. 대신 타입 교차(intersection types)를 사용해 확장할 수 있습니다.
type Animal = {
  name: string;
};

type Pet = Animal & {
  age: number;
};

const cat: Pet = { name: "Kitty", age: 2 };

3. 타입 정의의 범위

  • **type**은 훨씬 더 유연합니다. type으로는 유니언 타입, 튜플, 기본 타입의 별칭 등을 정의할 수 있습니다.
type StringOrNumber = string | number;  // 유니언 타입
type TupleType = [string, number];  // 튜플 타입
  • **interface**는 객체 타입을 정의하는 데 더 적합합니다. 그러나 extends를 통해 여러 인터페이스를 확장할 수 있습니다.

4. 함수 표현

두 가지 모두 함수 타입을 정의할 수 있지만, 인터페이스는 메서드 시그니처를 사용하는 반면, 타입은 함수 표현식을 사용할 수 있습니다.

// type을 사용한 함수 타입 정의
type GreetFunction = (name: string) => string;

// interface를 사용한 함수 타입 정의
interface GreetFunction {
  (name: string): string;
}

5. 선택적 사용 권장 사항

  • 인터페이스는 주로 객체의 구조를 설명할 때 권장됩니다. 객체의 모양을 정의하고 상속을 통해 확장하거나 병합을 원할 때 유용합니다.
  • 타입유연성이 더 필요한 경우 사용합니다. 기본 타입을 재정의하거나 유니언 타입, 튜플 등을 정의해야 할 때 좋습니다.

요약

  • interface: 객체의 구조를 설명하고, 상속과 병합이 가능.
  • type: 객체뿐만 아니라 유니언, 튜플, 기본 타입 등에 더 유연하게 사용 가능. 병합 불가.

 

토큰

리프레시 토큰의 역할

  • 리프레시 토큰(Refresh Token): 일반적으로 액세스 토큰이 만료되었을 때, 인증 서버에 이 토큰을 사용해 새로운 액세스 토큰을 요청하는 데 사용됩니다. 리프레시 토큰은 액세스 토큰보다 보안상 더 오래 사용할 수 있습니다.

OAuth를 통한 인증 과정에서는 액세스 토큰 외에도 다른 토큰들이 사용될 수 있습니다.

예를 들어, OAuth에서는:

  • 액세스 토큰: 사용자의 인증 상태를 증명하고, 리소스에 접근할 수 있는 권한을 부여하는 토큰.
  • 리프레시 토큰: 만료된 액세스 토큰을 갱신하는 데 사용되는 토큰.
  • ID 토큰: 사용자의 식별 정보를 포함하는 토큰 (보통 OpenID Connect에서 사용).

따라서 additional_token은 이 과정에서 발급된 추가적인 인증 토큰일 수 있습니다. 예를 들어, OAuth 서버에서 발급된 추가적인 자격 증명이거나 특정 작업을 위한 임시 토큰입니다.

 

OAuth 인증

사용자가 자신의 비밀번호를 제공하지 않고도, 다른 애플리케이션이나 웹사이트가 사용자의 리소스에 접근할 수 있도록 허용하는 오픈 표준 프로토콜입니다. 즉, OAuth는 안전하게 제3자 애플리케이션이 사용자의 데이터를 접근할 수 있는 방법을 제공해줍니다.

예시:

OAuth 인증의 가장 흔한 예는, 사용자가 구글(Google)이나 페이스북(Facebook) 같은 플랫폼을 통해 로그인할 때입니다. 이를 통해 사용자는 구글 계정으로 다른 사이트에 로그인하거나, 구글의 특정 데이터를 제3의 애플리케이션에서 사용할 수 있게 할 수 있습니다.

OAuth의 주요 특징

  1. 비밀번호 제공 없이 권한 부여: 사용자는 구글이나 페이스북 같은 플랫폼에 자신의 비밀번호를 제공하지 않고도, 해당 플랫폼을 통해 다른 애플리케이션에 접근할 수 있는 권한을 부여할 수 있습니다.
  2. 토큰 기반 인증: OAuth는 **액세스 토큰(access token)**을 사용하여 인증된 사용자임을 증명하고, 애플리케이션이 이 토큰을 사용하여 해당 사용자의 데이터를 접근합니다.
  3. 유효 기간이 있는 토큰: 액세스 토큰은 일정한 유효 기간이 있으며, 만료되면 리프레시 토큰을 사용하여 새로운 액세스 토큰을 발급받습니다.

OAuth의 작동 방식

OAuth 인증 프로세스는 주로 다음과 같은 단계로 이루어집니다:

  1. 사용자가 인증 요청:
    • 사용자가 제3자 애플리케이션(예: 타 웹사이트 또는 앱)에 로그인하거나, 자신의 데이터를 제공하려 할 때 해당 애플리케이션은 사용자의 OAuth 제공자(예: 구글, 페이스북 등)에 인증을 요청합니다.
  2. 사용자의 권한 부여:
    • 사용자는 OAuth 제공자에게 로그인한 후, 제3자 애플리케이션이 자신의 특정 데이터에 접근하도록 권한을 부여합니다.
  3. 액세스 토큰 발급:
    • OAuth 제공자는 사용자의 권한 부여를 확인하고, 제3자 애플리케이션에게 액세스 토큰을 발급합니다. 이 토큰을 사용해 애플리케이션은 사용자 데이터를 접근할 수 있습니다.
  4. 리소스에 접근:
    • 제3자 애플리케이션은 발급받은 액세스 토큰을 사용해 OAuth 제공자(예: 구글의 API 등)에게 요청을 보내고, 권한이 허용된 범위 내에서 사용자의 데이터를 접근하거나 작업을 수행합니다.
  5. 토큰 갱신 (선택적):
    • 액세스 토큰이 만료되면, 제3자 애플리케이션은 리프레시 토큰을 사용해 새로운 액세스 토큰을 발급받을 수 있습니다.

OAuth의 주요 개념

  1. 리소스 소유자 (Resource Owner):
    • 사용자를 의미합니다. 리소스 소유자는 자신의 리소스(예: 구글 드라이브 파일, 페이스북 프로필 정보 등)에 대한 권한을 제3자 애플리케이션에 부여합니다.
  2. 클라이언트 (Client):
    • 제3자 애플리케이션으로, 사용자의 데이터를 접근하기 위해 OAuth 인증을 요청하는 주체입니다. 예를 들어, 구글 계정으로 로그인하는 웹사이트가 클라이언트 역할을 합니다.
  3. 권한 부여 서버 (Authorization Server):
    • OAuth 제공자(예: 구글, 페이스북)가 사용자를 인증하고, 애플리케이션에 액세스 토큰을 발급해 주는 서버입니다.
  4. 액세스 토큰 (Access Token):
    • 애플리케이션이 사용자 데이터를 접근할 수 있도록 허용하는 짧은 유효 기간을 가진 토큰입니다. 애플리케이션은 이 토큰을 사용해 사용자의 데이터를 요청할 수 있습니다.
  5. 리프레시 토큰 (Refresh Token):
    • 액세스 토큰이 만료되었을 때, 새로운 액세스 토큰을 발급받기 위해 사용하는 긴 유효 기간을 가진 토큰입니다.

OAuth 예시 흐름 (구글 계정으로 로그인):

  1. 사용자가 웹사이트에서 구글 계정으로 로그인을 클릭합니다.
  2. 사용자는 구글 로그인 페이지로 이동하여 자신의 구글 계정으로 로그인하고, 해당 웹사이트가 구글 프로필 정보에 접근하도록 권한을 부여합니다.
  3. 구글은 웹사이트에 액세스 토큰을 발급합니다.
  4. 웹사이트는 이 액세스 토큰을 사용하여 구글에서 사용자의 프로필 정보를 가져옵니다.

요약:

OAuth 인증은 사용자 비밀번호를 노출하지 않고도 제3자 애플리케이션이 사용자의 데이터를 접근할 수 있도록 권한을 부여하는 안전한 방법입니다. 이를 통해 사용자는 안전하게 다른 웹사이트나 애플리케이션을 이용하면서 자신의 데이터를 공유할 수 있습니다.

 

postAPI 예시

export async function postApi(
  endpoint: string,
  body: any,
  requireAuth = true,
  isFormData = false
) {
  const url = new URL(${API_URL}${endpoint});

  const headers: any = {};
  if (!isFormData) {
    headers["Content-Type"] = "application/json";
  }

  return fetchWithAuth(
    url.toString(),
    {
      method: "POST",
      headers,
      body: isFormData ? body : JSON.stringify(body),
    },
    requireAuth,
    isFormData // FormData 사용 여부를 fetchWithAuth에 전달
  );
}

 

  • 매개변수:
    • endpoint: API 요청을 보낼 경로입니다. 기본적으로 API_URL에 붙여서 완전한 URL을 만듭니다.
    • body: 요청에 포함될 데이터입니다. JSON 형태로 전송할 수도 있고, FormData 형식으로 보낼 수도 있습니다.
    • requireAuth (기본값: true): 인증이 필요한지 여부를 나타냅니다. 인증이 필요한 경우, fetchWithAuth 함수에서 적절한 처리를 할 것으로 보입니다.
    • isFormData (기본값: false): 데이터가 FormData 형식인지 아닌지를 나타냅니다. FormData 형식이라면, 본문을 그대로 사용하고, 아니라면 JSON으로 변환해 전송합니다.
  • URL 구성:
    • const url = new URL(${API_URL}${endpoint});: API_URL과 endpoint를 결합하여 완전한 API URL을 만듭니다.
  • 헤더 설정:
    • const headers: any = {};: 헤더 객체를 만듭니다.
    • if (!isFormData) { headers["Content-Type"] = "application/json"; }: FormData 형식이 아닌 경우, 요청 본문이 JSON임을 나타내기 위해 Content-Type 헤더를 application/json으로 설정합니다.
  • fetchWithAuth 함수 호출:
    • fetchWithAuth라는 함수가 API 호출을 처리하는데 사용됩니다. 여기서 POST 요청 방식, 헤더, 본문 등을 설정하여 API에 요청을 보냅니다.
    • isFormData가 true이면, 본문(body)을 그대로 보내고, false인 경우 JSON.stringify(body)로 변환해서 전송합니다.
  • 인증 여부 전달:
    • requireAuth가 true이면, fetchWithAuth가 인증 처리를 할 가능성이 큽니다. 이 값을 전달하여 인증이 필요한 API 요청인지 여부를 제어합니다.

 

FormData

JSON 객체와는 다릅니다. 둘은 다른 목적으로 사용되는 데이터 형식입니다.

 

1. FormData

  • FormData는 주로 HTML 폼 데이터를 전송할 때 사용되는 객체입니다.
  • 키-값 쌍으로 데이터를 관리하며, 주로 파일 업로드나 폼 필드와 같은 데이터를 서버로 전송하는 데 사용됩니다.
  • 파일(이미지, 문서 등)과 같은 바이너리 데이터를 전송할 수 있는 특징이 있습니다.
  • MIME 타입은 multipart/form-data입니다.
const formData = new FormData();
formData.append('name', 'Alice');
formData.append('file', someFile); // 파일 전송 가능

fetch('/submit', {
  method: 'POST',
  body: formData,
});

2. JSON 객체

  • JSON(JavaScript Object Notation)은 문자열 기반의 데이터 형식으로, 주로 구조화된 데이터를 전송하거나 저장할 때 사용됩니다.
  • 파일 같은 바이너리 데이터를 포함할 수 없으며, 텍스트 데이터만 처리합니다.
  • MIME 타입은 application/json입니다.
const jsonData = {
  name: 'Alice',
  age: 25,
};

fetch('/submit', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(jsonData),
});

차이점 요약:

  • FormData: 파일이나 폼 데이터를 서버로 전송할 때 사용하며, 파일 업로드를 지원합니다.
  • JSON 객체: 주로 구조화된 데이터(텍스트)를 서버로 전송할 때 사용되며, 파일 전송은 지원하지 않습니다.

 

const expires = new Date(); expires.setDate(expires.getDate() + 7);

쿠키나 기타 데이터의 만료 날짜를 설정하는 데 자주 사용되며, 현재 날짜에서 7일 후의 날짜를 계산하는 것입니다.