1 분 소요

설명

  • https://github.com/swaggo/swag
  • Go 주석을 swagger 문서 2.0으로 변환
  • 명령어
    • swag 설치
      • go install github.com/swaggo/swag/cmd/swag@latest
    • init
      • 구문 분석 및 doc 생성
      • 의존성이 없는 경우
        • ~/go/bin/swag init
      • 의존성이 있는 경우
        • 다른 패키지의 구조체를 요청이나 응답으로 사용하는 경우 등
        • ~/go/bin/swag init --parseDependency
    • fmt
      • swag 주석에 swag 포맷 적용
    • ~/go/bin/swag init
  • Swagger UI
    • ip:port/swagger/index.html을 통해 접근 가능
    • api 확인 및 테스트 가능


예제

  • 코드
    package main

    import (
    	"context"
    	"net/http"
    	"os"
    	"os/signal"
    	"sync"
    	"syscall"
    	"time"

    	"test/docs"

    	"github.com/gorilla/mux"
    	httpSwagger "github.com/swaggo/http-swagger"
    )

    var server *http.Server

    type TestPostRequest struct {
    	Field1 string `json:"field_1",omitempty example:"value"`
    }

    type ResponseSuccess struct {
    	Field1 string `json:"field_1"`
    }

    type ResponseFailure struct {
    	Cause string `json:"cause"`
    }

    func loggingMiddleware(next http.Handler) http.Handler {
    	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    		println(r.RequestURI, r.Method, "start")
    		defer println(r.RequestURI, r.Method, "end")

    		next.ServeHTTP(w, r)
    	})
    }

    // @Summary get test
    // @Description get test
    // @Accept json
    // @Produce json
    // @Param param_1 query string true "param_1 selection" Enums(1, 2, 3)
    // @Param param_2 query string true "param_2 selection" Enums(A, B, C, D) default(A)
    // @Param param_3 query string true "param_3" default(AAA)
    // @Param id path string true "id" default(id_1)
    // @Success 200 {object} ResponseSuccess
    // @Failure default {object} ResponseFailure
    // @Router /v1/test/{id} [get]
    // @tags test
    func testGet(w http.ResponseWriter, r *http.Request) {
    	w.WriteHeader(http.StatusOK)
    	w.Write([]byte(`{"field_1" : "get ok"}`))
    }

    // @Summary post test
    // @Description post test
    // @Accept json
    // @Produce json
    // @Param id path string true "id" default(aaa)
    // @Param request body TestPostRequest true "country selection"
    // @Success 200 {object} ResponseSuccess
    // @Failure default {object} ResponseFailure
    // @Router /v1/test [post]
    // @tags test
    func testPost(w http.ResponseWriter, r *http.Request) {
    	w.WriteHeader(http.StatusOK)
    	w.Write([]byte(`{"cause" : "post fail"}`))
    }

    func run(wg *sync.WaitGroup, done chan int) {
    	defer wg.Done()

    	go finalize(done)

    	docs.SwaggerInfo.Version = "1.0"
    	docs.SwaggerInfo.Host = "127.0.0.1:10000"
    	docs.SwaggerInfo.BasePath = ""
    	docs.SwaggerInfo.Title = "test"
    	docs.SwaggerInfo.Description = "test"

    	router := mux.NewRouter()

    	router.Use(loggingMiddleware)

    	router.PathPrefix("/swagger/").Handler(httpSwagger.WrapHandler)
    	router.HandleFunc("/v1/test/{id:[a-z,A-Z][a-z,A-Z,0-9,--,_,.]+}", testGet).Methods("GET")
    	router.HandleFunc("/v1/test", testPost).Methods("POST")

    	server = &http.Server{
    		Addr:    ":10000",
    		Handler: router}

    	server.ListenAndServe()
    }

    func finalize(done chan int) {
    	for len(done) == 1 {
    		time.Sleep(1 * time.Second)
    	}

    	if server != nil {
    		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    		cancel()
    		server.Shutdown(ctx)
    	}
    }

    func main() {
    	var wg sync.WaitGroup

    	done := make(chan int, 1)
    	done <- 1

    	signals := make(chan os.Signal, 1)
    	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)

    	wg.Add(1)
    	go run(&wg, done)

    	<-signals

    	<-done

    	wg.Wait()
    }
  • 실행 결과