일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 코딩강의
- golang
- 데이터베이스
- 스키마모델
- 파이썬
- 개발공식문서 어려움
- 자바
- HTTP
- 실무PT
- 자료구조
- 개발 영어실력
- tableplus
- 개발자공통지식
- 코멘토
- 개발공부
- Go언어실무
- 개발실무
- 유데미
- 리액트
- 데이터스키마
- Go언어
- 개발자되기
- jsx
- 개발 공식문서 읽기
- 개발 공식문서
- 알고리즘
- 웹서버
- postgredb
- 코멘토실무PT
- 컴공과개념정리
- Today
- Total
웹개발일지
CRUD 게시판 웹서버 구현 본문
이 글은 코멘토에서 3주차 Go언어 서버 개발과정 실무 PT를 실시간으로 수강한 후기와 3주차 수업내용인 오픈소스 MERN-CRUD 프로젝트를 활용하여 웹서버 구현과 관련하여 학습한 과정을 담았습니다.
설치사항
1. 도커
2. maria DB
3. Gorm
4. Node .js
가상 실행환경인 도커, 서버와 maria db를 연결할 gorm, 클라이언트를 구동시켜줄 Node.js 를 각각 설치한다.
들어가기 앞서, 도커란?
https://docs.docker.com/get-started/
Overview
docs.docker.com
도커란 무엇일까? 위 고래그림을 많이 보았다. 도커는 가상 컴퓨터이다. 진짜 컴퓨터 처럼 os, ip, port를 가지고있다. 그래서인지 도커 사용의 가장큰 장점이 쉽고 빠른 실행환경 구축과 하드웨어 자원의 절감이다.
도커는 우리가 사용하는 맥이나 윈도우같은 호스트 서버 위에서 별도의 서버로 작동한다. 이 때 별도의 서버로 작동하는 것이 컨테이너이고 이 컨테이너들을 관리하는 것이 쿠버네티스이다. 앱과 앱의 구동환경을 격리시켜 가볍고 빠르게 실행되도록 한다. 서버에서 DB에 접근할 때 도커 컨테이너에서 접근할 때와 host에서 접근할 때 port를 굳이 다르게 사용하는 것이 궁금했는데 이렇게 격리된 차원의 개념이라는 것에서 조금 이해가 간다.
Backend 구조
.go-server
|_.
├── README.md
├── go.mod
├── go.sum
├── main.go
└── pkg
├── api
│ ├── api.go
│ └── handler.go
├── db
│ ├── db.go
│ └── handler.go
├── model
│ └── board.go
└── router
└── router.go
pkg 파일로 api, db, model, router를 설정하고 각 핸들러를 구현했다.
도커 설치확인하기
docker ps
도커 설치가 잘 되었는지 확인하기 위해 위 명령어를 터미널에 입력해보자. 도커 컨테이너의 리스트를 보여준다.
설치 과정과 명령어
npm start
client디렉토리에서 npm 서버를 실행해주고 go-server 디렉토리에서 docker run을 해준다.
docker run -d -p 3307:3306 —name some-mariadb —env MARIADB_USER=user —env MARIADB_PASSWORD=password —env MARIADB_ROOT_PASSWORD=password —env MARIADB_DATABASE=dev mariadb:latest
코드
실행된 클라이언트에서 개발자모드를 열면 Network란에 실행된 목록을 볼 수 있다. 여기 Payload가 request Body인데 여기 들어온 company Name, description 등 데이터 내용들을 서버의 db에 저장해야한다. 그리고 서버에서도 아래 항목들과 일치하게 키값을 지정해줘야한다. model 패키지의 board.go 에 지정한다.
type Board struct { // db의 컬럼 항목들을 필드로 가지고 있다. snakeCase를 사용했다.
ID uint `gorm:"primarykey;autoIncrement" json:"_id"`
CompanyName string `json:"companyName"`
Phone string `json:"phone"`
Email string `json:"email"`
Location string `json:"location"`
Link string `json:"link"`
Description string `json:"description"`
}
위처럼 클라이언트로 부터 Get요청을 받을때 Payload 항목들과 바인등을 하기 위해 json 지정까지 해준것이다. 응답을 줄 때도 마찬가지다. ID항목에는 _id로 별도 구분시켰는데 이는 프론트에서 view요청시 _id 별로 구분되어 있기 때문에(url에 '/숫자'가 붙는다) 이도 마찬가지로 바인딩 시켜 데이터를 가져오기위해 키값으로 넣어준 것이다. 프론트 파일에서 없애주던지 아니면 서버에서 프론트 형식에 맞게 써줘야한다.
CRUDS의 게시판 목록을 불러오면 Request Method 가 GET으로 동작하는 것을 알 수 있다. 반면 Create를 통해 새롭게 목록을 작성해서 submit하면 Request Method가 POST로 작동한다. GET요청은 Payload (Request Body)사항이 없다.
Edit은 CRUD 중 Update이다.
main.go
package main
import (
"fmt"
"github.com/jackbalageru/MERN-CRUD/go-server/pkg/api"
"github.com/jackbalageru/MERN-CRUD/go-server/pkg/db"
"github.com/jackbalageru/MERN-CRUD/go-server/pkg/router"
)
func main() {
dbHandler, err := db.NewAndConnectGorm("user:password@tcp(127.0.0.1:3307)/dev?charset=utf8mb4&parseTime=True&loc=Local")
if err != nil {
fmt.Printf("%+v\n", err)
}
apis := api.NewAPI(dbHandler) // DB공간에 POST요청 db를 저장시킴
r := router.Router(apis)
r.Run(":8081")
}
main파일의 import 사항은 이러하다.
.main
_ pkg/api
_ pkg/db
_ pkg/router
main함수의 시작점에서 db.go에 구현된 함수를 불러와 dbHandler를 생성한다. 이 핸들러를 통해 db에 접근할 수 있게된다. 이 역할을 gorm 이 한다.
db.NewConnectGorm()
이 함수는 인자로 db에서 Gorm에 요구하는 형식의 데이터를 받는다. 문서를 참고한 코드이다.
https://gorm.io/docs/connecting_to_the_database.html#MySQL
Connecting to a Database
GORM officially supports the databases MySQL, PostgreSQL, SQLite, SQL Server MySQLimport ( "gorm.io/driver/mysql" "gorm.io/gorm")func main() { // refer https://github.com/g
gorm.io
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func main() {
dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
}
보면 local path 앞부분의 user:pass 부분을 도커 db실행시 설정한 user, password로 지정하고 포트번호 또한 내가 지정한 3307로 넣어서 실습했다. 아래는 도커로 DB 실행을 하는 명령어다
docker run -d -p 3306:3306 --name some-mariadb --env MARIADB_USER=user --env MARIADB_PASSWORD=password --env MARIADB_ROOT_PASSWORD=password --env MARIADB_DATABASE=dev mariadb:latest
위에서 얘기한 docker ps를 실행했을 때 아래와 같이 나오는데 잘 살펴보면 mariadb에 연결되어있는 것을 볼 수 있다.
도커에서 db로 진입하기 위해 sever 디렉토리에서 다음과 같은 명령어를 입력한다.
mysql -h localhost -h localhost —port 3306 -u user -p
localhost에 연결된 db 포트는 3307이나 도커에 연결된 포트는 3306이다. Local과 매핑된다.
서버를 실행하고 게시판 데이터를 POST한 뒤 데이터베이스 테이블을 확인해본다. 이를 확인하기 위해선 use dev > show tables > ;를 차례대로 입력하면 아래처럼 boards라는 우리의 CRUD 게시판의 테이블 정보가 터미널에 확인된다.
여기서 테이블의 모든 항목을 불러오려면 다음과 같은 명령어를 입력한다.
select * from boards
항목들을 가져온 모습이다.
내가 웹브라우저에서 입력한 데이터들의 모습이다.
여기까지 main.go의 코드와 데이터베이스에 연결하고 불러오는 작업을 실행해보았다. 코드로 db에 접근하려면 db파일에 작성된 메서드들을 살펴봐야한다. 다음으로 db.go 파일을 살펴보자.
db.go
func NewAndConnectGorm(dsn string) (*DBHandler, error) {
gormDB, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
gormDB.AutoMigrate(&model.Board{})
dbHandler := &DBHandler{
gDB: gormDB,
}
return dbHandler, err
}
AutoMigrate()
gorm의 메서드이다. 자동으로 모델을 마이그레이션하며 테이블을 생성해준다. 마이그레이션이란 테이블이 원래 있었다면 생성하지 않고 없었다면 생성한다. 원리 있는데 세팅이 조금 다르다면 덮어씌워 추가해준다. 이 부분에 대한 동작은 조금 더 파봐도 괜찮다.
모델을 여러개 인자로 줘서 (...interface) 테이블을 여러개 생성할 수도 있다.
api.go
package api
import "github.com/jackbalageru/MERN-CRUD/go-server/pkg/db"
type APIs struct {
db *db.DBHandler // 필드 인자에 DBHandler 포인터변수 넣어줌
}
func NewAPI(h *db.DBHandler) *APIs {
// a := APIS{db: h}
// a.db = h 와 같은 의미이다.
// return a
return &APIs{db: h} // DBHandler 포인터 인스턴스를 위 API구조체의 db 에 넣어준다.
}
처음에 이 파일이 뭐하는 파일이지 했다. API구조체 포인터 인스턴스의 필드에 db에서 받아온 DBHandler의 포인터 인스턴스를 넣었다.
Router.go
func Router(apis *api.APIs) *gin.Engine {
r := gin.Default()
crudRouter := r.Group("/api/cruds")
crudRouter.GET("/", apis.GetBoardList)
crudRouter.POST("/", apis.CreateBoard)
crudRouter.GET("/:id", apis.GetBoardByID)
crudRouter.PATCH("/:id", apis.UpdateBoard)
crudRouter.DELETE("/:id", apis.DeleteBoardByID)
return r
}
r.Group으로 relative path 시작 경로를 동일하게맞춰준다. (게시판의 CRUDS의 Id 값)
핸들러 살펴보기
db.go에 gDB라는 것을 해당구조체의 멤버변수(필드)로 설정한 이유
핸들러 파일에 보면 CreateBoard라는 함수가 있는데 이게 웹에서 Submit했을 때 실행되는 함수다. 얘는 board를 인자로 받아서 gDB로 Create()를 해서 db에 데이터 베이스를 생성해준다. Create는 간단하게 board를 insert해주는메서드다. insert라는 용어가 잘 안와닿았었는데 습득이 된 것 같다.
gDB를 가서 보면 gorm.DB의 포인터형이다. gorm 라이브러리의 DB패키지에 있는 자원들을 모두 사용할 수 있는 인스턴스를 하나 만들어준 셈이다.
그러니까 gDB.으로 사용한 Create()는 gorm 라이브러리의 메서드다.
이렇게 3주차 수업으로 웹 게시판 CRUD 를 구현하는 서버 개발을 실습해보았다. 혼자 구현해보기엔 어려움이 있지만 HTTP동작 이해를 높이고 해당 메서드들의 동작 또한 이해할 수 있게되었다. 실습한 프로젝트가 해당 개념을 이해하기 좋았던 것 같다. 1주당 배우는 것들이 정말 많고 이해가 어려운 부분들이 많았지만 개인 질문을 통해 코드를 많이 뜯어보고 재미를 느낄 수 있었다.
성과를 만드는 현직자의 실무 노하우 ㅣ 코멘토
내 실무에 적용하며 성과내는, 진짜 실무 퍼스널 트레이닝!
comento.kr
성과를 만드는 현직자의 실무 노하우 ㅣ 코멘토
내 실무에 적용하며 성과내는, 진짜 실무 퍼스널 트레이닝!
comento.kr
DB 연결작업 참고문서
- https://gorm.io/docs/connecting_to_the_database.html#MySQL
- https://gorm.io/ko_KR/docs/models.html
- https://gorm.io/docs/create.html
- https://gorm.io/docs/query.html
- https://gorm.io/docs/update.html
- https://gorm.io/docs/delete.html
'Lang > Go' 카테고리의 다른 글
Go언어의 동시성 프로그래밍, 고루틴 (0) | 2023.08.29 |
---|---|
Docker 활용 웹 어플리케이션 배포 (0) | 2023.01.06 |
Go Scan() 함수의 기본과 활용 (0) | 2023.01.05 |
Go 자료구조 : map [맵] (0) | 2022.12.24 |
Golang 기본 문법 복습 및 Mutex 패키지 활용 (3) | 2022.12.20 |