[RESTful API 설계하기] 1. RESTful과 API

[RESTful API 설계하기] 2. REST 특징 [RESTful API] 1. RESTful과 API 어떤 서비스를 개발할 때 본래 필수적인 기능은 아니었지만, 이제는 필수적인 기능이 되어버린 API와 관련하여 글을 작성하려 한다. 이 중

dev-whoan.xyz

 

[RESTful API 설계하기] 2. REST 특징

[RESTful API] 1. RESTful과 API 어떤 서비스를 개발할 때 본래 필수적인 기능은 아니었지만, 이제는 필수적인 기능이 되어버린 API와 관련하여 글을 작성하려 한다. 이 중 굉장히 많이 쓰이고, 한번도 안

dev-whoan.xyz

 

[RESTful API 설계하기] 3. RESTful API 데이터 조회 GET Method

[RESTful API 설계하기] 1. RESTful과 API 어떤 서비스를 개발할 때 본래 필수적인 기능은 아니었지만, 이제는 필수적인 기능이 되어버린 API와 관련하여 글을 작성하려 한다. 이 중 굉장히 많이 쓰이고,

dev-whoan.xyz

오늘은 POST Method의 기능에 대해 알아보자.

POST Method 데이터의 생성부분을 담당한다. 다시 말하면, 데이터 조회의 조건이 필요없다는 말이다.

생성 대상이 되는 Data Set에 대하여 새로운 데이터의 내용을 채워주면 된다.

POST /dataset --data '새로운 데이터의 내용'

즉 사용자에 대한 dataset이 user이고, 채워야 하는 내용이 id, pw, name이 전부라면 다음과 같은 생김새를 갖게 된다.

POST /user --data '{"id":"gildong", "pw":"password", "name":"홍길동"}'
Data Set은 URI,
데이터 내용은 Body Parameter

간혹가다 사설 RESTful API의 경우 Body Parameter를 Query String으로 보내는 경우가 있는데, 어.. 매우 좋지 않다. Query String으로 보낼 경우, 외부에 노출되기 때문에 보안적 측면에서 매우매우 아주아주 좋지 않은 구현이다.

사용자 로그인 기능을 구현할 때, 사용자 정보를 Body Parameter에 담아서 보내는 것을 생각하면, 그 이유를 떠올리기 쉬울 것이다.

Body Parameter는 JSON Type으로!

Body Parameter는 어느 플랫폼에서 보내느냐에 따라 획득할 수 있는 방법이 다르다. Nodejs 즉 React에서 전송된 데이터와 JSP를 통해 전송된 데이터를 구하기 위한 방식에 약간의 차이가 있기 때문에, (적어도 Java의 Dynamic Web Application은 그러했다.) 될 수 있으면 데이터 생성 요청에 대한 컨텐츠 타입을 미리 서버에서 JSON만 허용하도록 설계해 놓는게 편하다.

따라서 우리가 편하게 데이터를 조작할 수 있는 JSON Type으로 요청을 받도록 하는게 제일 좋다.


글이 짧아서 실망했을 수 있는데, 데이터 조회를 제외하고는 우리가 흔히 했던 일반적인 API를 설계하는 것과 비슷하다. 다만 RESTful API라는 객체의 입장에서 다른 부가기능적인 요소를 생각해야 하고, 그것은 POST Method를 설계하기 위해 필수조건이 아니기 때문에 오늘 POST Method의 설계는 여기서 마치겠다.

그렇다고 해서 다른 Methods에서 다 되는데 POST만 안되게 하라는건 아니다. 다만 POST의 의무가 아닌 RESTful API 객체의 의무라는 뜻이다.

 

 

 

[RESTful API 설계하기] 1. RESTful과 API

어떤 서비스를 개발할 때 본래 필수적인 기능은 아니었지만, 이제는 필수적인 기능이 되어버린 API와 관련하여 글을 작성하려 한다. 이 중 굉장히 많이 쓰이고, 한번도 안 써본 사람은 있어도 한

dev-whoan.xyz

 

[RESTful API 설계하기] 2. REST 특징

[RESTful API] 1. RESTful과 API 어떤 서비스를 개발할 때 본래 필수적인 기능은 아니었지만, 이제는 필수적인 기능이 되어버린 API와 관련하여 글을 작성하려 한다. 이 중 굉장히 많이 쓰이고, 한번도 안

dev-whoan.xyz

 

[RESTful API 설계하기] 4. RESTful API 데이터 생성 POST Method

[RESTful API 설계하기] 1. RESTful과 API [RESTful API 설계하기] 2. REST 특징 [RESTful API] 1. RESTful과 API 어떤 서비스를 개발할 때 본래 필수적인 기능은 아니었지만, 이제는 필수적인 기능이 되어버린 AP..

dev-whoan.xyz

RESTful API중 데이터 조회를 위한 방법은 GETHEAD 두 가지가 있다. 

Method가 조회를 담당하는데, 이중 HEAD는 실제 response body가 없는 녀석이다.

GET
{
  "took":"12",
  "code":"200",
  "response":"HTTP 1.1 200 OK",
  "Content-Type":"application/json;charset=UTF-8",
  "Content-Length":"79",
  "users" : [ {
    "address" : "dev.whoan@gmail.com",
    "name" : "dev.whoan",
    "user_SEQ" : "1"
  } ]
}

HEAD

{
  "took":"12",
  "code":"200",
  "response":"HTTP 1.1 200 OK",
  "Content-Type":"application/json;charset=UTF-8",
  "Content-Length":"79"
}

많은 사람들이 API를 생성할 때 다음과 같은 형식을 가지게 설계한다.

1. QueryString

GET /getUsers?name={name}&user_SEQ={seq}&type={type}&print={print}

2. URI Segment

GET /users/name/{name}/user_SEQ/{seq}?type={type}&print={print}
사실 이 방식은 MkWeb을 설계하면서 고안한 방법이고, 앞 글을 보면 내가 준 팁에 그대로 나와있다.

앞서 말한것 처럼 RESTful API는 URI Segment를 지향하고, 주소에 데이터 관련 조작 방식을 나타내지 않는게 좋기 때문에 2. URI Segment방식을 활용하여 설계하는 것이 좋다.

하지만 바로 전 글에서 말한것 처럼 꼭 이를 지킬 필요는 없다. ElasticSearch의 RESTful API같은 경우에는 QueryString중 q 파라미터를 통해 데이터를 조회하는것 처럼, 내가 잘 설계하고, 사람들에게 잘 지침을 주면 된다.

MkWeb의 경우에는 다음과 같이 설계 했다.

 /DATASET/조건1/{조건1값}/조건2/{조건2값}/...?OPTIONS
먼저 데이터 셋을 정의해라

어떤 RESTful API든 간에 우리가 조회하고자 하는 대상이 있다. 해당 대상에 대한 데이터 셋을 먼저 정의하고, URI의 최상단에 선언하자.

그렇게 되면, 우리가 조회하고자 하는 데이터가 무엇인지 한눈에 보기 쉽기 때문이다.

데이터 셋을 정의할 때는, 여러개의 데이터를 하나로* 묶을 수 있고, 한 API당 하나의 데이터만**을 조회하게 할 수 있다.

MkWeb에서는 한 API당 하나의 데이터만을 조회하게 했는데, 이미 MkWeb에서 지원하는 다른 SQL Method에서 여러 데이터를 하나로 묶은 결과를 받을 수 있기 때문이었고, 큰 이유는 API는 데이터를 조작하기 위함인데, 여러 데이터를 통합했을 때 발생하는 데이터는 이러한 목적, 즉 이미 조작된 데이터이기 때문에 약간 다르다고 생각했기 때문이다.

*여러개의 데이터를 하나로: 유저정보 + 직장정보

**한 API당 하나의 데이터: 유저정보, 직장정보 각각 따로

데이터 조건들은 모두 Key-Value 쌍을 이루게 하자

RESTful API를 처음 설계할 때, 다음과 같은 설계를 허용할지 엄청 고민했다.

GET /users/name
MkWeb 자체가 범용적인 사용이 가능하기를 바랬고, 그렇기 때문에 발생한 고민이었는데 결국 의미 없는 고민이었다.

해당 요청의 목적은 요청에 대한 응답이 이름만 반환하기를 바랬던 것인데, 이는 사용자가 요청부분에서 담당할게 아니라, 응답하기 위한 데이터 셋에 name만 반환하도록 설계하면 되는 것 이었다.

딴 말이 길었는데, 조건들이 Key-Value 쌍을 이룸으로써 어떤 데이터 셋에 대한. 조회를 할 때, 정확한 데이터만 집을 수 있도록 함이다. 물론 정확한 데이터, Unique하지 않은 필드의 조회에 대해서는 그 결과에서도 겹치는 부분이 많을 것이다. (동명이인과 같이)

그렇지만, 적어도 쌍을 이루게 함으로써 조회의 정확도를 높이고, RESTful API의 설계 난이도를 낮출 수 있다.

API 조건은 모두 Query String으로

URI Segment에 조회하고자 하는 데이터 셋을 특정짓고, 검색 옵션을 모두 Query String에 넣음으로써 우리는 무엇이 데이터와 관련된 조건이고, 응답에 대한 옵션인지를 한눈에 파악할 수 있다.

API 조건은 예를 들어, 응답을 특정 방식으로 정렬하기를 바라거나, 데이터 조회시 20개만 가져오길 바라는 등, 검색하고자 하는 데이터를 특정하지는 않지만, 데이터 조회에 영향을 미치는 부가 기능을 의미한다.

1.Query String처럼 한곳에 데이터 검색을 위한 조건과 옵션을 모두 때려 넣으면, 어느 것이 데이터 조건이고, 부가기능인지 헷갈리기 때문이다.


그래서 설계를 어떻게 해야 하는가?

사실 많은 사람들이 설계를 어떻게하는지 보기 위해서 이 페이지에 들어왔을거라 생각한다. 나도 처음 RESTful API를 접했을 때 많은 고민을 했고, 특히 MkWeb의 특징을 살리기 위해 가능한 모든 방안을 수용 가능하도록 만들려고 했다. 하지만 RESTful API인 것 처럼, 그리고 이미 RESTful API의 설계에 대해 고민을 해봤다면, 의미 없는 질문인 것을 알 수 있다.

결국, RESTful API를 설계하기 위한 방법론, 즉 설계도면을 구하고자 하는 것이지, 이미 설계도면을 구한 상태에서 설계를 어떻게 해야하는가 하는 질문은, 건축하기 위한 설계도를 구했으나, 내부 자재는 어떤걸 쓸지, 드릴질은 몇번 할지를 묻는것과 같기 때문이다.

이미 프로그래밍을 할 수 있고, 웹 통신을 할 수 있다면, 위 방법들을 통해 적어도, 낮은 수준의 코딩에서라도 GET Method를 구현할 수 있다고 생각한다.


 

[RESTful API] 1. RESTful과 API

어떤 서비스를 개발할 때 본래 필수적인 기능은 아니었지만, 이제는 필수적인 기능이 되어버린 API와 관련하여 글을 작성하려 한다. 이 중 굉장히 많이 쓰이고, 한번도 안 써본 사람은 있어도 한

dev-whoan.xyz

 

[RESTful API 설계하기] 3. RESTful API 데이터 조회 GET Method

[RESTful API 설계하기] 1. RESTful과 API 어떤 서비스를 개발할 때 본래 필수적인 기능은 아니었지만, 이제는 필수적인 기능이 되어버린 API와 관련하여 글을 작성하려 한다. 이 중 굉장히 많이 쓰이고,

dev-whoan.xyz

 

[RESTful API 설계하기] 4. RESTful API 데이터 생성 POST Method

[RESTful API 설계하기] 1. RESTful과 API [RESTful API 설계하기] 2. REST 특징 [RESTful API] 1. RESTful과 API 어떤 서비스를 개발할 때 본래 필수적인 기능은 아니었지만, 이제는 필수적인 기능이 되어버린 AP..

dev-whoan.xyz

RESTful API는 HTTP Methods를 이용하여 데이터를 조작할 수 있는 도구다.
RESTful 하다는 것은 대표적으로 GET, POST, PUT(PATCH), DELETE, OPTIONS, HEAD를 이용하여 데이터를 조작하는 것인데, 이는 다음 글에서 얘기하도록 하고 오늘은 RESTful 하다는 것은 어떤 가이드 라인을 지켜야 하는지 얘기하려 한다. 물론 아직 나도 RESTful을 완전히 구현할 수 없기 때문에, 이 글을 읽는 독자께서 내가 설명하고자 하는 것에 의문이나 현실과 괴리감을 느낄 수 있다. 그럴 경우 알려주시면 감사하겠다.


우선, REpresentational State Transfer이라는 이름과 같이 '상태를 표현하는' 아키텍처가 RESTful API다.
상태를 표현하기 위해 많은 방법이 있겠지만, 그중 RESTful API는 HTTP 프로토콜을 이용한다. 즉, URI를 이용해 얻고자 하는 대상에 대한 상태를 획득할 수 있다.
HTTP를 이용하기 때문에, 우리가 얻는 특징은 다음과 같다.

1. 캐싱 : HTTP자체의 Last-Modified 등 태그를 이용하여 캐싱을 할 수 있으며, 필요시 기능 구현을 위한 내용을 서버에 미리 정의해 놓을 수 있다.
2. 무상태성 : HTTP 프로토콜은 요청에 대한 응답을 통한 통신이기 때문에, REST API는 응답 전/후에 아무 상태를 갖지 않는다.
3. 계층형 구조 : HTTP 프로토콜 이외의 계층을 API 요청 처리를 위한 객체(혹은 동작) 안에 정의하여 보안, 유저인증, 암호화 등을 Flexible하게 추가할 수 있다. 클라이언트는 RESTful API 서버에 단지 '요청'을 보내고, 이 안의 동작을 알 필요가 없기 때문에 이런 설계가 가능하다.

1. 캐싱

캐싱은 간단하다. 우리가 흔히 알고있는 그 캐싱을 의미하며, 같은 URI에 대해 조회 요청이 발생했을 때, 일전에 가지고 있는 데이터로 응답하기 위한 기능이다.
서버 어딘가에 캐싱을 위한 객체를 만들어 놓고, lifetime, 새로운 생성 요청 특정 트리거가 발동되면 캐싱된 데이터를 무시하고, 새로운 조회를 한 뒤에 해당 결과를 캐싱하면 된다.

2. 무상태성

무상태성은 그냥 말 그대로 HTTP는 아무 상태를 갖지 않기 때문에 발생하는 특징이다.

3. 계층형 구조

계층형 구조는 HTTP 요청이 클라이언트 <--> 서버간 발생하는 통신이고, 클라이언트는 서버가 어떻게 동작하는지 알 필요 없이 요청을 보내고, 서버는 내부의 동작을 통해 응답을 생성하여 보내면 된다.
따라서 서버는 내부에 계층을 추가할 수 있고, 이로 인해 계층형 구조(Layered Structure)라는 특징을 갖는다.
쉽게 말해 User Authenticate Layer, Cryptography Layer, Secure Layer 등 원하는 것을 서버에 구성해 놓고, 사용자는 단지 여기에 유저 토큰, 공개키, HTTPS 통신 등 알맞은 요청을 보내면 된다.


이와 별개로, HTTP를 이용하기 때문에 주의해야 할 특징들도 있다.

첫 째, URI에 목적을 명시해서는 안된다.

RESTful API는 보통 데이터의 관리를 위한 내용 제공이 대부분이고, 따라서 데이터 조회, 수정, 삭제 등 관련 내용을 수행함에 따라 직관적으로 알기 위해 다음과 같이 설계하는 경우가 있다.

http://myrest.api/user/get/name
(앞으로는 URI부분만 작성하겠다.)

즉 이처럼 uri 자체에 데이터 조작과 관련된 목적의 행위를 기술하지 않아야 한다. 데이터 조작과 관련된 행위는 모두 HTTP 6 Methods에 정의되어 있다.
즉, 위 요청은 다음과 같이 변환되어야 한다.

GET /user/name
둘 째, URI Segment를 활용하여 대상을 한정한다.
그리고 Query String을 활용해 기능을 할당해라.

Query String을 활용하여 RESTful API에 대한 접근을 하는 경우도 많지만, 만들때는 편하더라도 꽤 불편할 수 있다.
이 두번 째 내용은 내가 MkWeb에서 RESTful API를 설계하며 얻은 팁이다.
Query String은 보통 URI 제일 마지막 세그먼트 이후에 붙는 녀석인데, 다음과 같이 생겼다.

GET /user?id=짧은머리%20개발자&age=~...

RESTful API에 대해 어느정도 이해한 사람은 위 구문이 Query String을 통해 대상을 한정한 구문이다. 하지만 우리가 데이터를 검색할 때는 많은 제약조건이나 요구사항에 마주할 수 있다.
예를 들어, 검색 내용에 대해 정렬시키거나, 모두 소문자 혹은 대문자로 바꾸거나, 한 페이지에 불러올 개수를 바꾸는 등. 우리가 딱딱한 RESTful API를 설계하게 되면, 이는 수정할 수 없게된다.
혹은 대상 한정자와 추가 기능에 대해 모두 Query String으로 해버리면, 사용할 때 꽤나 까다로울 수 있다.
따라서 다음과 같이 정의하는 것이 좋다.

GET /user/id/짧은머리 개발자/age/13?order=desc&lowercase&numOfRows=20

파란색은 대상 한정자, 보라색은 추가 기능이다.

셋 째, 데이터 대상에 대한 내용이 아닌 이상 소문자 사용하고,
확장자는 표시하지 마라.

소문자는 일관된 사용성을 위해 추천하는 바고, 확장자는 보안을 위해, 그리고 조금 더 유연한 자원 활용을 위해 표시하지 마라.


이러한 특징을 잘 지켜서 작성하면 RESTful API라 칭할 수 있다. 그렇다고, 캐싱을 안했다 해서 RESTful API가 아닌 것은 아니다.
특징들은 모두 '설계를 위한 가이드라인'이지, '설계를 위한 매뉴얼' 같은 것이 아니다. 그렇다 해서 딱 하나만 지키고 RESTful API라 하는 사람은 없을거라 믿는다.

[RESTful API 설계하기] 2. REST 특징

[RESTful API] 1. RESTful과 API 어떤 서비스를 개발할 때 본래 필수적인 기능은 아니었지만, 이제는 필수적인 기능이 되어버린 API와 관련하여 글을 작성하려 한다. 이 중 굉장히 많이 쓰이고, 한번도 안

dev-whoan.xyz

[RESTful API 설계하기] 3. RESTful API 데이터 조회 GET Method

[RESTful API 설계하기] 1. RESTful과 API 어떤 서비스를 개발할 때 본래 필수적인 기능은 아니었지만, 이제는 필수적인 기능이 되어버린 API와 관련하여 글을 작성하려 한다. 이 중 굉장히 많이 쓰이고,

dev-whoan.xyz

[RESTful API 설계하기] 4. RESTful API 데이터 생성 POST Method

[RESTful API 설계하기] 1. RESTful과 API [RESTful API 설계하기] 2. REST 특징 [RESTful API] 1. RESTful과 API 어떤 서비스를 개발할 때 본래 필수적인 기능은 아니었지만, 이제는 필수적인 기능이 되어버린 AP..

dev-whoan.xyz

어떤 서비스를 개발할 때 본래 필수적인 기능은 아니었지만, 이제는 필수적인 기능이 되어버린 API와 관련하여 글을 작성하려 한다.
이 중 굉장히 많이 쓰이고, 한번도 안 써본 사람은 있어도 한번만 쓰는 사람은 없는 RESTful API와 관련된 글을 작성할 것이다.


API, 도대체 뭐길래?

Application Programming Interface. 말 그대로 애플리케이션을 프로그래밍하기 위한 인터페이스다.
어떤 서비스에는 많은 시스템이 결합하게 되고, 각 시스템은 서로 다른 성격을 가진 녀석들이다.
예를 들어 웹 서비스를 개발한다 할 때, 간단하게는 서버와 클라이언트로 나눌 수 있고,
서버는 그 안에 데이터베이스, 파일 시스템, 웹 서버 ... 가 존재하며, 클라이언트도 모바일, 데스크탑, IoT등 여러 가지로 나눌 수 있다.
즉 어떤 서비스를 개발 하려면, 위와 같은 성격이 다른 녀석들을 모두 설계, 개발해야 하고, 결국에는 통합하여 하나의 서비스를 제공해야 한다.
API는 이 때 사용할 수 있는 어떤 인터페이스다.
Interface, 예전에 인터페이스와 관련된 내용을 작성했는데, 해당 글의 내용을 빌려 정의하자면 다음과 같이 말할 수 있다.

여러 사람이 함께 작업할 때, 틀이 되는 것 또는 그러한 가이드라인

RESTful 하다는건 뭐지?
API는 이제 알겠는데..

많은 사람들이 헷갈리는게 있는데, REST API는 없다. 다만, RESTful 한 API를 설계 하고, 이러한 것을 REST API라고 줄여서 부르기는 한다. 나 또한 REST API로 줄여서 부를 때가 많다.
내가 MkWeb의 RESTful API를 개발할 때 애를 먹었던 이유도 위와 같이, 무지에서 비롯한 사고의 불가능, 즉 설계를 할 수 있는 밑바탕이 없었기 때문에, 오랜 시간이 걸렸고, 시행착오를 많이 거쳤다. 이론을 바탕으로, 설계할 수 있어야 한다고 생각하는 나지만, RESTful 그 자체가 어떤 설명임에도 불구하고, 그래서 REST API는 어떻게 만드는건데?라는 생각으로 시간을 많이 소모했다.

RESTful 하다.

RESTful 하다는 것은 기본적으로 다음과 같은 의미를 갖는다고 나는 정의내렸다.

HTTP Methods를 사용하여 단말간 통신하면서 필요한 정보를 주고 받을 수 있는 Tool. 또는 그러한 방식

'서버'와 이를 이용하는 '엔드 포인트'의 통신이라 할 수 있지만, 사실 요즘 세상에 그것도 Blockchain이 크게 발전하고 있는 시대에 이르러 이러한 구시대적인 발상으로 정의하고 싶지 않았고, 따라서 '단말간 통신'이라고 나는 정의내렸다.
여기까지 아무런 질문없이 이해했다면, 그리고 단 한번도 RESTful API를 접해본 적이 없다면 한번 깊게 생각해보길 바란다.

웹 사이트를 제작 할 때, float: left로 둔 속성들에 대해 빈공간이 생기는 걸 볼 수 있다.

HTML을 처음 시도한다면 아래와 같은 코드를 입력했을 때, 빈공간이 없어야 한다고 생각할 수 있다.

#p-wrapper{
	float: left;
	background-color: #f1cc82;
}

.p-tag{
	display: inline-block;
	background-color: #ccc;
}
<div id="p-wrapper">
  <p class="p-tag">너</p>
  <p class="p-tag">와</p>
  <p class="p-tag">나</p>
</div>

빈공간이 보인다

그럼에도 불구하고 위 사진처럼 너 와 나 사이에 공간이 생기는걸 볼 수 있는데, 이는 버그가 아니라 HTML 문서에서 줄바꿈이 인식되어 공간이 발생한 것이다. 즉 이를 해결하기 위해서는 빈공간에 대한 사이즈를 줄여야 하는데, 다음과 같은 방법이 있다.

1. <p> 태그를 작성하면서 엔터(줄바꿈)을 하지 않는다.
2. p-wrapper내부에 있는 공간을 인식하는 것 이기 때문에, p-wrapper내의 글자 크기를 줄인다.
3. <p>태그의 닫힘 문자를 건너뛴다. (</p>를 쓰지 않는다. 이는 문제가 될 수 있어서 비추천...)

1번은 다음과 같다.

<div id="p-wrapper">
<p class="p-tag">너</p><p class="p-tag">와</p><p class="p-tag">나</p>
</div>

그러나 이 역시 p태그의 요소와 내용이 간결하기 때문에 보기 쉽지만, 클래스가 여러 개 들어가거나, 내용이 길어질 경우 꽤 tricky 해질 수 있기 때문에 비추천 한다.

그래서 내가 주로 사용하는 방법은 2번 방법이다. css에서 p-wrapper의 글자 크기(줄바꿈을 없애기 위해)를 0으로 설정하고, p-wrapper내에 직접적인 글자를 작성하지 않는 것이다. 

#p-wrapper{
	float: left;
	background-color: #f1cc82;
    font-size: 0;	/* 여기서 p-wrapper의 글자를 지우고 */
}

.p-tag{
	display: inline-block;
	background-color: #ccc;
    font-size: 16px; /* 여기서 p tag의 글자 크기를 설정한다. */
}

만약 p-tag에서 font-size를 지정해주지 않으면, 다음과 같은 문제가 발생할 수 있으니, 꼭 p-wrapper 내부의 어떤 요소에 글자를 작성한다면, 해당 요소의 css에서 글자 크기를 반드시 지정해 줘야 한다.

아무것도 없다!

정상적으로 모든 요소에 글자 크기 설정을 진행하고 나면, 아래와 같이 빈 공간이 사라진 채로 요소를 붙일 수 있다.

너와나가 드디어 붙어있다!

+ Recent posts