๋ณธ๋ฌธ์œผ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ

ยท ์•ฝ 1๋ถ„

Github์— ์žˆ๋Š” Pull Request๋ฅผ Local๋กœ ๊ฐ€์ ธ์˜ค๊ธฐ#

git fetch origin pull/{ํ’€ ๋ฆฌํ€˜์ŠคํŠธ ID}/head:{๋ธŒ๋žœ์น˜ ์ด๋ฆ„}git checkout {๋ธŒ๋žœ์น˜ ์ด๋ฆ„}

์—…๋ฐ์ดํŠธ๋œ Pull Request ๊ฐ€์ ธ์˜ค๊ธฐ#

git pull origin pull/{ํ’€ ๋ฆฌํ€˜์ŠคํŠธ ID}/head

ยท ์•ฝ 8๋ถ„

PMP ๊ฐ€์ด๋“œ#

OAuth#

OAuth ๊ธฐ์ˆ ์˜ ์ฐธ์—ฌ์ž

Our Service ( example.com ), User(์‚ฌ์šฉ์ž), Their(Google, Facebook, Twitter ๋“ฑ๋“ฑ)


User์—๊ฒŒ Their์˜ id , pw ๋ฅผ ๊ทธ๋Œ€๋กœ ์ „๋‹ฌ๋ฐ›๋Š” ๋ฐฉ๋ฒ•

  • User : ์ฒ˜์Œ๋ณด๋Š” ์„œ๋น„์Šค๋ฅผ ๋ฏฟ์„ ์ˆ˜ ์—†๋‹ค.

  • Our Service : ์œ ์ €์˜ id , pw ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•ด์•ผํ•  ์ฑ…์ž„์„ ์ง€๋‹ˆ๊ฒŒ ๋œ๋‹ค.

  • Their Service : ์ œ 3์ž์˜ ์„œ๋น„์Šค๊ฐ€ ๋ณธ์ธ๋“ค์˜ id , pw ๋ฅผ ๊ฐ–๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์— ๋ถˆ๋งŒ์ด ์ƒ๊ธด๋‹ค.


Their๊ฐ€ accessToken ์„ ๋ฐœ๊ธ‰ํ•˜๋Š” ๋ฐฉ๋ฒ•

  • accessToken ์€ id , pw ๊ฐ€ ์•„๋‹ˆ๋‹ค.

  • Their Service๋Š” ์ œ๊ณตํ•˜๊ธฐ ์›ํ•˜๋Š” ๊ธฐ๋Šฅ๋งŒ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค.


์šฉ์–ด#

  • Client(Our Service)

  • Resource Owner(User)

  • Resource Server(Their) + Authorization Server(์ธ์ฆ ์„œ๋ฒ„๋ฅผ ๋”ฐ๋กœ ๊ตฌ๋ถ„ํ•˜๊ธฐ๋„ ํ•จ)


๋“ฑ๋ก#

2020-12-21-201221-image-0

  • Client ID : ์„œ๋น„์Šค๋ฅผ ์‹๋ณ„ํ•˜๋Š” ์•„์ด๋””

  • Client Secret : ์„œ๋น„์Šค์— ๋Œ€ํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ (์ ˆ๋Œ€๋กœ ๋…ธ์ถœ์ด ๋˜์–ด์„  ์•ˆ๋œ๋‹ค.)

  • Authorized redirect URIs : Resource Server๊ฐ€ ์ธ์ฆ ์ฝ”๋“œ๋ฅผ ์ œ๊ณตํ•  ์„œ๋น„์Šค์˜ URL

  • Scope : Resource Server์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ (ํ•„์š”ํ•œ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ์ธ์ฆ๋งŒ ์ œ๊ณต ๊ฐ€๋Šฅ )

์†Œ์…œ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์€ ๋‹ค์Œ์˜ ๋งํฌ๊ฐ€ ๋‹ด๊ฒจ์žˆ๋‹ค.

  • http://{๋ฆฌ์†Œ์Šค ์„œ๋ฒ„์˜ ์ฃผ์†Œ}/?{ํด๋ผ์ด์–ธํŠธ ID=id}&{์Šค์ฝ”ํ”„=b,c}&{๋ฆฌ๋‹ค์ด๋ ‰ํŠธ URL=url}

๋ฆฌ์†Œ์Šค ์„œ๋ฒ„๋Š” ์œ ์ €์˜ ๋กœ๊ทธ์ธ ์ •๋ณด๋ฅผ ๋ฐ›๊ณ , ํด๋ผ์ด์–ธํŠธ ์•„์ด๋””์™€ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ URL์ด ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ๊ถŒํ•œ ํ—ˆ์šฉ์— ๋Œ€ํ•œ ์•ˆ๋‚ด๋ฅผ ์œ ์ €์—๊ฒŒ ์ „๋‹ฌํ•˜๊ณ , ์œ ์ €๊ฐ€ ํ—ˆ์šฉํ•œ ๊ถŒํ•œ์ด ๋ฌด์—‡์ธ์ง€์— ๋Œ€ํ•ด ์ €์žฅํ•œ๋‹ค.

๋ฆฌ์†Œ์Šค ์„œ๋ฒ„๋Š” authorization code ๋ฅผ ๋‹ด์•„์„œ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ URL๋กœ ์œ ์ €์˜ ๋ธŒ๋ผ์šฐ์ €๋ฅผ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ์‹œํ‚จ๋‹ค.

ํด๋ผ์ด์–ธํŠธ๋Š” authorization code ๋ฅผ ์œ ์ €์—๊ฒŒ ๋ฐ›๊ณ , ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ URL, ํด๋ผ์ด์–ธํŠธ ID, ํด๋ผ์ด์–ธํŠธ ์‹œํฌ๋ฆฟ์„ ๊ฐ–๊ณ  ๋ฆฌ์†Œ์Šค ์„œ๋ฒ„์— ์š”์ฒญํ•œ๋‹ค.

์ด ๊ณผ์ •์ด ์™„๋ฃŒ๋˜๋ฉด access token์„ ๋ฐœ๊ธ‰ํ•œ๋‹ค.

access token์„ Header: { Authorization : Bearer token } ์— ๋‹ด์•„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.


OAuth๋ฅผ ํ™œ์šฉํ•ด์„œ API ์‚ฌ์šฉํ•˜๊ธฐ#

2020-12-21-201221-image-1

Using OAuth 2.0 to Access Google APIs | Google Identity


Database Naming Convention#

๋ณต์ˆ˜ํ˜• vs ๋‹จ์ˆ˜ํ˜•#

  • ํ…Œ์ด๋ธ”์€ ์—”ํ‹ฐํ‹ฐ์˜ ์ธ์Šคํ„ด์Šค๋“ค์„ ํ‘œํ˜„ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์˜๋ฏธ์ ์œผ๋กœ ๋ณต์ˆ˜ํ˜•์ด ๋” ๋งž๋‹ค.

  • ํ…Œ์ด๋ธ”์„ ๋‹จ์ˆ˜ํ˜•์„ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ SQL ๋ฌธ์—์„œ SELECT activity.name ์œผ๋กœ ํ‘œํ˜„ํ•  ์ˆ˜์žˆ๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.

    • ํ•˜์ง€๋งŒ ๋ณต์ˆ˜ํ˜•์„ ์‚ฌ์šฉํ•˜๋”๋ผ๋„ SQL alias๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๊ทน๋ณต ๊ฐ€๋Šฅํ•˜๋‹ค.

    • SELECT id, name, description FROM products product WHERE product.name = โ€˜fooโ€™ AND product.description = โ€˜barโ€™

  • REST API์—์„œ ์ž์›์— ๋Œ€ํ•œ ์š”์ฒญ ์—ญ์‹œ ํ…Œ์ด๋ธ”์— ๋”ฐ๋ผ ๋ณต์ˆ˜ํ˜•์œผ๋กœ ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ex) GET /users/1

The table naming dilemma: singular vs. plural

camelCase vs snake_case#

  • MySQL ์—์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” ๋ฐ์ดํ„ฐ ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด์˜ ๋””๋ ‰ํ† ๋ฆฌ์— ํ•ด๋‹นํ•˜๊ณ , ํ…Œ์ด๋ธ”์€ํŒŒ์ผ์— ํ•ด๋‹นํ•œ๋‹ค. ๋”ฐ๋ผ์„œ, ์šด์˜์ฒด์ œ์˜ ๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ถ„์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค, ํ…Œ์ด๋ธ” ๋ฐ ํŠธ๋ฆฌ๊ฑฐ ์ด๋ฆ„์˜ ๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ถ„์— ์˜ํ–ฅ์„ ์ค€๋‹ค.

  • Windows๋Š” ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š์ง€๋งŒ Unix๋Š” ๊ตฌ๋ถ„, macOS๋Š” ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š๋Š” ํŒŒ์ผ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ•˜์ง€๋งŒ ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๊ตฌ๋ถ„ํ•˜๋Š” ๋ณผ๋ฅจ๋„ ์ง€์›ํ•จ.

  • ๋”ฐ๋ผ์„œ snake_case ๊ฐ€ ์ด์‹์„ฑ๊ณผ ์‚ฌ์šฉ ํŽธ์˜์„ฑ ์ธก๋ฉด์—์„œ ๊ฐ€์žฅ ๊ถŒ์žฅ๋œ๋‹ค.

  • ํ•˜์ง€๋งŒ camelCase ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ๊ณ , JS๊ฐ€ camelCase๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์—์–ป์„ ์ˆ˜ ์žˆ๋Š” ํŽธ์˜์„ฑ์ด ์žˆ๋‹ค.

  • ๋ฌด์—‡๋ณด๋‹ค ์ผ๊ด€๋œ ๊ทœ์น™์„ ์ฑ„ํƒํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹๋‹ค.

MySQL :: MySQL 8.0 Reference Manual :: 9.2.3 Identifier Case Sensitivity

RESTful API#

์„œ๋ฒ„ ์‘๋‹ต์— HTTP ์ƒํƒœ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•ด๋ผ#

์˜ค๋ฅ˜ ๋ฐœ์ƒ์‹œ API ์‚ฌ์šฉ์ž์˜ ํ˜ผ๋™์„ ์—†์• ๊ธฐ ์œ„ํ•ด ์˜ค๋ฅ˜๋ฅผ ์ •์ƒ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ๋ฐœ์ƒํ•œ ์˜ค๋ฅ˜์˜ ์ข…๋ฅ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” HTTP ์‘๋‹ต ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.ย ์ด๋ฅผ ํ†ตํ•ด API ๊ด€๋ฆฌ์ž๋Š” ๋ฐœ์ƒํ•œ ๋ฌธ์ œ๋ฅผ ์ดํ•ดํ•  ์ˆ˜์žˆ๋Š” ์ถฉ๋ถ„ํ•œ ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.ย ์˜ค๋ฅ˜๋กœ ์ธํ•ด ์‹œ์Šคํ…œ์ด์ค‘๋‹จ๋˜๋Š” ๊ฒƒ์„ ์›ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์€ ์ฑ„๋กœ ๋‘˜ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, API ์†Œ๋น„์ž๊ฐ€ ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์ธ ์˜ค๋ฅ˜ HTTP ์ƒํƒœ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • 400 ์ž˜๋ชป๋œ ์š”์ฒญ โ€“ ์ด๋Š” ํด๋ผ์ด์–ธํŠธ ์ธก ์ž…๋ ฅ์ด ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์— ์‹คํŒจ ํ•จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค .

  • 401 Unauthorized โ€“ ์‚ฌ์šฉ์ž๊ฐ€ ๋ฆฌ์†Œ์Šค์— ์•ก์„ธ์Šค ํ•  ์ˆ˜์žˆ๋Š” ๊ถŒํ•œ์ด ์—†์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค .ย ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.

  • 403 ๊ธˆ์ง€๋จ โ€“ ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ๋˜์—ˆ์ง€๋งŒ ๋ฆฌ์†Œ์Šค์— ์•ก์„ธ์Šค ํ•  ์ˆ˜ ์—†์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

  • 404 Not Found โ€“ ๋ฆฌ์†Œ์Šค๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

  • 500 ๋‚ด๋ถ€ ์„œ๋ฒ„ ์˜ค๋ฅ˜ โ€“ ์ผ๋ฐ˜์ ์ธ ์„œ๋ฒ„ ์˜ค๋ฅ˜์ž…๋‹ˆ๋‹ค.ย ์•„๋งˆ๋„ ๋ช…์‹œ ์ ์œผ๋กœ ๋˜์ ธ์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค.

  • 502ย Bad Gateway โ€“ ์—…์ŠคํŠธ๋ฆผ ์„œ๋ฒ„์˜ ์ž˜๋ชป๋œ ์‘๋‹ต์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

  • 503 ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ โ€“ ์„œ๋ฒ„ ์ธก์—์„œ ์˜ˆ๊ธฐ์น˜ ์•Š์€ ์ผ์ด ๋ฐœ์ƒํ–ˆ์Œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค (์„œ๋ฒ„ ๊ณผ๋ถ€ํ•˜, ์‹œ์Šคํ…œ์˜ ์ผ๋ถ€ ์˜ค๋ฅ˜ ๋“ฑ์ด ๋  ์ˆ˜ ์žˆ์Œ).

Best practices for REST API design - Stack Overflow Blog

Best Practices for your REST API

FE API ์—๋Ÿฌ ํ•ธ๋“ค๋ง#

Catch request errors with Axios

Handling Failed HTTP Responses With fetch()

ํƒœ๊ทธ:

ยท ์•ฝ 1๋ถ„

React Router Private Route#

https://medium.com/@thanhbinh.tran93/private-route-public-route-and-restricted-route-with-react-router-d50b27c15f5e

LocalStorage vs Cookies: Storing JWT#

https://dev.to/cotter/localstorage-vs-cookies-all-you-need-to-know-about-storing-jwt-tokens-securely-in-the-front-end-15id#:~:text=Local storage is vulnerable because,attacks involving your access token.


  • XSS ๊ณต๊ฒฉ

    • LocalStorage๋Š” ์™„์ „ํžˆ JavaScript๋กœ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๊ณ , ํƒ€์‚ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (React, jQuery, Google Analytics ...)์„ ํฌํ•จํ–ˆ์„ ๋•Œ, ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ๋‹ด๊ธด Token์„ ๊ฐˆ์ทจ๋‹นํ•  ์ˆ˜ ์žˆ๋‹ค.

https://medium.com/@ryanchenkie_40935/react-authentication-how-to-store-jwt-in-a-cookie-346519310e81

https://bezkoder.com/react-express-authentication-jwt/

https://velog.io/@yaytomato/ํ”„๋ก ํŠธ์—์„œ-์•ˆ์ „ํ•˜๊ฒŒ-๋กœ๊ทธ์ธ-์ฒ˜๋ฆฌํ•˜๊ธฐ

React SignUp API#

https://medium.com/@hirukarunathilaka/signup-form-with-real-time-validation-using-react-typescript-6a7dfb3122b5

Express Cookie ๋‹ค๋ฅธ ๋„๋ฉ”์ธ๊ฐ„ ์ „์†ก#

https://www.zerocho.com/category/NodeJS/post/5e9bf5b18dcb9c001f36b275

ยท ์•ฝ 1๋ถ„

MySQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ƒ์„ฑ#

CREATE DATABASE mydb;--- ์•„์ด๋”” ๋ฐ ํŒจ์Šค์›Œ๋“œ ์„ค์ •CREATE USER 'myuserid'@'%' IDENTIFIED BY 'mypassword';GRANT ALL ON mydb.* TO 'myuserid'@'%';FLUSH PRIVILEGES;

mydb: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ด๋ฆ„

myuserid: ์‚ฌ์šฉ์ž id

mypassword: ์‚ฌ์šฉ์ž ํŒจ์Šค์›Œ๋“œ

์‚ฌ์šฉ์ž ํŒจ์Šค์›Œ๋“œ๊ฐ€ ์ƒ๊ฐ๋‚˜์ง€ ์•Š์„ ๋•Œ#

๋ฃจํŠธ ์‚ฌ์šฉ์ž๋กœ ๋กœ๊ทธ์ธ ํ›„ ์ผ๋ฐ˜ ์‚ฌ์šฉ์ž ํŒจ์Šค์›Œ๋“œ๋Š” ์‰ฝ๊ฒŒ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ

SET PASSWORD FOR 'myuserid'@'%'='new_password';FLUSH PRIVILEGES;

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค๊ณ„#

https://medium.com/@Mareks_082/auto-increment-keys-vs-uuid-a74d81f7476a

https://tomharrisonjr.com/uuid-or-guid-as-primary-keys-be-careful-7b2aa3dcb439

https://www.percona.com/blog/2019/11/22/uuids-are-popular-but-bad-for-performance-lets-discuss/

https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/

https://medium.com/aha-official/์•„ํ•˜-rest-api-์„œ๋ฒ„-๊ฐœ๋ฐœ-6-43568d94878a

Node + Express#

https://github.com/goldbergyoni/nodebestpractices#2-error-handling-practices

TypeScript + Sequelize#

https://github.com/maximegris/typescript-express-sequelize/blob/master/src/sqlz/config/config.json

https://sequelize.org/v5/manual/migrations.html

Sequelize + Crypto#

https://medium.com/@benjaminpwagner/using-sequelize-hooks-and-crypto-to-encrypt-user-passwords-5cf1a27513d9

https://medium.com/aha-official/์•„ํ•˜-rest-api-์„œ๋ฒ„-๊ฐœ๋ฐœ-7-712e0588579f


Jest did not exit one second after the test run has completed using express#

https://stackoverflow.com/a/63299022/12983614

Wrap Async#

https://medium.com/@changjoopark/express-๋ผ์šฐํŠธ์—์„œ-async-await๋ฅผ-์‚ฌ์šฉํ•˜๋ ค๋ฉด-7e8ffe0fcc84

ยท ์•ฝ 5๋ถ„

์ธ์ฆ ์„œ๋น„์Šค ๊ธฐ์ดˆ ๊ฐ•์˜#

Auth Service Fundamentals#

  • ๊ตฌ๊ธ€๊ณผ ์œ ํŠœ๋ธŒ์˜ ์‚ฌ๋ก€ - ์ธ์ฆ์ด ํ•„์š”ํ•œ ์ด์œ ๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

2020-12-16-201216-image-0

  • ์„œ๋น„์Šค ์ œ๊ณต์ž : ํšŒ์› ํ™•๋ณด โ†’ ๋ฐ์ดํ„ฐ ๋ถ„์„ โ†’ ์„œ๋น„์Šค ๋ฐฉํ–ฅ ์„ค์ •, ๋‹ค์–‘ํ•œ ๋งˆ์ผ€ํŒ… ํ™œ์šฉ

  • ์‚ฌ์šฉ์ž : ์„œ๋น„์Šค ์ด์šฉ ํŽธ์˜์„ฑ, ๊ฐœ์ธํ™” ์„œ๋น„์Šค ์ด์šฉ

ํšŒ์› ๊ฐ€์ž…#

  • ์„œ๋น„์Šค์˜ ์ผ์›์ด ๋˜๊ธฐ ์œ„ํ•œ ์ ˆ์ฐจ

  • ์ด ๊ณผ์ •์„ ๊ฑฐ์น˜์ง€ ๋ชปํ•œ๋‹ค๋ฉด ๊ฒฝ์šฐ์— ๋”ฐ๋ผ์„œ ํ•ด๋‹น ์„œ๋น„์Šค์— ๊ฒŒ์‹œ๋˜์–ด ์žˆ๋Š” ๊ธ€ ์ž์ฒด๋ฅผ๋ชป ๋ณด๊ฒŒ ๋˜๋Š” ๋“ฑ ๊ฐ€์ž…์ž๋“ค์— ๋น„ํ•ด ํ™œ๋™์˜ ์ œ์•ฝ์ด ๋ฐœ์ƒ

๋กœ๊ทธ์ธ#

  • ๋กœ๊ทธ์ธ์€ ์ ‘๊ทผ ํ—ˆ๊ฐ€ ์ฆ๋ช…์„ ์–ป๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ์ž ์ธ์ฆ์œผ๋กœ ๊ฐœ์ธ์ด ์ปดํ“จํ„ฐ ์‹œ์Šคํ…œ์— ์ ‘๊ทผํ•˜๋Š” ์ž‘์—…

์ธ์ฆ ๋ฐฉ๋ฒ•#

2020-12-16-201216-image-1

Authentication vs Authorization#

2020-12-16-201216-image-2

  • Authorization์€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ธ์ฆ๋œ ์œ ์ €์—๊ฒŒ ์ž์›์˜ ์†Œ์œ ์ž๊ฐ€ ํ—ˆ๊ฐ€ํ•œ ์ž์›์— ์ ‘๊ทผํ• ์ˆ˜ ์žˆ๋Š” ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

OAuth 2.0#

  • OAuth 2.0์€ ๋‹ค์–‘ํ•œ ํ”Œ๋žซํผ ํ™˜๊ฒฝ์—์„œ ๊ถŒํ•œ ๋ถ€์—ฌ๋ฅผ ์œ„ํ•œ ํ‘œ์ค€ ํ”„๋กœํ† ์ฝœ

  • ์ œ 3์˜ ์•ฑ์ด ์ž์›์˜ ์†Œ์œ ์ž์ธ ์„œ๋น„์Šค ์ด์šฉ์ž๋ฅผ ๋Œ€์‹ ํ•˜์—ฌ ์„œ๋น„์Šค๋ฅผ ์š”์ฒญํ•  ์ˆ˜ ์žˆ๋„๋ก์ž์› ์ ‘๊ทผ ๊ถŒํ•œ์„ ์œ„์ž„ํ•˜๋Š” ๋ฐฉ๋ฒ•

2020-12-16-201216-image-3

2020-12-16-201216-image-4

Sample#

ํ•„์ˆ˜ ์ •๋ณด - key (์‚ฌ์šฉ์ž์— ๋Œ€ํ•œ ์œ ๋‹ˆํฌ ๊ฐ’), id , password

  • ? ์œ ์ € ์•„์ด๋””๋ฅผ key ๋กœ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ์˜ ๋ฌธ์ œ์ 

    • id ๋Š” public ํ•˜๋‹ค.

    • id ๋Š” ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋‹ค. (์œ ์ €์˜ key ๊ฐ’์ด ๋ฐ”๋€” ์ˆ˜ ์žˆ๋‹ค.)

      • ๊ด€๊ณ„๋œ ๋ฐ์ดํ„ฐ์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
  • id ๋Š” unique ํ•ด์•ผ ํ•œ๋‹ค.

    • ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ํ—ˆ์šฉํ•  ๊ฒฝ์šฐ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
  • password ๋Š” ์•”ํ˜ธํ™” ๋˜์–ด์•ผ ํ•œ๋‹ค.

2020-12-16-201216-image-5

    • ๊ฐ€์ž… ์ผ์ž
  • key ๊ฐ’์œผ๋กœ ์ˆซ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ณต๊ฒฉ์˜ ์—ฌ์ง€๋ฅผ ์ค„ ์ˆ˜ ์žˆ๋‹ค.

  • ๋ฌธ์ž์—ด์„ ๋งŽ์ด ์“ฐ๋Š”๋ฐ, ์œ ์ถ”ํ•˜๊ธฐ ์–ด๋ ค์›Œ์•ผ ํ•œ๋‹ค.

  • user_id ๋Š” ์ด๋ฉ”์ผ์„ ๋งŽ์ด ์“ฐ๋Š”๋ฐ, ์ด๋ฉ”์ผ์€ ์œ ๋‹ˆํฌ ํ•˜๋‹ค๋Š” ์ ์ด ๋ณด์žฅ๋œ๋‹ค.

    • ์ด๋ฉ”์ผ์ด ํ•ด๋‹น ์œ ์ €์˜ ์†Œ์œ ์ธ์ง€ ์ธ์ฆ ๊ณผ์ •์ด ํ•„์š”ํ•˜๋‹ค.
  • password ๋Š” ๋ฌธ์ž์™€ ์ˆซ์ž, ํŠน์ˆ˜ ๋ฌธ์ž ๋“ฑ์„ ์กฐํ•ฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

2020-12-16-201216-image-6

2020-12-16-201216-image-7

2020-12-16-201216-image-8

  • Cookie vs Session

์ฟ ํ‚ค๊ฐ€ ๋ณด์•ˆ์— ์ทจ์•ฝํ•œ ์ด์œ 

2020-12-16-201216-image-9

2020-12-16-201216-image-10

๋งŽ์€ ๊ฒฝ์šฐ ์ฟ ํ‚ค์— token ์„ ๋„ฃ๋Š”๋ฐ, ๋ณด์•ˆ ์ธก๋ฉด์—์„œ ๊ทธ๋ƒฅ ๋„ฃ๋Š” ๊ฒฝ์šฐ, ์กฐํ•ฉํ•ด์„œ ๋„ฃ๋Š”๊ฒฝ์šฐ ๋“ฑ์ด ์žˆ๋‹ค.

2020-12-16-201216-image-11

  • access token ์€ ์‹œ๊ฐ„ ๋‹จ์œ„๋ฅผ ๋งŽ์ด ์“ฐ๊ณ  ex) 6์‹œ๊ฐ„ , refresh token์€ ๋ช‡ ์ผ ๋‹จ์œ„ , ex) 1์ฃผ 2์ฃผ ํ•œ ๋‹ฌ

2020-12-16-201216-image-12

  • ์žฌ๋ฐœ๊ธ‰ ํ•˜์ง€ ์•Š๊ณ  ๊ธฐ์กด ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋ฉด, refresh token์€ ์–ธ์  ๊ฐ€ ๋งŒ๋ฃŒ ๋˜์–ด ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ถˆํŽธํ•จ์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค.

  • ํ•ญ์ƒ ์‹ ๊ทœ๋กœ ๋ฐœ๊ธ‰ํ•˜๋ฉด, ์—ฌ๋Ÿฌ ํ”Œ๋žซํผ ๊ฐ„์— ์žฌ๋ฐœ๊ธ‰ ๋œ ํ† ํฐ์„ ์–ด๋–ป๊ฒŒ ๋™๊ธฐํ™” ํ•  ๊ฒƒ์ด๋ƒ์— ๋Œ€ํ•œ ๊ณ ๋ฏผ์ด ํ•„์š”ํ•˜๋‹ค.


Storybook ๊ธ€๋กœ๋ฒŒ ์Šคํƒ€์ผ ์„ค์ •#

preview.js

import React from 'react';
import {ThemeProvider} from 'styled-components';
import GlobalStyle from 'src/styles/GlobalStyle';import theme from 'src/styles/theme';
export const parameters = {    actions: {argTypesRegex: '^on[A-Z].*'},};
export const decorators = [    (Story) => (        <ThemeProvider theme={theme}>            <GlobalStyle />            <Story />        </ThemeProvider>    ),];

Styled-components#

The Advanced Way to Style with Styled Components

์ด์Šˆ - styled-components์˜ craeteGlobalStyle ์ ์šฉ ์‹œ user agent stylesheet๊ฐ€ override ํ•˜๋Š” ์ด์Šˆ

2020-12-16-201216-image-13


Validation#

Use RegEx To Test Password Strength In JavaScript

Form Validation

ยท ์•ฝ 3๋ถ„

React + TypeScript + Storybook + ESLint ์„ธํŒ…#

ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ#

yarn create react-app my-app-name --template typescript

CRA + ESLint + Prettier#

Create-React-App with TypeScript, ESLint, Prettier, and Github Actions

Husky + lint-staged#

์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํŒŒ์ผ ์ง€์šฐ๊ธฐ#

.gitignore#

.gitignore ๋Š” ํ”„๋กœ์ ํŠธ์—์„œ ์ค‘์š”ํ•œ ๊ฒƒ์œผ๋กœ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ ์ž์ฒด์—์„œ ์ƒ์„ฑํ•œ ํŒŒ์ผ์ด๋‚˜ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๋‚˜์—ดํ•ด์•ผ ํ•œ๋‹ค. ๊ฐ€์žฅ ์ข‹์€ ์˜ˆ๋Š” ์บ์‹œ ํŒŒ์ผ, ๋กœ๊ทธ, ๋กœ์ปฌ ๊ตฌ์„ฑ ๋“ฑ์ด๋‹ค.

.vscode , .idea , .DS_Store ๋“ฑ์€ ํ”„๋กœ์ ํŠธ์˜ .gitignore ๋ณด๋‹ค ์ปดํ“จํ„ฐ์˜ ๊ธ€๋กœ๋ฒŒ .gitignore ์— ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

๊ธ€๋กœ๋ฒŒ .gitignore ๋Š” home ๋””๋ ‰ํ† ๋ฆฌ์˜ .gitconfig ์„ ๋ณด๋ฉด ์•Œ ์ˆ˜ ์žˆ๋‹ค.

[core]    excludesfile = /Users/{home}/.gitignore_global

Don't put .idea and .vscode directories to project's .gitignore

ํด๋” ๊ตฌ์„ฑํ•˜๊ธฐ#

โ””โ”€โ”€ src    โ”œโ”€โ”€ components        โ””โ”€โ”€ src    โ”œโ”€โ”€ pages    โ”œโ”€โ”€ App.tsx    โ””โ”€โ”€ index.tsx

Storybook ์„ค์น˜ํ•˜๊ธฐ#

npx sb init

https://storybook.js.org/docs/react/get-started/install


์›น ํฐํŠธ ์‚ฌ์šฉ#

NAVER D2


free illustration#

unDraw - Open source illustrations for any idea


Styled Components#

The Advanced Way to Style with Styled Components

Thoughts around design systems: implementationโ€Š-โ€ŠReact, Styled-Components, and more

How does the ampersand work in styled-components?

The Sass Ampersand | CSS-Tricks

Type Guard#

https://www.typescriptlang.org/docs/handbook/advanced-types.html

validate css unit value#

https://www.reddit.com/r/learnjavascript/comments/8u5pew/function_that_can_validate_if_a_string_is_a_valid/

ยท ์•ฝ 1๋ถ„

๋‚ด์ผ ํ•  ๊ฒƒ#

์œˆ๋„์šฐ#

  • ๊ฒ€์ƒ‰ :win + s

  • ์œˆ๋„์šฐ VSCode ํ„ฐ๋ฏธ๋„ ์„ค์ •

  • ์œˆ๋„์šฐ React, NodeJS ํ™˜๊ฒฝ ์„ค์ •

Jira#

  • ๋งˆํฌ๋‹ค์šด ๋ฌธ๋ฒ• ์ง€์› ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด๊ธฐ

URL Shortener#

๊ธฐ์ˆ  ์Šคํƒ#

  • TypeScript (Vanilla)

  • Node, Express

  • Jest

๊ธฐ๋Šฅ#

  • URL Validation

  • ์ธ๊ธฐ URL ํ†ต๊ณ„

  • ์ตœ๊ทผ ๊ฒ€์ƒ‰ URL


ยท ์•ฝ 4๋ถ„

ํšŒ๊ณ #

  • ๋‚ฏ์„  ํ™˜๊ฒฝ์—์„œ ์ƒˆ๋กœ์šด ํŒ€ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ํ•œ๋™์•ˆ ์ง‘(์ปดํฌํŠธ ์กด)์—๋งŒ์žˆ์œผ๋ฉด์„œ, ๋™๊ธฐ ๋ถ€์—ฌ๋‚˜ ์˜์ง€๋ ฅ ๋“ฑ๋“ฑ์ด ์•ฝํ•ด์กŒ์—ˆ๋Š”๋ฐ, ์ƒˆ๋กœ์šด ํ™˜๊ฒฝ์—์„œ ๋„์ „ ๊ณผ์ œ๋ฅผ๋ถ€์—ฌ๋ฐ›๊ฒŒ ๋˜๊ณ , ํ•จ๊ป˜ ํ˜‘์—…ํ•ด์•ผ ํ•ด์„œ ๋™๊ธฐ ๋ถ€์—ฌ๊ฐ€ ๋˜์—ˆ๋‹ค.

  • ์šฐ์•„ํ•œํ…Œํฌ์บ ํ”„๊ฐ€ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž์™€ ํ˜‘์—…ํ•  ์ˆ˜ ์žˆ๋Š” ์บ ํ”„์˜€๋‹ค๋ฉด, ์ด๋ฒˆ ์บ ํ”„๋Š” ๋‹ค๋ฅธ ๋ถ„์•ผ ๊ฐœ๋ฐœ์ž๋“ค๊ณผ ํ˜‘์—…ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐํšŒ์˜€๋‹ค. ํŠนํžˆ ์ด๋ฒˆ ํŒ€ ๋นŒ๋”ฉ์„ ํ†ตํ•ด์„œ ์ž๋ฐ” ๋ฐฑ์—”๋“œ ํŒ€๊ณผ ํ˜‘์—…ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

  • ์บ ํ”„ ์ „์ฒด์— ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฑฐ์˜ ์—†๋Š”๊ฒŒ ์กฐ๊ธˆ ์ถฉ๊ฒฉ์ด์—ˆ๊ณ , ์บ ํ”„์—์„œ ํ˜ผ์ž ํ”„๋ก ํŠธ์—”๋“œ๋ฅผ ํ•˜๋Š” ๊ฒƒ์ด ๋ถˆ์•ˆํ•˜๊ณ  ๋‘๋ ค์šด ๋งˆ์Œ์ด ๋“ ๋‹ค.

  • ์ด๋ฒˆ์— ์ง„ํ–‰ํ•  ํ”„๋กœ์ ํŠธ ์ฃผ์ œ์— ๋Œ€ํ•ด ๊ฐ์ด ์ž˜ ์˜ค์ง€ ์•Š๋Š”๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„์„ํ•ด์„œ ๋ณด์—ฌ์ฃผ๋Š” ์‚ฌ์ดํŠธ ๋ ˆํผ๋Ÿฐ์Šค๋“ค์„ ์ฐพ์•„๋ด์•ผ๊ฒ ๋‹ค.

์ด๋ฒˆ ์บ ํ”„์˜ ๋ชฉํ‘œ#

  • ๋งค์ผ์˜ ๊พธ์ค€ํ•œ ๋ฃจํ‹ด

    • ์ง€๋‚œ ์บ ํ”„์—์„œ๋Š” ํ‰์ผ์— ๋„ˆ๋ฌด ๋ฌด๋ฆฌํ•ด์„œ ๊ฐœ๋ฐœํ•˜๋Š๋ผ ์ฃผ๋ง์— ํ”ผ๋กœ๊ฐ€ ๋ˆ„์ ๋˜์–ด ์“ฐ๋Ÿฌ์ ธ๋ฒ„๋ฆฌ๋Š” ์ผ์ด ๋งŽ์•˜๋‹ค.

    • ํŽ˜์ด์Šค๋ฅผ ์ž˜ ์กฐ์ ˆํ•˜์ž.

    • ๋งค์ผ ๊ฐœ์ธ ํšŒ๊ณ ๋ฅผ ์Šต๊ด€ํ™”ํ•˜์ž.

  • ์ด์Šˆ ๊ด€๋ฆฌ, ํƒœ์Šคํฌ ๊ด€๋ฆฌ

    • ์˜ค๋Š˜ ์„ธ์…˜์—์„œ "์ •์‹ ์—†์ด ๋ฐ”์œ ์บ ํ”„์ด๊ธฐ ๋•Œ๋ฌธ์—, ํ•œ ๋ฌธ์ œ์— ๋„ˆ๋ฌด ๊นŠ์ด ์‚ฌ๋กœ์žกํžˆ๋Š”๊ฒƒ์ด ๋ณ‘๋ชฉ์„ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ฃผ์˜ํ•˜๋ผ"๋Š” ๋‚ด์šฉ์„ ๋“ค์—ˆ๋‹ค.

    • ํ˜‘์—…์ด ํ•„์š”ํ•œ ์ผ์„ ๋จผ์ € ํ•ด๊ฒฐํ•˜์ž.

    • ๋‚ด๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ์„ ๋จผ์ € ํ•ด๊ฒฐํ•˜์ž.

    • ์–ด๋ ค์šด ๋ฌธ์ œ๋Š” ์‹œ๊ฐ„์„ ํ™•๋ณดํ•˜๊ณ  ๊ฐœ์ธ ์‹œ๊ฐ„์— ๊นŠ์ด ํŒŒ๊ณ ๋“ ๋‹ค.

  • ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ๋œ ๊ธฐ์ˆ , ๋Š๋‚€ ์ ์— ๋Œ€ํ•œ ๋ฌธ์„œํ™”

  • ๊ธฐ์ˆ ์— ๋Œ€ํ•œ ์ดํ•ด

    • ๋ฉ”์ธ ๊ธฐ์ˆ  ์Šคํƒ์ธ React, TypeScript์— ๋Œ€ํ•œ ์ดํ•ด๊ฐ€ ๋ถ€์กฑํ–ˆ๋‹ค

    • ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ ์ œ๋Œ€๋กœ ๊ณต๋ถ€ํ•˜๊ณ  ์ ์šฉํ•ด๋ณด์ž

  • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

    • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ 1๋„ ์ž‘์„ฑํ•˜์ง€ ์•Š์•˜๋‹ค

    • ์ด๋ฒˆ ๋ธ”๋ž™์ปคํ”ผ ์Šคํ„ฐ๋””์—์„œ ๋ฐฐ์šด ๋‚ด์šฉ์„ ์ ์šฉํ•ด๋ณด์ž

  • ์ž์‹ ๊ฐ ๊ฐ€์ง€๊ธฐ

    • ์ž์‹ ๊ฐ์€ ํ’์„ ๊ณผ ๊ฐ™๋‹ค

    • ๋ถˆ์–ด๋„ฃ๊ธฐ๋Š” ํž˜๋“ค์ง€๋งŒ ๋น ์ง€๋Š”๊ฑด ๊ธˆ๋ฐฉ ๋น ์ง„๋‹ค


ยท ์•ฝ 3๋ถ„

ํ…Œ์ŠคํŒ… ์ „๋žต#

HTML ๊ตฌ์กฐ ํ…Œ์ŠคํŠธ#

์ „๋žต#

  • HTML์„ ๋ฌธ์ž์—ด๋กœ ์ง์ ‘ ๋น„๊ต

  • diff๊ฐ€ ์šฉ์ดํ•˜๋„๋ก HTML ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•จ

  • ex) https://github.com/rayrutjes/diffable-html

๋‹จ์ #

  • ์‹ค์ œ UI ๊ฒฐ๊ณผ๋ฌผ ํ™”๋ฉด๊ณผ HTML์ด ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค.

  • HTML์ด ๋‹ฌ๋ผ๋„ ๊ฒฐ๊ณผ๋ฌผ์ด ๋™์ผํ• ์ˆ˜๋„ ์žˆ๊ณ , ๊ทธ ๋ฐ˜๋Œ€๋„ ๊ฐ€๋Šฅ

  • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋งŒ ๋ณด๊ณ  ์˜๋„๋ฅผ ํŒŒ์•…ํ•˜๊ธฐ ์–ด๋ ต๋‹ค

์Šค๋ƒ…์ƒท ํ…Œ์ŠคํŠธ#

์ „๋žต#

  • ํ˜„์žฌ์˜ HTML ๊ตฌ์กฐ๋ฅผ ๊ทธ๋Œ€๋กœ ํŒŒ์ผ๋กœ ์ €์žฅ, ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ํ…Œ์ŠคํŠธ ์‹คํŒจ

  • ์‹ค์ œ ๊ฒฐ๊ณผ๋Š” ํŒŒ์ผ ๋‚ด๋ถ€๋ฅผ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค

  • HTML์„ ์ง์ ‘ ๋น„๊ตํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๊ฐ„ํŽธํ•˜๋‹ค

  • ํšŒ๊ท€ ํ…Œ์ŠคํŠธ์˜ ์—ญํ• 

๋‹จ์ #

  • ํ…Œ์ŠคํŠธ์˜ ์˜๋„๊ฐ€ ์—†๋‹ค

  • ์Šค๋ƒ…์ƒท ๋ฐ์ดํ„ฐ์˜ Diff๋ฅผ ๋ด๋„ ์˜๋„๋ฅผ ํŒŒ์•…ํ•˜๊ธฐ ์–ด๋ ต๋‹ค

  • ์Šต๊ด€์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ ๋˜๋ฉด์„œ ํ…Œ์ŠคํŠธ์˜ ์‹ ๋ขฐ์„ฑ์ด ๊ฐ์†Œ

์‹œ๊ฐ์  ํ…Œ์ŠคํŠธ#

์‹œ๊ฐ์  ํ…Œ์ŠคํŠธ์˜ ์–ด๋ ค์›€#

  • ์ž๋™ํ™”๊ฐ€ ์–ด๋ ต๋‹ค

  • ์Šคํฌ๋ฆฐ์ƒท์„ ์ฐ์–ด๋‚ด๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ํ…Œ์ŠคํŠธ์˜ ๋ชฉ์ ์— ๋ถ€ํ•ฉ

์Šคํ† ๋ฆฌ๋ถ#

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ๋ถ„๋ฆฌ๋œ ํ™˜๊ฒฝ์—์„œ UI๋งŒ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค€๋‹ค

  • ์ปดํฌ๋„ŒํŠธ ๋ฐฉ์‹์˜ ๊ฐœ๋ฐœ์— ์–ด์šธ๋ฆฐ๋‹ค

์‹œ๊ฐ์  ํšŒ๊ท€ ํ…Œ์ŠคํŠธ#

  • AI ๊ธฐ์ˆ  ํ™œ์šฉ

  • ์Šคํ† ๋ฆฌ๋ถ / Cypress / ์…€๋ ˆ๋‹ˆ์›€๊ณผ ์—ฐ๋™ํ•ด์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

  • Percy, applitools, Chromatic

์‹œ๊ฐ์  ์š”์†Œ์™€ ๊ธฐ๋Šฅ์  ์š”์†Œ ๋ถ„๋ฆฌ#

dom-testing-library#

Introduction | Testing Library

  • CSS ์…€๋ ‰ํ„ฐ๋ฅผ ์ง€์–‘ํ•˜๊ณ  ์‚ฌ์šฉ์ž๊ฐ€ ๋ณผ ์ˆ˜ ์žˆ๋Š” ํ…์ŠคํŠธ ์œ„์ฃผ์˜ ์…€๋ ‰ํ„ฐ๋ฅผ ์‚ฌ์šฉ

    • getByText , getByLabelText , getByAltText , getByTitle , getByValue
  • ํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ์—๋Š” data-test-id ์†์„ฑ์„ ์‚ฌ์šฉ

    • getByTestId
  • ์ด๋ฒคํŠธ ์‹œ๋ฎฌ๋ ˆ์ด์…˜

    • fireEvent
  • DOM์ด ๋ณ€๊ฒฝ๋˜๊ฑฐ๋‚˜ ํŠน์ • ๋‹จ์–ธ(Assertion)์ด ์„ฑ๊ณตํ•  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆด ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜ - ๋น„๋™๊ธฐ ๋กœ์ง ํ…Œ์ŠคํŠธ

    • wait , waitForElement , waitForDomChange

jest-dom#

testing-library/jest-dom

  • DOM๊ณผ ๊ด€๋ จ๋œ ๋‹ค์–‘ํ•œ ํ˜•์‹์˜ ๋งค์ณ๋ฅผ ์ œ๊ณต

    • toBeDisable

    • toBeVisible

    • toHaveTextContent

    • toHaveStyle

    • toHaveClass

    • ...


Ajax Mocking#