ํฐ์คํ ๋ฆฌ ๋ทฐ
[JavaScript] REST API
๊ฐ๋ฐ๊ฐ๊ตด๐ธ 2022. 8. 16. 00:46REST API(REpresentational State Transfer)๋?
REST๋ HTTP๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ์ ๋ฆฌ์์ค์ ์ ๊ทผํ๋ ๋ฐฉ์์ ๊ท์ ํ ์ํคํ ์ฒ๊ณ , REST API๋ REST๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์๋น์ค API๋ฅผ ๊ตฌํํ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
- *๋ก์ด ํ๋ฉ์ด ์์ ์ 2000๋ ๋ ผ๋ฌธ์์ ๋ฐํ ๋น์ ์น HTTP๋ฅผ ์ ๋๋ก ์ฌ์ฉํ์ง ๋ชปํ๊ณ ์๋ ์ํฉ์ ๋ณด๊ณ ์๊ฐํจ
- HTTP์ ์ฅ์ ์ ์ต๋ํ ํ์ฉํ ์ ์๋ ์ํคํ ์ฒ
- HTTP ํ๋กํ ์ฝ์ ์๋์ ๋ง๊ฒ ๋์์ธํ๋๋ก ์ ๋ํจ
- REST์ ๊ธฐ๋ณธ ์์น์ ์ฑ์คํ ์งํจ ์๋น์ค ๋์์ธ์ "RESTful"์ด๋ผ๊ณ ํํ
*๋ก์ด ํ๋ฉ : ์ํ์น HTTP ์๋ฒ ํ๋ก์ ํธ์ ๊ณต๋ ์ค๋ฆฝ์๋ก HTTP/1.0๊ณผ 1.1์ ์คํ ์์ฑ์ ์ฐธ์ฌํจ
REST API์ ๊ตฌ์ฑ
REST API๋ ์์(resorce), ํ์(verb), ํํ(representations)์ 3๊ฐ์ง ์์๋ก ๊ตฌ์ฑ๋ฉ๋๋ค. ์ด๋ฌํ REST๋ ์์ฒด ํํ ๊ตฌ์กฐ๋ก ๊ตฌ์ฑ๋์ด REST API๋ง์ผ๋ก HTTP ์์ฒญ์ ๋ด์ฉ์ ์ดํดํ ์ ์์ต๋๋ค.
๊ตฌ์ฑ ์์ | ๋ด์ฉ | ํํ ๋ฐฉ๋ฒ |
์์ | ์์ | URL(์๋ํฌ์ธํธ) |
ํ์ | ์์์ ๋ํ ํ์ | HTTP ์์ฒญ ๋ฉ์๋ |
ํํ | ์์์ ๋ํ ํ์์ ๊ตฌ์ฒด์ ๋ด์ฉ | ํ์ด๋ก๋ |
REST API์ ์ค๊ณ ์์น
REST์์ ๊ฐ์ฅ ์ค์ํ ๊ธฐ๋ณธ์ ์ธ ์์น์ 2๊ฐ์ง๋ก, URL๋ ๋ฆฌ์์ค๋ฅผ ํํํ๋ ๋ฐ ์ง์คํ๊ณ ํ์์ ๋ํ ์ ์๋ HTTP ์์ฒญ ๋ฉ์๋๋ฅผ ํตํด ํ๋ ๊ฒ์ด RESTful API๋ฅผ ์ค๊ณํ๋ ์ค์ฌ ๊ท์น์ ๋๋ค.
1. URL๋ ๋ฆฌ์์ค๋ฅผ ํํํด์ผ ํฉ๋๋ค.
URL๋ ๋ฆฌ์์ค๋ฅผ ํํํ๋๋ฐ ์ค์ ์ ๋์ด์ผ ํฉ๋๋ค. ๋ฆฌ์์ค๋ฅผ ์๋ณํ ์ ์๋ ์ด๋ฆ์ ๋์ฌ๋ณด๋ค๋ ๋ช ์ฌ๋ฅผ ์ฌ์ฉํด์ผ ํ๊ธฐ ๋๋ฌธ์ ์ด๋ฆ์ get ๊ฐ์ ํ์์ ๋ํ ํํ์ด ๋ค์ด๊ฐ์๋ ์ ๋ฉ๋๋ค.
# bad
GET /getTodos/1
GET /todos/show/1
# good
GET /todos/1
2. ๋ฆฌ์์ค์ ๋ํ ํ์๋ HTTP ์์ฒญ ๋ฉ์๋๋ก ํํํฉ๋๋ค.
HTTP ์์ฒญ ๋ฉ์๋๋ ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ์๊ฒ ์์ฒญ์ ์ข ๋ฅ์ ๋ชฉ์ (๋ฆฌ์์ค์ ๋ํ ํ์)์ ์๋ฆฌ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ์ฃผ๋ก 5๊ฐ์ง์ ์์ฒญ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ CRUD๋ฅผ ๊ตฌํํฉ๋๋ค.
HTTP ์์ฒญ ๋ฉ์๋ | ์ข ๋ฅ | ๋ชฉ์ | ํ์ด๋ก๋ |
GET | index/retrieve | ๋ชจ๋ /ํน์ ๋ฆฌ์๋ ์ทจ๋ | X |
POST | create | ๋ฆฌ์์ค ์์ฑ | O |
PUT | replace | ๋ฆฌ์์ค์ ์ ์ฒด ๊ต์ฒด | O |
PATCH | modify | ๋ฆฌ์์ค์ ์ผ๋ถ ์์ | O |
DELETE | delete | ๋ชจ๋ /ํน์ ๋ฆฌ์์ค ์ญ์ | X |
๋ฆฌ์์ค์ ๋ํ ํ์๋ HTTP ์์ฒญ ๋ฉ์๋๋ฅผ ํตํด ํํํ๋ฉฐ URL์ ํํํ์ง ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๋ฆฌ์์ค๋ฅผ ์ทจ๋ํ๋ ๊ฒฝ์ฐ GET, ๋ฆฌ์์ค๋ฅผ ์ญ์ ํ๋ ๊ฒฝ์ฐ DELETE๋ฅผ ์ฌ์ฉํ์ฌ ๋ฆฌ์์ค์ ๋ํ ํ์๋ฅผ ๋ช ํํ ํํํฉ๋๋ค.
# bad
GET /getTodos/delete/1
# good
DELETE /todos/1
JSON Server๋ฅผ ์ด์ฉํ REST API ์ค์ต
HTTP ์์ฒญ์ ์ ์กํ๊ณ ์๋ต์ ๋ฐ๊ธฐ ์ํด์ ์๋ฒ๊ฐ ํ์ํฉ๋๋ค. ๋ฐ๋ผ์ JSON Server๋ฅผ ์ฌ์ฉํด ๊ฐ์ REST API ์๋ฒ๋ฅผ ๊ตฌ์ถํ์ฌ HTTP ์์ฒญ์ ์ ์กํ๊ณ ์๋ต์ ๋ฐ์๋ณด๊ฒ ์ต๋๋ค.
JSON Server ์ค์น
JSON Server๋ json ํ์ผ์ ์ฌ์ฉํ์ฌ ๊ฐ์ REST API ์๋ฒ๋ฅผ ๊ตฌ์ถํ ์ ์๋ ํด์ ๋๋ค. ๋จผ์ npm์ ์ฌ์ฉํ์ฌ ํฐ๋ฏธ๋์์ ๋ค์๊ณผ ๊ฐ์ด ๋ช ๋ น์ด๋ฅผ ์ ๋ ฅํ์ฌ JSON Server์ ์ค์นํฉ๋๋ค.
mkdir json-server-exam
cd json-server-exam
npm init -y
npm install json-server --save-dever --save-dev
db.json ํ์ผ ์์ฑ
ํ๋ก์ ํธ ๋ฃจํธ ํด๋(/json-server-exam)์ ๋ค์๊ณผ ๊ฐ์ด db.json ํ์ผ์ ์์ฑํฉ๋๋ค.
db.json ํ์ผ์ ๋ฆฌ์์ค๋ฅผ ์ ๊ณตํ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ญํ ์ ํฉ๋๋ค.
{
"todos": [
{
"id": 1,
"content": "HTML",
"completed": true
},
{
"id": 2,
"content": "CSS",
"completed": false
},
{
"id": 3,
"content": "Javascript",
"completed": true
}
]
}
JSON Server ์คํ
ํฐ๋ฏธ๋์์ ๋ค์๊ณผ ๊ฐ์ด ๋ช ๋ น์ด๋ฅผ ์ ๋ ฅํ์ฌ JSON Server๋ฅผ ์คํํฉ๋๋ค. JSON Server๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ญํ ์ ํ๋ db.json ํ์ผ์ ๋ณ๊ฒฝ์ ๊ฐ์งํ๊ฒ ํ๋ ค๋ฉด watch ์ต์ ์ ์ถ๊ฐํฉ๋๋ค. ๋ง์ฝ, ํฌํธ๋ฅผ ๋ณ๊ฒฝํ๋ ค๋ฉด port ์ต์ ์ ์ถ๊ฐํฉ๋๋ค.
## ๊ธฐ๋ณธ ํฌํธ(3000) ์ฌ์ฉ / watch ์ต์
์ ์ฉ
json-server --watch db.json
## ํฌํธ ๋ณ๊ฒฝ / watch ์ต์ ์ ์ฉ
json-server --watch db.json --port 5000
์์ ๊ฐ์ด ๋งค๋ฒ ๋ช ๋ น์ด๋ฅผ ์ ๋ ฅํ๋ ๊ฒ์ ๋ฒ๊ฑฐ๋ก์ฐ๋ package.json ํ์ผ์ scripts๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์์ ํ์ฌ ํฐ๋ฏธ๋์์ npm start ๋ช ๋ น์ด๋ฅผ ํตํด JSON Server๋ฅผ ์คํํฉ๋๋ค.
GET ์์ฒญ
todos ๋ฆฌ์์ค์์ ๋ชจ๋ todo๋ฅผ ์ทจ๋(index)ํฉ๋๋ค.
JSON Server์ ๋ฃจํธ ํด๋(/json-server-exam)์ public ํด๋๋ฅผ ์์ฑํ๊ณ JSON Server๋ฅผ ์ค๋จํ ํ ์ฌ์คํํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ public ํด๋์ ๋ค์ get_index.html์ ์ถ๊ฐํ๊ณ ๋ธ๋ผ์ฐ์ ์์ http://localhost:3000/get_index.html๋ก ์ ์ํฉ๋๋ค.
<!DOCTYPE html>
<html>
<body>
<pre></pre>
<script>
// XMLHttpRequest ๊ฐ์ฒด ์์ฑ
const xhr = new XMLHttpRequest();
// HTTP ์์ฒญ ์ด๊ธฐํ
// todos ๋ฆฌ์์ค์์ ๋ชจ๋ todo๋ฅผ ์ทจ๋(index)
xhr.open('GET', '/todos');
// HTTP ์์ฒญ ์ ์ก
xhr.send();
// load ์ด๋ฒคํธ๋ ์์ฒญ์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋ ๊ฒฝ์ฐ ๋ฐ์ํ๋ค.
xhr.onload = () => {
// status ํ๋กํผํฐ ๊ฐ์ด 200์ด๋ฉด ์ ์์ ์ผ๋ก ์๋ต๋ ์ํ๋ค.
if (xhr.status === 200) {
document.querySelector('pre').textContent = xhr.response;
} else {
console.error('Error', xhr.status, xhr.statusText);
}
};
</script>
</body>
</html>
todos ๋ฆฌ์์ค์์ id๋ฅผ ์ฌ์ฉํ์ฌ ํน์ todo๋ฅผ ์ทจ๋(retrieve)ํ๊ธฐ ์ํด์ public ํด๋์ ๋ค์ get_retrieve.html์ ์ถ๊ฐํ๊ณ ๋ธ๋ผ์ฐ์ ์์ http://localhost:3000/get_retrieve.html๋ก ์ ์ํฉ๋๋ค.
<!DOCTYPE html>
<html>
<body>
<pre></pre>
<script>
// XMLHttpRequest ๊ฐ์ฒด ์์ฑ
const xhr = new XMLHttpRequest();
// HTTP ์์ฒญ ์ด๊ธฐํ
// todos ๋ฆฌ์์ค์์ id๋ฅผ ์ฌ์ฉํ์ฌ ํน์ todo๋ฅผ ์ทจ๋(retrieve)
xhr.open('GET', '/todos/1');
// HTTP ์์ฒญ ์ ์ก
xhr.send();
// load ์ด๋ฒคํธ๋ ์์ฒญ์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋ ๊ฒฝ์ฐ ๋ฐ์ํ๋ค.
xhr.onload = () => {
// status ํ๋กํผํฐ ๊ฐ์ด 200์ด๋ฉด ์ ์์ ์ผ๋ก ์๋ต๋ ์ํ๋ค.
if (xhr.status === 200) {
document.querySelector('pre').textContent = xhr.response;
} else {
console.error('Error', xhr.status, xhr.statusText);
}
};
</script>
</body>
</html>
POST ์์ฒญ
todos ๋ฆฌ์์ค์ ์๋ก์ด todo๋ฅผ ์์ฑํฉ๋๋ค. POST ์์ฒญ ์์๋ setRequestHeader ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ์์ฒญ ๋ชธ์ฒด์ ๋ด์ ์๋ฒ๋ก ์ ์กํ ํ์ด๋ก๋์ MIME ํ์ ์ ์ง์ ํด์ผ ํฉ๋๋ค.
public ํด๋์ ๋ค์ post.html์ ์ถ๊ฐํ๊ณ ๋ธ๋ผ์ฐ์ ์์ http://localhost:3000/post.html๋ก ์ ์ํฉ๋๋ค.
<!DOCTYPE html>
<html>
<body>
<pre></pre>
<script>
// XMLHttpRequest ๊ฐ์ฒด ์์ฑ
const xhr = new XMLHttpRequest();
// HTTP ์์ฒญ ์ด๊ธฐํ
// todos ๋ฆฌ์์ค์ ์๋ก์ด todo๋ฅผ ์์ฑ
xhr.open('POST', '/todos');
// ์์ฒญ ๋ชธ์ฒด์ ๋ด์ ์๋ฒ๋ก ์ ์กํ ํ์ด๋ก๋์ MIME ํ์
์ ์ง์
xhr.setRequestHeader('content-type', 'application/json');
// HTTP ์์ฒญ ์ ์ก
// ์๋ก์ด todo๋ฅผ ์์ฑํ๊ธฐ ์ํด ํ์ด๋ก๋๋ฅผ ์๋ฒ์ ์ ์กํด์ผ ํ๋ค.
xhr.send(JSON.stringify({ id: 4, content: 'Angular', completed: false }));
// load ์ด๋ฒคํธ๋ ์์ฒญ์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋ ๊ฒฝ์ฐ ๋ฐ์ํ๋ค.
xhr.onload = () => {
// status ํ๋กํผํฐ ๊ฐ์ด 200(OK) ๋๋ 201(Created)์ด๋ฉด ์ ์์ ์ผ๋ก ์๋ต๋ ์ํ๋ค.
if (xhr.status === 200 || xhr.status === 201) {
document.querySelector('pre').textContent = xhr.response;
} else {
console.error('Error', xhr.status, xhr.statusText);
}
};
</script>
</body>
</html>
PUT ์์ฒญ
PUT์ ํน์ ๋ฆฌ์์ค ์ ์ฒด๋ฅผ ๊ต์ฒดํ ๋ ์ฌ์ฉํฉ๋๋ค. ๋ค์ ์์ ์์๋ todos ๋ฆฌ์์ค์์ id๋ก todo๋ฅผ ํน์ ํ์ฌ id ๊ฐ์ ์ ์ธํ ๋ฆฌ์์ค ์ ์ฒด๋ฅผ ๊ต์ฒดํฉ๋๋ค. PUT ์์ฒญ ์์๋ setRequestHeader ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ์์ฒญ ๋ชธ์ฒด์ ๋ด์ ์๋ฒ๋ก ์ ์กํ ํ์ด๋ก๋์ MIME ํ์ ์ ์ง์ ํด์ผ ํฉ๋๋ค.
public ํด๋์ ๋ค์ put.html์ ์ถ๊ฐํ๊ณ ๋ธ๋ผ์ฐ์ ์์ http://localhost:3000/put.html๋ก ์ ์ํฉ๋๋ค.
<!DOCTYPE html>
<html>
<body>
<pre></pre>
<script>
// XMLHttpRequest ๊ฐ์ฒด ์์ฑ
const xhr = new XMLHttpRequest();
// HTTP ์์ฒญ ์ด๊ธฐํ
// todos ๋ฆฌ์์ค์์ id๋ก todo๋ฅผ ํน์ ํ์ฌ id๋ฅผ ์ ์ธํ ๋ฆฌ์์ค ์ ์ฒด๋ฅผ ๊ต์ฒด
xhr.open('PUT', '/todos/4');
// ์์ฒญ ๋ชธ์ฒด์ ๋ด์ ์๋ฒ๋ก ์ ์กํ ํ์ด๋ก๋์ MIME ํ์
์ ์ง์
xhr.setRequestHeader('content-type', 'application/json');
// HTTP ์์ฒญ ์ ์ก
// ๋ฆฌ์์ค ์ ์ฒด๋ฅผ ๊ต์ฒดํ๊ธฐ ์ํด ํ์ด๋ก๋๋ฅผ ์๋ฒ์ ์ ์กํด์ผ ํ๋ค.
xhr.send(JSON.stringify({ id: 4, content: 'React', completed: true }));
// load ์ด๋ฒคํธ๋ ์์ฒญ์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋ ๊ฒฝ์ฐ ๋ฐ์ํ๋ค.
xhr.onload = () => {
// status ํ๋กํผํฐ ๊ฐ์ด 200์ด๋ฉด ์ ์์ ์ผ๋ก ์๋ต๋ ์ํ๋ค.
if (xhr.status === 200) {
document.querySelector('pre').textContent = xhr.response;
} else {
console.error('Error', xhr.status, xhr.statusText);
}
};
</script>
</body>
</html>
PATCH ์์ฒญ
PATCH์ ํน์ ๋ฆฌ์์ค ์ผ๋ถ๋ฅผ ์์ ํ ๋ ์ฌ์ฉํฉ๋๋ค. ๋ค์ ์์ ์์๋ todos ๋ฆฌ์์ค์์ id๋ก todo๋ฅผ ํน์ ํ์ฌ completed๋ง ์์ ํฉ๋๋ค. PATCH ์์ฒญ ์์๋ setRequestHeader ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ์์ฒญ ๋ชธ์ฒด์ ๋ด์ ์๋ฒ๋ก ์ ์กํ ํ์ด๋ก๋์ MIME ํ์ ์ ์ง์ ํด์ผ ํฉ๋๋ค.
public ํด๋์ ๋ค์ patch.html์ ์ถ๊ฐํ๊ณ ๋ธ๋ผ์ฐ์ ์์ http://localhost:3000/patch.html๋ก ์ ์ํฉ๋๋ค.
<!DOCTYPE html>
<html>
<body>
<pre></pre>
<script>
// XMLHttpRequest ๊ฐ์ฒด ์์ฑ
const xhr = new XMLHttpRequest();
// HTTP ์์ฒญ ์ด๊ธฐํ
// todos ๋ฆฌ์์ค์ id๋ก todo๋ฅผ ํน์ ํ์ฌ completed๋ง ์์
xhr.open('PATCH', '/todos/4');
// ์์ฒญ ๋ชธ์ฒด์ ๋ด์ ์๋ฒ๋ก ์ ์กํ ํ์ด๋ก๋์ MIME ํ์
์ ์ง์
xhr.setRequestHeader('content-type', 'application/json');
// HTTP ์์ฒญ ์ ์ก
// ๋ฆฌ์์ค๋ฅผ ์์ ํ๊ธฐ ์ํด ํ์ด๋ก๋๋ฅผ ์๋ฒ์ ์ ์กํด์ผ ํ๋ค.
xhr.send(JSON.stringify({ completed: false }));
// load ์ด๋ฒคํธ๋ ์์ฒญ์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋ ๊ฒฝ์ฐ ๋ฐ์ํ๋ค.
xhr.onload = () => {
// status ํ๋กํผํฐ ๊ฐ์ด 200์ด๋ฉด ์ ์์ ์ผ๋ก ์๋ต๋ ์ํ๋ค.
if (xhr.status === 200) {
document.querySelector('pre').textContent = xhr.response;
} else {
console.error('Error', xhr.status, xhr.statusText);
}
};
</script>
</body>
</html>
DELETE ์์ฒญ
todos ๋ฆฌ์์ค์์ id๋ฅผ ์ฌ์ฉํ์ฌ todo๋ฅผ ์ญ์ ํฉ๋๋ค.
public ํด๋์ ๋ค์ delete.html์ ์ถ๊ฐํ๊ณ ๋ธ๋ผ์ฐ์ ์์ http://localhost:3000/delete.html๋ก ์ ์ํฉ๋๋ค.
<!DOCTYPE html>
<html>
<body>
<pre></pre>
<script>
// XMLHttpRequest ๊ฐ์ฒด ์์ฑ
const xhr = new XMLHttpRequest();
// HTTP ์์ฒญ ์ด๊ธฐํ
// todos ๋ฆฌ์์ค์์ id๋ฅผ ์ฌ์ฉํ์ฌ todo๋ฅผ ์ญ์ ํ๋ค.
xhr.open('DELETE', '/todos/4');
// HTTP ์์ฒญ ์ ์ก
xhr.send();
// load ์ด๋ฒคํธ๋ ์์ฒญ์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋ ๊ฒฝ์ฐ ๋ฐ์ํ๋ค.
xhr.onload = () => {
// status ํ๋กํผํฐ ๊ฐ์ด 200์ด๋ฉด ์ ์์ ์ผ๋ก ์๋ต๋ ์ํ๋ค.
if (xhr.status === 200) {
document.querySelector('pre').textContent = xhr.response;
} else {
console.error('Error', xhr.status, xhr.statusText);
}
};
</script>
</body>
</html>
[์ถ์ฒ] ๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ Deep Dive
'JavaScript > ๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ Deep Dive' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[JavaScript] ์ ๋๋ ์ดํฐ์ async/await (0) | 2022.08.17 |
---|---|
[JavaScript] ํ๋ก๋ฏธ์ค(Promise) (0) | 2022.08.17 |
[JavaScript] Ajax (0) | 2022.08.15 |
[JavaScript] ํ์ด๋จธ (0) | 2022.08.13 |
[JavaScript] ์ด๋ฒคํธ (0) | 2022.08.13 |
- Total
- Today
- Yesterday
- ํ๋กํ ์ฝ
- JavaScript
- ๋ฐฑ์ค node.js
- ๋คํธ์ํฌ
- ๋ค์ด๋๋ฏน ํ๋ก๊ทธ๋๋ฐ
- ์๋ฐ์คํฌ๋ฆฝํธ
- ์ ์ญ ๋ณ์
- map
- ํ๋กํผํฐ
- ํจ์ํ ํ๋ก๊ทธ๋๋ฐ
- git
- ๋ฐฑ์ค
- http
- fp
- Baekjoon
- ์นด์นด์ค ์ธํด
- ํ๋ก๊ทธ๋๋จธ์ค
- ๋์์ธ ํจํด
- TDD
- ๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ deep dive
- ๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ
- ์ด๋ถํ์
- ํฌํฌ์ธํฐ
- ๋ฐฑ์ค javascript
- ์ฝ๋ฉํ ์คํธ
- ๋ ์์ปฌ ํ๊ฒฝ
- 2019 ์นด์นด์ค ๊ฐ๋ฐ์ ๊ฒจ์ธ ์ธํด
- ์๋ฐ
- ์ด์์ฒด์
- ์๊ณ ๋ฆฌ์ฆ
์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
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 |