목표

GCP의 Compute Engine과 Cloud SQL을 이용해서 SpringBoot 프로젝트 서버 구축하기

 

준비

1. 빌드된 SpringBoot 프로젝트 (*.jar 파일)

 

방법

1. Google Cloud Platform의 새로운 계정을 만들어서 프리티어 이용하기

 

2. 사용할 Project 선택하기

링크 => https://console.cloud.google.com/

 

3. Cloud SQL로 데이터베이스 만들기

3-1. 메뉴에서 SQL 메뉴로 이동

 

3-2. Cloud SQL 인스턴스 만들기

 

Create a PostgreSQL instance
Create a PostgreSQL instance

CREATE INSTANCE 버튼을 누르면 완료

(이후 인스턴스 생성되는 시간이 꽤 걸리므로 4. Compute Engine에서 VM 인스턴스 만들기를 먼저해도 됨)

 

3-3. 유저 만들기

SpringBoot 프로젝트에서 데이터베이스 연결할 username과 password 생성

 

3-4. 데이터베이스 만들기

 

3-5. 외부에서 데이터베이스 접속가능하게 하기

모든 네트워크에서 접속가능하게 하려면 0.0.0.0/0을 입력한다

특정 네트워크만 허용해도 된다

Save 누르면 완료

 

4. Compute Engine에서 VM 인스턴스 만들기

4-1. 인스턴스 생성하기

Create Instance
Create Instance
Create Instance
Create Instance

CREATE 버튼을 누르면 완료

 

4-2. VM 인스턴스의 고정 IP 주소 만들기

현재는 외부/내부 임시 IP로 구성되어 있으므로 외부 고정 IP를 만든다 

 

Reserve 버튼을 누르면 완료

 

4-3. 포트(Port) 열어주기

SpringBoot의 기본 포트인 8080을 열어준다

Create a Firewall Rule
Create a Firewall Rule

Create 버튼 누르면 완료

 

5. SSH Key 발급하고 VM Instance에 등록하기

1. SSH KEY 발급하는 방법 => https://cloud.google.com/compute/docs/connect/create-ssh-keys?hl=ko#linux-and-macos

2. SSH Key 중에 .pub으로 끝나는 파일의 내용을 복사한다

3. 다음으로

Save 누르면 완료

 

6. VSCode에서 SSH로 VM 인스턴스에 연결하기

 

7. VM 인스턴스에서 SpringBoot 실행하기

1. api 폴더(아무 이름의 폴더)를 만듭니다.

2. SpringBoot를 빌드한 파일과 application.properties 또는 application.yml을 옮깁니다.

(이 환경 설정 파일에서 database 관련 설정을 Cloud SQL에서 만들었던 정보들로 수정)

spring.datasource.url=jdbc:postgresql://[Cloud Sql Instance의 Public IP]/[만든 데이터베이스 이름]?useSSL=false&characterEncoding=UTF-8
spring.datasource.username=[만든 유저 이름]
spring.datasource.password=[만든 유저 비밀번호]

3. 터미널에서 api 폴더로 이동한 합니다.

4. SpringBoot를 백그라운드에서 중단 없이 실행하는 명령어를 입력합니다.

nohup java -jar [빌드파일이름].jar &

 

문제

로컬에서는 bean이 내가 생각한 대로 실행된다. 그래서 firebase 초기화를 한 부분이 실행 되고 firebase를 사용하는 service 부분이 다음으로 실행되기 때문에 에러가 나지 않는다.

 

그런데 App Engine에 배포를 하니 @PostConstructor 어노테이션을 붙인 firebase 초기화 코드가 먼저 실행되지 않고 service 부분이 먼저 실행돼서 계속 에러가 난다는 것을 알게 됐다.

 

해결

1. FirebaseConfig 클래스에 @Order(1) 어노테이션을 붙인다.

2. 그리고 그 다음으로 실행되는 클래스인 FirebaseStorageService 클래스에 @DependsOn("firebaseConfig")를 붙여서 FirebaseConfig에 의존한 클래스라는 것을 명시한다.

3. 그리고 그 다음으로 실행되는 클래스인 BoardService 클래스에 @DependsOn("firebaseStorageService")를 붙여서 FirebaseStorageService에 의존한 클래스라는 것을 명시한다.

 

*주의점은 @DependsOn(" ") 이곳에 들어가는 값이 클래스 명이 아니라 빈의 이름을 쓴다고 한다. 그렇기에 파스칼 케이스가 아닌 카멜 케이스로 쓴다.

 

위 처럼 작성하면 App Engine에서도 문제 없이 순서대로 실행되는 것 같다.

model/Users.java

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String username;
    private String password;
}

repository/UserRepository.java

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByUsername(String username);
}

service/UserService.java

@Service
public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User registerUser(User user) {
        // 비밀번호 강도 확인
        if (!isPasswordStrong(user.getPassword())) {
            throw new IllegalArgumentException("비밀번호는 최소 8자 이상이어야 합니다.");
        }

        // 중복 사용자명 확인 (UserRepository의 findByUsername 메서드 사용)
        Optional<User> existingUser = userRepository.findByUsername(user.getUsername());
        if (existingUser.isPresent()) {
            throw new IllegalArgumentException("이미 사용 중인 사용자명입니다.");
        }

        // 필수 필드 검사
        if (user.getUsername() == null || user.getUsername().isEmpty() ||
            user.getPassword() == null || user.getPassword().isEmpty()) {
            throw new IllegalArgumentException("사용자명과 비밀번호는 필수 입력값입니다.");
        }

        // 이메일 유효성 검사 등 추가 검사가 필요한 경우도 추가 가능

        // 유효성 검사를 통과한 경우 사용자 저장
        return userRepository.save(user);
    }

    private boolean isPasswordStrong(String password) {
        // 비밀번호 강도 확인 로직 추가 (예: 최소 길이, 특수 문자 포함 등)
        return password != null && password.length() >= 8;
    }
}

controller/UserController.java

@RestController
@RequestMapping("/api/users")
public class UserController {
    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @PostMapping("/register")
    public ResponseEntity<User> registerUser(@RequestBody User user) {
        User newUser = userService.registerUser(user);
        return new ResponseEntity<>(newUser, HttpStatus.CREATED);
    }
}

Oracle Stored Procedure란?

오라클 저장 프로시저(Stored Procedure)는 데이터베이스 내에 저장된 미리 작성된 프로시저나 함수로, PL/SQL(Procedural Language/Structured Query Language)이라는 오라클의 프로그래밍 언어를 사용하여 작성됩니다. 이러한 저장 프로시저는 데이터베이스 내에서 실행되며, 자주 사용되는 작업이나 비즈니스 로직을 저장하여 호출할 수 있도록 도와줍니다.

저장 프로시저의 주요 특징과 기능:

  1. 재사용성: 반복적으로 사용되는 작업이나 쿼리를 프로시저로 작성하여 여러 곳에서 재사용할 수 있습니다.
  2. 코드의 보안성 강화: 사용자가 직접 접근하여 수정할 수 없으므로 코드의 보안성이 높아집니다.
  3. 성능 향상: 데이터베이스 내부에서 실행되기 때문에 네트워크 트래픽이 감소하고, 쿼리 최적화를 통해 성능이 향상됩니다.
  4. 트랜잭션 관리: 저장 프로시저 안에서 트랜잭션을 관리하고 제어할 수 있어 데이터 일관성을 유지할 수 있습니다.

저장 프로시저는 보통 데이터 조작, 업데이트, 삭제 등의 작업을 수행하거나 비즈니스 로직을 처리하는 데 사용됩니다. PL/SQL을 이용하여 작성되며, 데이터베이스에 저장되어 필요할 때마다 호출하여 실행됩니다.

 

ex)

재고 알림 프로시저 작성:

  • 재고 수량이 일정 수준 이하로 떨어질 때 관리자에게 알림을 보내는 프로시저를 작성할 수 있습니다. 이 프로시저는 재고 수량을 확인하고 일정 수준 이하인 제품을 관리자에게 알림 메시지를 보내거나 로그에 기록할 수 있습니다.

 

저장 프로시저의 장단점

장점:

  1. 보안 강화: 데이터베이스 내에 로직을 저장함으로써 보안성이 높아질 수 있습니다. 외부에서 직접적인 테이블 접근을 막고 저장 프로시저를 통한 접근만을 허용할 수 있습니다.
  2. 성능 향상: 일부 CRUD 작업은 저장 프로시저를 통해 데이터베이스 내에서 빠르게 실행될 수 있습니다. 특히 대량의 데이터를 처리해야 할 때 성능면에서 이점을 얻을 수 있습니다.
  3. 중복 코드 방지: 비슷한 로직이 여러 번 반복되는 것을 방지하고 데이터베이스 내에 중앙 집중적으로 유지할 수 있습니다.

단점:

  1. 유지 보수 어려움: 저장 프로시저가 복잡해질수록 유지보수가 어려워질 수 있습니다. 특히 로직의 변경이 필요할 때에는 데이터베이스에 직접적인 접근이 필요하고, 이는 개발자들에게 추가적인 부담을 줄 수 있습니다.
  2. 가독성과 이식성: 일부 개발자들은 데이터베이스에 로직을 저장하는 것이 코드의 가독성과 이식성을 해치는 것으로 보기도 합니다. 특히 저장 프로시저 언어에 대한 익숙함이 없는 경우에는 코드 이해가 어려울 수 있습니다.

따라서, CRUD 작업을 저장 프로시저로 구현할지 여부는 프로젝트의 특성과 개발자들의 선호도에 따라 다를 수 있습니다. 일반적으로 CRUD 작업 중에서 성능상 이점이 크거나 보안적인 측면에서 중요한 작업에 대해 저장 프로시저를 활용하는 것이 좋을 수 있습니다.하지만 모든 CRUD 작업을 저장 프로시저로 옮기는 것이 항상 최선의 선택은 아닙니다.

 

Sequelize와 저장프로시저

 

현재 Sequelize에서는 저장 프로시저를 직접 호출하는 기능을 공식적으로 지원하지 않습니다. 이는 Sequelize가 데이터베이스와의 ORM 매핑을 위해 객체와 데이터베이스 테이블 간의 매핑을 중심으로 설계되어 있기 때문입니다.

따라서 Sequelize를 사용하여 직접 저장 프로시저를 호출하는 것은 기본 기능으로 제공되지 않습니다. 그러나 Sequelize를 사용하는 동안 저장 프로시저를 호출해야 하는 경우, Sequelize의 query 메서드를 통해 직접 SQL 쿼리를 실행하여 저장 프로시저를 호출할 수 있습니다. 하지만 이 경우에는 Sequelize가 제공하는 모델과의 직접적인 매핑이 이루어지지 않습니다.

docker-compose.yml 파일의 첫번째 라인을 보면 대체적으로 version: "x.x"가 쓰여져 있다.

이 version은 내가 설치한 docker-compose의 버전과는 docker-compose.yml의 설정 버전을 의미한다. 이 설정은 Docker Compose 파일에서 사용할 수 있는 구문과 기능을 결정한다.

 

버전별 차이점

version: "3.1"

환경변수가 자동으로 설정되지 않아서 database의 유저와 데이터베이스를 새로 만들어야 했다.

 

version: "3.9" (현재 최신 버전)

환경변수가 자동으로 설정되어 첫실행에서도 데이터베이스와 유저가 생성되어 있어서 바로 백엔드와도 연결됐다.

 


 

카페에서 도커를 실행하려고 하는데 이러한 에러가 났다.

Error response from daemon: Ports are not available: exposing port TCP 0.0.0.0:3000 -> 
0.0.0.0:0: listen tcp 0.0.0.0:3000: bind: An attempt was made to access a socket 
in a way forbidden by its access permissions.

 

3000 포트가 이미 사용되고 있다는 의미인 것 같아서 3000 -> 3100으로 바꿔줬다.

원래는 3000:3000 이렇게 썼는데 이것의 의미는 호스트 포트 3000을 컨테이너의 포트 3000으로 매핑한다는 뜻이다.

3100으로 바꿀때는 호스트의 3000번 포트를 3100번으로 바꿨다. 이렇게 하면 접속은 3100번으로 해야하지만 컨테이너에서는 3000번으로 통하고 있으므로 코드를 수정하지 않아도 된다.

* 접속할때는 3100번으로 접속하라.

  frontend:
    build:
      context: ./client
      dockerfile: Dockerfile
    restart: always
    ports:
      - 3100:3000
    depends_on:
      - backend

 

 

참고

https://yjkim-dev.tistory.com/76


환경

  • VSCode
  • React
  • Spring Boot
  • PostgreSQL

1. docker desktop 설치하기

docker desktop을 설치하면 docker compose가 포함되어 설치된다.

mac --> https://docs.docker.com/desktop/install/mac-install/

windows --> https://docs.docker.com/desktop/install/windows-install/ 

 

1-1 docker 설치후 vscode를 열어보니 아래와 같이 WSL을 설치하라고 해서 했다.

 

2. Dockerfile을 각각의 폴더(client, server, database)에 만들고, 프로젝트 폴더 안에 docker-compose.yml 파일을 만든다.

projectname(folder)
|_ docker-compose.yml
|_ client(folder)
   |_ Dockerfile
   |_ ...
|_ server(folder)
   |_ Dockerfile
   |_ ...
|_ db(folder)
   |_ Dockerfile
   |_ ...

 

2-1 Dockerfile을 프로젝트에 추가하니 아래와 같이 설치하라고 해서 했다.

 

3. Dockerfile

* react+next.js여서 npm run dev로 개발 모드 실행한다.

* springboot image는 참고에 적어둔 블로그에서 참고했다.

# client/Dockerfile
FROM node
COPY ./ ./
RUN npm install
ENTRYPOINT [ "npm", "run", "dev" ]

# server/Dockerfile
FROM amazoncorretto:17
ARG JAR_PATH=./build/libs
COPY ${JAR_PATH}/*.jar .
ENTRYPOINT [ "java", "-jar", "server-0.0.1-SNAPSHOT.jar" ]

 

4. docker-compose.yml

version: '3.1'

services:
  database:
    image: postgres:16.1
    restart: always
    environment:
      POSTGRES_DB: 접속할db
      POSTGRES_USER: 접속할username
      POSTGRES_PASSWORD: 접속할password
    ports:
      - 5432:5432
    volumes:
      - ./postgres/:/var/lib/postgresql/data
  backend:
    build:
      context: 백엔드 폴더 경로
      dockerfile: Dockerfile
    restart: always
    ports:
      - 8080:8080
    environment:
      SPRING_DATASOURCE_URL: jdbc:postgresql://database:5432/연결할데이터베이스이름
      SPRING_DATASOURCE_USERNAME: 연결할username
      SPRING_DATASOURCE_PASSWORD: 연결할password
    depends_on:
      - database
  frontend:
    build:
      context: 프론트엔드 폴더 경로
      dockerfile: Dockerfile
    restart: always
    ports:
      - 3000:3000
    depends_on:
      - backend

 

4-1 docker image name

database/ backend/ frontend 가 각각 이미지 이름이 된다.

4-2 volumes

위와 같이 적어두면 docker build를 하면서 폴더가 생성된다.

4-3 postgres 공식 이미지의 최신 버전을 사용하였다. https://hub.docker.com/_/postgres

4-4 SPRING_DATASOURCE_URL

server에서 데이터베이스 연결 설정할 때와 달리 localhost 부분을 database로 적어준다.

spring.datasource.url=jdbc:postgresql://localhost:5432/testdb
SPRING_DATASOURCE_URL: jdbc:postgresql://database:5432/testdb

 

5. 도커 이미지 생성 후 실행

docker-compose.yml 파일이 있는 프로젝트 폴더에서 실행한다.

이미지가 생성되며 컨테이너도 함께 생성된다.

docker-compose up --build

 

5-1 springboot에서 postgresql을 연결할때 이미 만들어진 db가 필요하므로 docker에서 만들어진 서버에서 데이터베이스를 생성해준다.

 

 

  • Docker Desktop --> Containers --> 지금위에서실행한컨테이너 --> 데이터베이스 컨테이너 클릭 --> Exec 클릭

 

 

 

 

 

 

 

 

 

 

 

 

 

 

**docker-compose.yml 파일에 version: "3.1"로 작성하였기 때문에 환경변수가 자동으로 설정되지 않을 수 있으므로 아래와 같이 유저와 데이터베이스를 만들어준다.**

 

psql -U postgres로 postgresql server 접속

  • 유저 만들기
  • 데이터베이스 만들기
  • 권한 부여하기
CREATE ROLE 새로운유저네임 WITH LOGIN PASSWORD '새로운패스워드';

ALTER USER 새로운유저네임 WITH CREATEDB;
ALTER USER 새로운유저네임 WITH SUPERUSER;

CREATE DATABASE 연결할데이터베이스이름;
GRANT ALL PRIVILEGES ON DATABASE 연결할데이터베이스이륾 TO 새로운유저네임;

 

 

 

 

 

 

 

 

6. 최종 실행된 모습

 

7. 이후에 캐시된 이미지 실행하기

--build: 캐싱된 이미지와 상관없이 새롭게 이미지를 빌드한다.

-d: 백그라운드에서 실행하기

docker-compose up -d

 

1. jdk 설치

https://www.oracle.com/java/technologies/downloads/ 

 

Download the Latest Java LTS Free

Subscribe to Java SE and get the most comprehensive Java support available, with 24/7 global access to the experts.

www.oracle.com

 

2. 환경변수 설정

환경변수 --> 시스템변수 --> JAVA_HOME 에 설치된 jdk 경로 추가

환경변수 --> 시스템변수 --> Path 누르고 편집 누르기 --> 새로 만들기 누르기 --> %JAVA_HOME%/bin 추가

 

3. vscode 마켓플레이스에서 확장팩 설치

  • Java Extension Pack
  • Spring Boot Extension Pack
  • Lombok Annotations Support for VS Code

4. Ctrl + Shift + P 누르고 선택창에서 "Spring initalizr: Create a Gradle Project" 선택 후

spring boot 3.1.5

language Java

Java version 17

Packaging type jar

Dependencies 

  • Spring Boot DevTools
  • Lombok
  • Spring Configuration Processor
  • Spring Web
  • Spring Data JPA
  • H2 Database
  • Flyway Migration
  • MariaDB Driver <- PostgreSQL Driver 등 사용하는 DB driver로

선택

 

5. 프로젝트 만들 폴더 선택

6. 완료

 

 

참고

https://www.freecodecamp.org/news/snake-case-vs-camel-case-vs-pascal-case-vs-kebab-case-whats-the-difference/


 

snake case, kebab case, carmel case, pascal case 등 명명 규칙이 존재한다.

명명 규칙을 정하여 사용하면 일관성이 생기고 보기에 좋으며 이해하기 쉬워진다.

 

snake case

_(밑줄, underscore)로 각 단어를 구분하고 모든 문자는 소문자여야 한다.

Python와 Database에서 많이 사용하고, Java와 Javascript, Typescript에서는 많이 사용하지 않습니다. 

ex) snake_case = 5

 

screaming snake case

snake case와 비슷하다. 그러나 모든 문자를 대문자로 한다.

대부분의 프로그래밍 언어에서 상수를 선언할 때 많이 사용한다.

ex) SNAKE_CASE = 5

 

kebab case

snake case와 비슷하다. -(하이픈,hyphen)으로 각 단어를 구분하고 모든 문자는 소문자여야 한다.

주로 URL에서 많이 사용한다.

ex) kebab-case = 5

 

camel case

첫번째 단어의 첫 문자를 소문자로 하고 두번째 단어부터 첫 문자를 대문자로 한다.

Java, Javascript, Typescript에서 변수, 함수, 메소드 이름에 사용한다.

ex) camelCase = 5

 

pascal case

camel case와 비슷하다. 그러나 각 단어의 첫문자마다 대문자로 한다.

대부분의 프로그래밍 언어에서 class를 선언할 때 사용한다.

ex) PascalCase = 5


정리

URL : kebab-case

대부분의 Class : PascalCase

대부분의 상수 : SCREAMING_SNAKE_CASE

Java : camelCase

Javascript : camelCase

Typescript : camelCase

Python : snake_case

Database: snake_case

validatorjs 라이브러리를 사용하여 nodejs에서 유효성 검사하기

1. 설치하기

npm install validatorjs

 

2. ~/helpers/validate.js 유효성 검사 스니펫 만들기

*스니펫(snippet)은 재사용 가능한 소스 코드, 기계어, 텍스트의 작은 부분을 일컫는 프로그래밍 용어이다. 

const Validator = require('validatorjs');
const validator = async (body, rules, customMessages, callback) => {
    const validation = new Validator(body, rules, customMessages);
    validation.passes(() => callback(null, true));
    validation.fails(() => callback(validation.errors, false));
};
module.exports = validator;

 

3. ~/middleware/validation.middleware.js 유효성 검사 정의하기

required : not null

string : 데이터타입이 string

min:6 : 최소 6글자

confirmed : 일치하는 필드가 필요함

const validator = require('../helpers/validate');
const signup = async (req, res, next) => {
    const validationRule = {
        "email": "required|string|email",
        "username": "required|string",
        "phone": "required|string",
        "password": "required|string|min:6|confirmed",
        "gender": "string"
    };

    await validator(req.body, validationRule, {}, (err, status) => {
        if (!status) {
            res.status(412)
                .send({
                    success: false,
                    message: 'Validation failed',
                    data: err
                });
        } else {
            next();
        }
    }).catch( err => console.log(err))
}
module.exports = {
    signup
};

 

4. 비밀번호 유효성 검사 추가, 3번에서 'strict' 추가됨. 

...
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]/;

// Tighten password policy
Validator.register('strict', value => passwordRegex.test(value),
    'password must contain at least one uppercase letter, one lowercase letter and one number');

module.exports = validator;

 

5. 비동기로해야하는 작업일때는 Validator.registerAsync()을 사용한다.

'개발 > Node.js' 카테고리의 다른 글

RESTful API  (0) 2023.11.02
node.js 로그 남기기 - winston  (0) 2023.10.20
[sequelize] update, destroy  (0) 2023.10.06
데이터베이스 권한 : admin/moderator/user  (0) 2023.09.22
ORM에 대하여  (0) 2023.09.21

참고

https://prohannah.tistory.com/156

https://restfulapi.net/

https://restfulapi.net/resource-naming/


REST, RESTful

REST는 REpresentational State Transfer의 약자이자 분산 하이퍼미디어 시스템의 아키텍처 스타일입니다. 데이터와 기능은 리소스로 간주되며  URI를 사용하여 액세스됩니다.


다른 아키텍처 스타일과 마찬가지로 REST도 그 가이드 원칙과 제약이 있습니다. 6가지 원칙 또는 제약 조건이 충족되면 RESTful하다고 할 수 있습니다.

 

RESTful API를 위한 원칙과 제약조건

1.1. 균일한 인터페이스(Uniform Interface)

전체 시스템 아키텍처를 단순화하고 상호 작용의 가시성을 개선할 수 있습니다.
다중 아키텍처 제약은 균일한 인터페이스를 얻고 구성 요소의 동작을 안내하는 데 도움이 됩니다.

다음과 같은 네 가지 제약 조건으로 REST 인터페이스를 균일하게 할 수 있습니다:

▶ Identification of resources – 인터페이스는 클라이언트와 서버 간의 상호 작용에 관련된 각 리소스를 고유하게 식별해야 합니다.

▶ Manipulation of resources through representations – 서버 응답에서 리소스가 균일한 표현을 가져야 합니다. API 소비자는 이러한 표현을 사용하여 서버의 리소스 상태를 수정해야 합니다.

▶ Self-descriptive messages – 각 리소스 표현은 메시지를 처리하는 방법을 설명하기에 충분한 정보를 전달해야 합니다. 또한 클라이언트가 리소스에 대해 수행할 수 있는 추가 작업에 대한 정보도 제공해야 합니다.

▶ Hypermedia as the engine of application state – 클라이언트는 응용 프로그램의 초기 URI만 가지고 있어야 합니다. 클라이언트 응용 프로그램은 하이퍼링크를 사용하여 다른 모든 리소스와 상호 작용을 동적으로 구동해야 합니다.

 

1.2. 클라이언트-서버(Client-Server)

클라이언트와 서버 설계 패턴은 관심사를 분리하도록 강요하며, 이는 클라이언트와 서버 구성요소가 독립적으로 발전하도록 도와줍니다.
사용자 인터페이스 관심사(클라이언트)와 데이터 스토리지 관심사(서버)를 분리하여 여러 플랫폼에 걸쳐 사용자 인터페이스의 휴대성을 개선하고 서버 구성 요소를 단순화하여 확장성을 개선합니다.
클라이언트와 서버가 진화하는 동안 클라이언트와 서버 간의 인터페이스/계약이 깨지지 않도록 해야 합니다.

 

1.3 무상태(Stateless)

클라이언트에서 서버로 요청할 때마다 요청을 이해하고 완료하는 데 필요한 모든 정보를 포함해야 합니다.
서버는 이전에 저장된 서버의 컨텍스트 정보를 이용할 수 없습니다.
이러한 이유로 클라이언트 응용프로그램은 세션 상태를 완전히 유지해야 합니다.

 

1.4. 캐시 가능(Cacheable)

응답 자체에 캐시 가능 또는 캐시 불가능으로 암시적 또는 명시적으로 레이블을 지정해야 합니다.
응답이 캐시 가능한 경우 클라이언트 응용 프로그램은 해당 요청 및 지정된 기간에 대해 나중에 응답 데이터를 재사용할 수 있는 권한을 가집니다.

 

1.5. 레이어드 시스템(Layered System)

구성요소 동작을 제한함으로써 아키텍처를 계층화된 계층으로 구성할 수 있게 합니다.
예를 들어 계층화된 시스템에서는 각 구성 요소가 상호 작용 중인 직접 계층 이상을 볼 수 없습니다.

1.6. 주문형 코드(선택 사항) (Code on Demand (Optional))

REST는 또한 애플릿이나 스크립트 형태의 코드를 다운로드하여 실행함으로써 클라이언트 기능을 확장할 수 있습니다.

 

RESTful API 네이밍 방식

- 가독성을 위해 `-`(하이픈)을 사용하라

- 소문자를 사용하라
Schem과 HOST에만 대소문자 구별이 없고, 이 외에는 대소문자가 구별된다.

- CRUD 함수명을 사용하지 마라

URI는 어떤 동작이 수행되는 지 가르키는 게 아니라, 리소스를 가르키는 것이다.
리소스에 대한 작업은 HTTP Method를 이용하도록 한다.

- 필터를 위해 쿼리 파라미터를 사용해라

Resource(or Reperesentation)에 대한 정렬, 필터링, 페이징은 신규 API를 생성하지 않고 쿼리 파라미터를 활용해라.

 

'개발 > Node.js' 카테고리의 다른 글

유효성 검사 validation  (1) 2023.11.03
node.js 로그 남기기 - winston  (0) 2023.10.20
[sequelize] update, destroy  (0) 2023.10.06
데이터베이스 권한 : admin/moderator/user  (0) 2023.09.22
ORM에 대하여  (0) 2023.09.21

+ Recent posts