[인프런워밍업스터디_BE_0기] 1주차 정리!

섹션 1. 생애 최초 API 만들기


[섹션 목표]
1. 스프링 부트 프로젝트를 설정해 시작하고 실행할 수 있다.

2. 서버란 무엇인지, 네트워크와 HTTP, API는 무엇인지, JSON은 무엇인지 등 서버 개발에 필요한 다양한 개념을 이해한다.

3. 스프링 부트를 이용해 간단한 GET API / POST API 를 만들어본다.

 

스프링 부트 프로젝트를 만들어보자!

우선 https://start.spring.io/ 로 접속한다. 해당 링크로 접속하면 아래와 같은 화면(작성일 기준)을 볼 수 있다.

image시간이 지나면 화면 구성이 바뀔 수 있다.

  1. Project : 프로젝트에서 사용될 '빌드 툴'을 고르는 항목

  2. Language : 개발 시 사용될 언어를 고르는 항목

  3. Spring Boot : 스프링 부트의 버전을 고르는 항목, SNAPTHOT, M1 등 숫자 옆에 무언가 붙어 있는 경우 안정성이 떨어질 수 있다.

  4. Project Metadata : 프로젝트와 관련된 설정 및 이름을 정하는 항목

    1. Java : 프로젝트에 사용될 Java 버전을 정하는 항목

  5. Dependencies : 프로젝트에서 사용될 라이브러리나 프레임워크를 추가하는 항목

    1. ADD DEPENDENCIES.. 를 눌러서 추가할 수 있다.

    2. 라이브러리 : 프로그램을 개발할 때 미리 만들어진 기능을 가져와 사용하는 것

    3. 프레임워크 : 프로그램을 개발할 때 미리 만들어진 구조에 코드를 끼워 넣는 것

  6. GENERATE 버튼을 누르면 만들어진 프로젝트가 다운로드 받아진다!

위 과정을 거쳐 만들어진 압축파일의 압축을 풀고 IDE에서 해당 프로젝트를 열어주면 끝!

 

서버란 무엇일까?

image서버하면 생각나는 이미지...

서버란 무엇일까? 우선 구글에 한 번 검색해보자.

서버(server)는 클라이언트에게 네트워크를 통해 정보나 서비스를 제공하는 컴퓨터 시스템으로 컴퓨터 프로그램 또는 장치를 의미한다. ( 출처 : 서버 - 위키백과, 우리 모두의 백과사전 (wikipedia.org) )

위키에 따르면 서버는 크게 두 가지를 의미한다.

  1. 클라이언트에게 정보 서비스를 제공하는 컴퓨터 프로그램

  2. 위 프로그램을 실행하는 장치 즉, 컴퓨터

     

보통 우리가 서버를 개발한다고 할 때, 하드웨어를 만들진 않으니까.. 클라이언트에게 서비스를 제공하는 프로그램을 말하는 것이다. 그럼 클라이언트는 무엇일까? 이번에도 구글에 검색해보자!

의뢰인, 고객이라는 뜻으로 컴퓨터 용어로는 네트워크를 통하여 서버라는 다른 컴퓨터 시스템 상의 원격 서비스에 접속할 수 있는 응용 프로그램이나 서비스를 의미한다. ( 출처 : 클라이언트 (컴퓨팅) - 위키백과, 우리 모두의 백과사전 (wikipedia.org) )

조금 어렵지만 간단하게 정리하면 서버로부터 서비스를 요청하고 제공받는게 클라이언트이다. 이 때 클라이언트는 '네트워크'를 통해 서버에 요청을 한다고 한다. 여기서 다음 키워드인 네트워크에 대해서 알아보자.

 

네트워크 그리고 HTTP, API란?

노드들이 자원을 공유할 수 있게하는 디지털 전기통신망의 하나로 즉, 분산되어 있는 컴퓨터를 연결하는 것을 말한다.

( 출처 : https://ko.wikipedia.org/wiki/%EC%BB%B4%ED%93%A8%ED%84%B0_%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC )

네트워크는 컴퓨터를 연결하는 것을 말한다고 한다. 즉, 네트워크를 통해서 서버와 클라이언트가 연결되고 이 네트워크를 통해서 클라이언트는 서버로 요청을 보내는 것이다. 그럼 어떻게 요청을 보낼까? 이 때 등장하는 것이 HTTP 와 API 이다.

HTTP는 Hyper Text Transfer Protocol의 약자로 클라이언트와 서버 사이에 이러우저니는 요청/응답 프로토콜이다. ( 출처 : https://ko.wikipedia.org/wiki/HTTP )

API 는 응용 프로그램에서 사용할 수 있도록 운영 체제나 프로그래밍 언어가 제공하는 기능을 제어할 수 있게 만든 인터페이스이다. ( 출처 : https://ko.wikipedia.org/wiki/API )

어려운 용어가 많이 나왔다. 내가 이해한 내용을 토대로 간단히 요약하자면 HTTP는 네트워크로 통신할 때 정해진 규약이고, API는 HTTP 를 통해 전달받은 내용을 토대로 미리 정해진(만들어진) 기능을 수행하는 것이다.

 

GET API 와 POST API를 만들어 보자

선생님과 함께 다음과 같이 코드를 만들어보았다. 위에서부터 차근차근 정리해보자

// 컨트롤러 클래스
@RestController
public class CalculatorController {

    @GetMapping("/addV1")
    public int addTwoNumbers(@RequestParam int number1, @RequestParam int number2) {
        return number1 + number2;
    }

    @GetMapping("/addV2")
    public int addTwoNumbers(CalculatorAddRequest request) {
        return request.getNumber1() + request.getNumber2();
    }

    @PostMapping("/multiply")
    public int multiplyTwoNumbers(@RequestBody CalculatorMultiplyRequest request) {
        return request.getNumber1() * request.getNumber2();
    }
}

// 요청 클래스
public class CalculatorAddRequest {
    private final int number1;
    private final int number2;

    public CalculatorAddRequest(int number1, int number2) {
        this.number1 = number1;
        this.number2 = number2;
    }

    public int getNumber1() {
        return nubmer1;
    }

    public int getNumber2() {
        return nubmer1;
    }
}

public class CalculatorMultiplyRequest {
    private final int number1;
    private final int number2;

    public int getNumber1() {
        return nubmer1;
    }

    public int getNumber2() {
        return nubmer1;
    }
}
  1. @RestController : 해당 클래스를 API의 진입 지점 즉, Controller로 만들어준다.

  2. @GetMapping("/addV1") : 해당 메서드를 HTTP Method가 GET이고 path가 /addV1인 API로 지정한다.

  3. @RequestParam : HTTP 쿼리로 들어온 값을 메서드의 파라미터에 넣어준다.

    1. 메서드의 파라미터가 많아졌을 때 일일이 @RequestParam 을 사용한다면 코드가 길어질 것이다.

    2. 이럴 때는 CalculatorAddRequest 와 같이 클래스를 만들어주면 파라미터를 한 번에 받을 수 있다.

  4. @PostMapping("/multiply") : 해당 메서드를 HTTP Method가 POST이고 path가 /multiply인 API로 지정한다.

  5. @RequestBody : HTTP 바디로 들어온 JSON 데이터를 객체로 바꿔준다.

    1. @RequestBody를 사용하는 경우에는 CalculatorMultiplyRequest 와 같이 생성자를 만들지 않아도 괜찮다.

위에서 배운 내용을 바탕으로 유저 생성 및 조회 API를 만들어보았는데, 한 가지 문제가 있다. 바로 서버를 껐다 키면 생성했던 유저 데이터가 사라진다는 것..! 다음 섹션을 통해 이를 해결해보자.

 

섹션 2. 생애 최초 Database 조작하기


[섹션 목표]
1. 디스크와 메모리의 차이를 이해하고, Database의 필요성을 이해한다.

2. MySQL Database를 SQL과 함께 조작할 수 있다.

3. 스프링 서버를 이용해 Database에 접근하고 데이터를 저장, 조회, 업데이트, 삭제할 수 있다.

4. API의 예외 상황을 알아보고 예외를 처리할 수 있다.

디스크와 메모리의 차이 그리고 Database

컴퓨터의 핵심 부품은 CPU, RAM, DISK 세 가지이다. 이 중 RAM은 단기기억장치 디스크는 장기기억장치인데, 우리가 이전 섹션에서 서버를 실행시킨 뒤 저장한 유저 정보는 메모리 즉 RAM에 저장되었다. 그래서 서버를 종료하면 생성되었던 유저 정보가 사라졌던 것이다. 이를 해결하기 위해서 우리는 주로 Database를 사용하게 된다. 여기서 Database란 데이터를 구조화시켜 저장한 것이다.

 

MySQL Database를 SQL과 함께 조작해보자.

강의를 시작하기 전 설치해두었던 MySQL을 한 번 사용해보자!

 

  1. DDL (Data Definition Language) : 데이터를 정의하기 위한 SQL

// 데이터베이스 생성
create database library;

// 데이터베이스 조회
show databases;

// 데이터베이스 삭제
drop database library;

// 데이터베이스 접속
use library;

// 테이블 생성
create table user
(
    id   bigint auto_increment,
    name varchar(25),
    age  int,
    primary key (id)
);

// 테이블 목록 조회
show tables;

// 테이블 삭제
drop table user;

테이블 생성 시에는 컬럼의 이름과 타입, 부가조건을 설정하는데 간단히 정리하면 다음과 같다.

MySQL 타입

  • 정수타입: tinyint, int, bigint

  • 실수타입: double, decimal(A,B)

  • 문자열타입: char(A), varchar(A)

  • 날짜, 시간타입: date, time, datetime

부가조건

  • auto_increment: 데이터를 넣지 않더라도 1부터 1씩 증가하며 자동으로 기록된다.

  • primary key: 데이터를 식별할 기본 키로 지정한다.

  • default: 데이터를 넣지 않았을 때 들어갈 기본값을 지정한다.

  • not null: NULL을 허용하지 않기 때문에 데이터가 반드시 들어가야한다.

이 외에도 많은 타입과 조건이 있지만 이번 글에서는 다루지 않겠다.

 

2. DML ( Data Manipulation Language) : 데이터를 조작하기 위한 SQL

// 데이터 추가 (Create)
insert into user (name, age) values ('철수', 20);

// 데이터 조회 (Read)
select * from user;

// 데이터 수정 (Update)
update user set name = '영희' where name = '철수';

// 데이터 삭제 (Delete)
delete from user where '철수';

이렇게 데이터를 조작하는 4가지 방법을 각각의 앞글자를 따서 CRUD라고 한다!

 

스프링 서버를 이용해 Database에 접근하고 데이터를 조작해보자

자, 이제 스프링에서 DB에 접근해보자. 먼저 src/main/resources 경로의 application.yml 파일을 만들고 다음과 같이 DB설정 정보를 적어준다.

spring:
  datasource:
    url: "jdbc:mysql://localhost/library"
    username: "root"
    password: "1234"
    driver-class-name: com.mysql.cj.jdbc.Driver

그리고 JdbcTemplate을 활용해 다음과 같이 코드를 작성하면 Database에 SQL로 데이터를 조작할 수 있다.

public class UserController {

    private final JdbcTemplate jdbcTemplate;

    public UserController(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @PostMapping("/user")
    public void saveUser(@RequestBody UserCreateRequest request) {
        String sql = "insert into user(name, age) values(?, ?)";
        jdbcTemplate.update(sql, request.getName(), request.getAge());
    }

    @GetMapping("/user")
    public List<UserResponse> getUsers() {
        String sql = "select * from user";
        return jdbcTemplate.query(sql, (rs, rowNum) -> {
            long id = rs.getLong("id");
            String name = rs.getString("name");
            int age = rs.getInt("age");
            return new UserResponse(id, name, age);
        });
    }
}
  1. 작성한 생성 sql문에서 ?에 해당하는 부분은 jdbcTemplate.update에서 적어준 파라미터로 채워져 DB에 전달된다.

  2. 작성한 조회 sql문은 jdbcTemplate.query를 통해 DB에 전달되고 조회된 데이터를 (rs, rowNum)->{} 람다식을 통해 가공하여 반환한다.

 

API 예외 상황을 처리해보자

이제 우리가 만든 서버를 통해 Database에 접근하여 데이터를 조작할 수 있게 되었다. 그리고 이를 토대로 유저 정보를 수정하고 삭제하는 API도 만들었다. 그런데 현재 존재하지 않는 유저를 수정하거나 삭제하려고 하면 어떻게 될까? Postman을 통해 요청을 해보면 200 OK가 돌아오는 것을 알 수 있다.

실제로 수정되거나 삭제된 데이터가 없는데도 성공했다는 응답이 오는 것은 이상하다. 다음과 같이 예외를 처리해보자

@PutMapping("/user")
public void updateUser(UserUpdateRequest request) {
    if (userJdbcRepository.isUserNotExist(request.getId())) {
        throw new IllegalArgumentException();
    }

    userJdbcRepository.updateUserName(request.getName(), request.getId());
}

isUserNotExist를 통해 유저가 존재하는지 확인하고 존재하지 않는 경우 IllegalArgumentException 예외를 던지도록 하였다. 이렇게 변경한 뒤 Postman을 통해 요청하면 500 Internal Server Error 로 응답이 오는 것을 확인할 수 있다!

이와 같이 우리는 API를 통해 들어온 요청을 처리하던 중 발생하는 예외상황을 클라이언트에 알릴 수 있도록 예외처리를 해주어야한다.

 

섹션 3. 역할의 분리와 스프링 컨테이너


[섹션 목표]
1. 좋은 코드가 왜 중요한지 이해하고, 원래 있던 Controller 코드를 보다 좋은 코드로 리팩토링한다.

2. 스프링 컨테이너와 스프링 빈이 무엇인지 이해한다.

3. 스프링 컨테이너가 왜 필요한지, 좋은 코드와 어떻게 연관이 있는지 이해한다.

4. 스프링 빈을 다루는 여러 방법을 이해한다.

좋은 코드 (Clean Code)는 왜 중요할까?

개발자는 새로운 코드를 작성하기도 하지만 기존의 코드를 수정하기도 한다. 특히 실무에서는 기존의 코드에 새로운 기능을 추가하거나 수정하는 일이 더욱 많다고 한다. 이를 위해서는 기존의 코드를 먼저 이해해야할텐데... 기존 코드가 이해하기 어렵게 작성되어 있다면 이해하는데 많은 공과 시간을 들여야할 것이다. 따라서 우리는 가능한 이해하기 쉽도록 좋은 코드를 만들어야 하는 것이다!

 

기존의 Controller를 분리해 더 좋은 코드로 만들어보자

기존의 컨트롤러를 Controller, Service, Repository 세 개로 분리하였다. 이렇게 각 클래스가 각자의 역할을 가지고 단계별로 동작하는 것을 Layered Architecture라고 부른다.

 

1주차는 여기까지..! 섹션의 나머지 부분은 다음주에 계속 배워볼 것이다.

 

1주차 과제 정리


각 과제를 블로그로 정리해두어 아래에 링크를 남긴다.

Day 1 : https://www.inflearn.com/blogs/6567

Day 2 : https://www.inflearn.com/blogs/6603

Day 3 : https://www.inflearn.com/blogs/6672

Day 4 : https://www.inflearn.com/blogs/6705

Day 5 : https://www.inflearn.com/blogs/6728

 

1주차를 마치며


실무를 하며 많은 부족함을 느끼고 인프런에서 여러 강의를 듣고 있었지만 어떻게 공부해나가야할지 방향성을 잡지 못하고 있던 와중에 이번 스터디를 발견했다. 이번 스터디를 통해 어떤 방법으로 공부해야할지 방향성을 잡는 것을 목표로 잡고 1주차를 맞이하였다.

 

  • 아쉬웠던 점

역시 가장 아쉬운건 일과 학습의 병행이었다. 집과 회사의 거리가 멀다보니 퇴근 이후 집에 도착하면 8시였다. 밥 먹고 운동하고 씻고... 공부를 할 시간이 1~2시간 밖에 없다보니 강의를 듣고 과제를 제출하는 것도 빠듯했다.

물론 공부할 시간이 부족할 것을 생각해 주말에 미리 이번주 분량의 강의를 들어두었지만 그럼에도 시간이 부족했다. 과제를 하는 시간도 꽤 오래 걸렸지만 아무래도 평소에 공부할 때 글로 정리하는 습관이 없다보니 블로그에 정리하는 것이 시간을 많이 잡아먹었다.

 

  • 칭찬할 점

그럼에도 진도에 맞춰서 모든 강의를 수강하고, 과제를 제출한 것을 칭찬하고 싶다! 퇴근길 지하철에서 앉아서 갈 때 수업을 듣고 노트북으로 직접 코드도 쳐볼 수 있도록 세팅해서 실제로 강의를 듣기도 하고 (다른 사람이 불편하지 않도록 어깨를 한껏 움츠린채 코드를 치기란...ㅠㅠ), 운동을 쉬기도 하면서(이건 아쉬운 점이기도 하지만..) 일정에 맞추기 위해 많은 노력을 했던 것이 자랑스럽다.

 

  • 보완할 점

역시 주말을 많이 활용해야겠다는 생각이 들었다. 이번 주는 시간에 쫓겨 운동을 쉬기도 하고 과제를 해결한 부분도 아쉬운 부분이 많았는데 다음 주는 시간이 부족하단 느낌이 들지 않도록 최선을 다해봐야겠다!

댓글을 작성해보세요.

채널톡 아이콘