컴퓨터잡동사니

 

 

RESTful API는 다음과 같은 주요 특징을 가지고 있습니다

 

1.자원 중심적 설계(Resource Oriented Design): RESTful API는 웹 자원을 중심으로 설계되며, 각 자원은 고유한 URI를 가집니다.

 

2.상태 없음(Stateless) 각 요청은 서버에서 어떤 상태도 유지하지 않습니다. 즉, 각 요청은 모든 필요한 정보를 포함하고 있어야 합니다.

 

3.클라이언트-서버 구조(Client-Server Architecture): 클라이언트와 서버는 독립적으로 진화할 수 있습니다. 즉, 클라이언트는 서버의 변경 없이 업데이트될 수 있으며, 반대로 서버도 클라이언트의 변경 없이 업데이트될 수 있습니다.

 

4.캐시 가능(Cacheable): 응답은 캐시될 수 있으며, 이를 통해 클라이언트는 이전에 받은 응답을 재사용할 수 있습니다.

 

5.계층화된 시스템(Layered System) : 클라이언트는 직접 연결된 서버에 대해서만 알고 있으며, 중간 서버를 통해 요청을 전달할 수 있습니다.

 

6.Code-On-Demand (optional): 서버는 필요에 따라 실행 가능한 코드를 클라이언트에게 제공할 수 있습니다.

 

7.Uniform Interface: REST는 일관된 인터페이스를 제공하여 API의 간단성과 가독성을 향상시킵니다. 이는 리소스 식별, 메시지를 통한 리소스 조작, 자기 설명적 메시지, 하이퍼미디어를 통한 애플리케이션 상태의 변화를 포함합니다.

 

 

 

 

@RestController
@RequestMapping("/api/books")
public class BookController {

    private final BookRepository bookRepository;

    public BookController(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }

    @GetMapping
    public ResponseEntity<List<Book>> getAllBooks() {
        List<Book> books = bookRepository.findAll();
        return new ResponseEntity<>(books, HttpStatus.OK);
    }

    @GetMapping("/{id}")
    public ResponseEntity<Book> getBook(@PathVariable Long id) {
        Optional<Book> book = bookRepository.findById(id);
        return book.map(value -> new ResponseEntity<>(value, HttpStatus.OK))
                .orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND));
    }

    @PostMapping
    public ResponseEntity<Book> createBook(@RequestBody Book book) {
        Book savedBook = bookRepository.save(book);
        return new ResponseEntity<>(savedBook, HttpStatus.CREATED);
    }

    @PutMapping("/{id}")
    public ResponseEntity<Book> updateBook(@PathVariable Long id, @RequestBody Book bookDetails) {
        Optional<Book> book = bookRepository.findById(id);
        if (book.isPresent()) {
            Book updatedBook = book.get();
            updatedBook.setTitle(bookDetails.getTitle());
            updatedBook.setAuthor(bookDetails.getAuthor());
            bookRepository.save(updatedBook);
            return new ResponseEntity<>(updatedBook, HttpStatus.OK);
        } else {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<HttpStatus> deleteBook(@PathVariable Long id) {
        try {
            bookRepository.deleteById(id);
            return new ResponseEntity<>(HttpStatus.NO_CONTENT);
        } catch (Exception e) {
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}

 

 

이 코드는 다음과 같은 RESTful API의 특징을 보여줍니다:

 

자원 중심적 설계: 각 Book 자원은 고유한 URI(/api/books/{id})를 가집니다.


상태 없음: 각 요청은 서버에서 어떤 상태도 유지하지 않습니다. 모든 필요한 정보는 요청에 포함됩니다.


클라이언트-서버 구조: 이 코드는 서버 측 코드이며, 클라이언트는 이 API를 사용하여 Book 자원을 생성, 조회, 업데이트, 삭제할 수 있습니다.


캐시 가능: 이 API의 응답은 HTTP 헤더를 사용하여 캐시될 수 있습니다(이 예제에서는 표시되지 않음).


계층화된 시스템: 이 API는 중간 서버를 통해 요청을 전달할 수 있습니다(이 예제에서는 표시되지 않음).


Uniform Interface: 이 API는 HTTP 메소드(GET, POST, PUT, DELETE)를 사용하여 Book 자원을 조작합니다.

 

 

 

캐시 가능

 

@Service
public class BookService {

    private final BookRepository bookRepository;

    public BookService(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }

    @Cacheable(value = "books")
    public Book getBookById(Long id) {
        return bookRepository.findById(id).orElse(null);
    }
}

 

위의 코드에서 getBookById 메소드는 @Cacheable 어노테이션이 적용되어 있습니다.

이는 getBookById 메소드의 결과를 "books"라는 이름의 캐시에 저장하라는 것을 의미합니다.

메소드가 호출될 때마다 Spring은 “books” 캐시를 확인하고, 동일한 id에 대한 결과가 캐시에 이미 있는 경우, 캐시된 값을 반환합니다.

그렇지 않으면 메소드를 실행하고 결과를 캐시에 저장한 후 반환합니다.

 

 

 

"계층화된 시스템"이란 클라이언트가 직접 연결된 서버 외에도 중간 서버를 통해 요청을 전달할 수 있는 구조를 의미합니다. 이는 클라이언트가 서버의 모든 세부 사항을 알 필요가 없으며, 서버의 구현이 변경되더라도 클라이언트에는 영향을 미치지 않습니다.

예를 들어, 웹 애플리케이션에서 클라이언트(브라우저)는 웹 서버에 직접 요청을 보냅니다. 그러나 이 요청은 여러 계층을 거쳐 처리될 수 있습니다. 예를 들어, 로드 밸런서, 캐시 서버, 프록시 서버 등의 중간 서버를 거쳐 최종적으로 웹 서버에 도달하게 됩니다. 
이러한 중간 서버들은 각각의 역할을 수행하며, 클라이언트는 이러한 세부 사항을 알 필요가 없습니다.

 

"계층화된 시스템"의 개념은 코드로 직접적으로 표현하기 어렵습니다. 이는 아키텍처의 구조적인 측면을 나타내며, 일반적으로 여러 서버나 서비스 간의 상호작용을 통해 구현됩니다. 그러나 아래에 간단한 예를 들어 설명하겠습니다.

예를 들어, 우리가 웹 애플리케이션을 개발하고 있고, 이 애플리케이션은 사용자 인증을 처리하는 별도의 인증 서버를 사용한다고 가정해봅시다. 이 경우, 웹 애플리케이션(클라이언트)은 인증 요청을 인증 서버로 전달(중간 서버를 통해)하고, 인증 서버는 인증 토큰을 반환합니다.

 

@RestController
@RequestMapping("/api/auth")
public class AuthController {

    private final AuthService authService;

    public AuthController(AuthService authService) {
        this.authService = authService;
    }

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody LoginRequest loginRequest) {
        String token = authService.authenticate(loginRequest.getUsername(), loginRequest.getPassword());
        return new ResponseEntity<>(token, HttpStatus.OK);
    }
}

 

 

위의 코드에서 AuthController는 클라이언트의 로그인 요청을 받아 AuthService에 전달합니다.

AuthService는 실제 인증 로직을 처리하며, 이는 별도의 인증 서버에서 수행될 수 있습니다.

이렇게 하면 AuthController는 인증 서버의 내부 구현에 대해 알 필요가 없으며, 인증 서버는 독립적으로 업데이트될 수 있습니다.

이것이 "계층화된 시스템"의 한 예입니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

about author

PHRASE

Level 1  라이트

댓글 ( 0)

댓글 남기기

작성