Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>

Contents

장 소개

앞서 다루었던 HTTP 챕터의 연장이다. 이번 장에서는 go 언어를 이용해서 완전히 작동하는 웹 서버를 만들 것이다. 원문에서는 중국어 flash card(단어장)를 서비스하는 예제를 제공하고 있는데, 예제로 하기에는 좀 직관적이지 않다는 생각이 들었다. 그래서 단어장 서비스 대신에, 유저 정보를 관리하는 "유저 정보 데이터 베이스" 서비스를 만들기로 했다.

단순히 코드만 설명하는 것에 머무르지 않고, 실제 배포하는 것을 가정해서 완전한 소프트웨어 구조를 만들려고 한다. 이를 위해서 1. 개발을 위한 완전한 디렉토리 구조를 설계 한다. 2. 설계하고 개발하는 코드들은 github에 올려서 다른 팀에서 협업할 수 있도록 한다.

서비스 소개

나는 유저 정보를 관리하는 웹 서비스를 만들 것이다. 이 서비스는 "유저 등록", "유저 검색", "유저 삭제", "유저 목록 확인", "유저 정보 수정" 등의 기능을 가지고 있다. 유저정보는 SQLite 데이터베이스에 저장한다. 저장된 데이터는 (유저가 요청하면) JSON 형태로 반환한다.

REST API 서버

만드려는 웹 애플리케이션 서버는 유저 정보에 대한 CRUD를 RESTful API형태로 제공한다. REST는 REST에 대하여문서를 참고 한다. 나는 아래와 같은 API를 준비했다.
  • GET /users : 유저 목록을 가져온다.
  • GET /users/123 : 특정 유저의 세부 정보를 가져온다.
  • POST /users : 유저 정보를 입력 한다.
  • PUT /users/123 : 특정 유저 정보를 업데이트 한다.
  • DELETE /users/123 : 특정 유저를 삭제한다.

웹 애플리케이션 구조

웹 애플리케이션을 만들 때, 가장 먼저하는 일은 애플리케이션 구조를 만드는거다. 나는 아래와 같은 구조를 만들었다. 웹 애플리케이션의 이름은 simpleweb으로 정했다.
 --+--- main.go
   |
   +--- /handler
   |
   +--- /server
   |
   +--- /user
  • 루트디렉토리 : main.go 파일과 빌드를 위한 Makefile이 위치한다.
  • /handler : 핸들러 파일들이 위치한다.
  • /server : 웹 서버를 초기화 하기 위한 코드가 위치한다. 데이터베이스를 오픈하고 핸들러를 실행하는 등의 일을 한다.
  • /user : 유저 정보 구조체가 있다.

Bitbucket

애플리케이션 구조를 만든다음 simpleweb 프로젝트를 위해서 Bitbucket에 코드 저장소를 만들고, 프로젝트를 밀어넣었다. 저장소의 주소는 https://bitbucket.org/dream_yun/simpleweb 이다.

패키지 구성

현재 GOPATH 다.
# echo $GOPATH
/home/yundream/golang
simpleweb을 개발하기 위해서 아래와 같은 디렉토리를 만들었다.
# mkdir -p ~/golang/src/bitbucket.org/dream_yun/simpleweb
기본 파일을 만든 다음 최초 파일을 push하는 걸로 프로젝트를 초기화 했다.
# cd ~/golang/src/bitbucket.org/dream_yun/simpleweb
# git init
# git remote add origin git@bitbucket.org:dream_yun/simpleweb.git
# echo "dream yun" >> contributors.txt
# git add contributors.txtgit 
# commit -m 'Initial commit with contributors'
# git push -u origin master

유저 데이터베이스 생성

simpleweb에서 사용할 유저 데이터베이스를 설계한다. SQLite 데이터베이스에 저장하며, 단지 하나의 테이블만 가지고 있다. 테이블의 이름은 users로 한다. 데이터베이스의 위치는 data 디렉토리다.
# cat user.sql
create table users (name char(32), address char(80), city char(32), blog char(160), email char(80));
# cat user.sql | sqlite3 user.db

라우팅 & 핸들러 패턴

RESTful API 서버는 라우팅 & 핸들러 패턴을 주로 사용한다. 유저의 요청을 처리하는 핸들러를 만들고, URI에 이 핸들러를 맵핑(라우팅)하는 패턴이다. 아래와 같이 개발 한다.
router := mux.NewRouter()
router.HandleFunc("/users", userList).Methods("GET")
router.HandleFunc("/users/[id]", getUser).Methods("GET")
router.HandleFunc("/users/[id]", delUser).Methods("DELETE")
router.HandleFunc("/users", createUser).Methods("POST")

func getUser(w http.ResonseWriter, r *http.Request) {
    vars := mux.Vars(r)
    id := vars["id"]
    // id를 key로 sqlite 데이터베이스를 조회 한다.
}
func delUser(w http.ResonseWriter, r *http.Request) {
    // id를 key로 유저 데이터를 삭제한다.
}

개발

이제 개발에 들어가 보자.

main.go

main.go에는 main 함수가 위치한다. main 함수는 server 패키지를 읽어서 실행하는 일을 한다. 이외에는 하는 일이 없다. 핸들러를 등록하고 웹 서버를 실행하는 일은 server 패키지가 도 맡아서 한다.
package main

import (
    "github.com/simpleweb/server"   
) 
    
func main() {
    myServer := server.New()   
    myServer.Run()
}
실제 코드는 더 복잡하겠지만 지금은 이정도로 충분하다. server.New 함수는 server 구조체를 초기화 한다음에 리턴한다. New 함수에서, 설정파일을 읽고, 데이터베이스를 초기화 하는 등의 일을 한다.

server.go

server 패키지를 살펴보자.