こんにちは。KOUKIです。
前日、以下の記事を書きましたが、その続きです。
Swaggerを使おうとして、下記のエラーに悩まされました。
1 2 |
$ swagger serve ./swagger.json webbrowser: tried to open "http://localhost:40323/docs", no screen found |
やれやれって感じです。
このエラーの解決策を記述します。
<目次>
環境
- MAC
- Docker
- Swagger(docker image latest)
何をしたのか
公式サイトを参考にDockerでswaggerを利用しようとしました。
1 2 3 4 5 6 7 8 |
# エイリアスを貼り、swaggerコマンドを使えるようにする alias swagger="docker run --rm -it -p 9999:9999 --user $(id -u):$(id -g) -e XDG_CACHE_HOME=/tmp/.cache -e GOPATH=$HOME/go:/go -v $HOME:$HOME -w $(pwd) quay.io/goswagger/swagger" # swagger設定ファイルを作成 swagger generate spec -o ./swagger.json # swagger画面を開く swagger serve ./swagger.json |
このSwagger画面を開くコマンドを実行した際に、エラーが発生したというわけです。
1 |
<meta charset="utf-8">webbrowser: tried to open "http://localhost:40323/docs", no screen found |
解決法
本事象は、SwaggerをDockerで動かすときに起こるものだと思います。
DockerがWebブラウザを開こうとする -> それに失敗する、といった感じのイメージをメッセージから受けたったので、その動きをキャンセルするために「–no-open」をつけました。
そして、ポートがランダムに割り当てられてしまうため、「-p 9999」を指定します。
1 2 |
# "真"コマンド swagger serve ./swagger.json --no-open -p 9999 |
こうすると「http://localhost:9999/docs」のパスでドキュメント画面を開けるようになります。
そして忘れてはいけないのが、dockerコンテナとローカルPCを通信させるためにportを開けることです。
設定したエイリアスに「-p 9999:9999」フラグをつけましょう。
1 2 |
# エイリアスに-pオプションをつける alias swagger="docker run --rm -it -p 9999:9999 --user $(id -u):$(id -g) -e XDG_CACHE_HOME=/tmp/.cache -e GOPATH=$HOME/go:/go -v $HOME:$HOME -w $(pwd) quay.io/goswagger/swagger" |
これで、OKです。
ブラウザから「http://localhost:9999/docs」へアクセスしましょう。

完璧ですね。
まとめ
Swaggerは、最近個人的に気になっているツールです。今回お見せしたようにDocumentを自動生成してくれます。
ちなみに、ドキュメントにしたい文言をプログラムファイルに書き込んで作成します。
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
// Recipes API // // This is a sample recipes API. You can find out more about the API. // // Schemes: http // Host: localhost:8080 // BasePath: / // Version: 1.0.0 // Contact: Mohamed Labouardy <mohamed@labouardy.com> https://labouardy.com // // Consumes: // - application/json // // Produces: // - application/json // swagger:meta package main import ( "encoding/json" "io/ioutil" "net/http" "strings" "time" "github.com/gin-gonic/gin" "github.com/rs/xid" ) type Recipe struct { ID string `json;"id"` Name string `json:"name"` Tags []string `json:"tags"` Ingredients []string `json:"ingredients"` Instructions []string `json:"instructions"` PublishedAt time.Time `json:"publishedAt"` } var recipes []Recipe func init() { recipes = make([]Recipe, 0) file, _ := ioutil.ReadFile("recipes.json") _ = json.Unmarshal([]byte(file), &recipes) } func NewRecipeHandler(c *gin.Context) { var recipe Recipe if err := c.ShouldBindJSON(&recipe); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": err.Error()}) return } recipe.ID = xid.New().String() recipe.PublishedAt = time.Now() recipes = append(recipes, recipe) c.JSON(http.StatusOK, recipe) } func ListRecipesHandler(c *gin.Context) { c.JSON(http.StatusOK, recipes) } func UpdateRecipeHandler(c *gin.Context) { id := c.Param("id") var recipe Recipe if err := c.ShouldBindJSON(&recipe); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": err.Error(), }) return } index := -1 for i := 0; i < len(recipes); i++ { if recipes[i].ID == id { index = i } } if index == -1 { c.JSON(http.StatusNotFound, gin.H{ "error": "Recipe not found", }) return } recipes[index] = recipe c.JSON(http.StatusOK, recipe) } func DeleteRecipeHandler(c *gin.Context) { id := c.Param("id") index := -1 for i := 0; i < len(recipes); i++ { if recipes[i].ID == id { index = i } } if index == -1 { c.JSON(http.StatusNotFound, gin.H{ "error": "Recipe not found", }) return recipes = append(recipes, recipes[index+1:]...) } c.JSON(http.StatusOK, gin.H{ "message": "Recipe has been deleted", }) } func SearchRecipesHandler(c *gin.Context) { tag := c.Query("tag") listOfRecipes := make([]Recipe, 0) for i := 0; i < len(recipes); i++ { found := false for _, t := range recipes[i].Tags { if strings.EqualFold(t, tag) { found = true } } if found { listOfRecipes = append(listOfRecipes, recipes[i]) } } c.JSON(http.StatusOK, listOfRecipes) } func main() { router := gin.Default() router.POST("/recipes", NewRecipeHandler) router.GET("/recipes", ListRecipesHandler) router.PUT("/recipes/:id", UpdateRecipeHandler) router.DELETE("/recipes/:id", DeleteRecipeHandler) router.GET("/recipes/search", SearchRecipesHandler) router.Run() } |
自動化最高!ですよね。
それではまた!
コメントを残す
コメントを投稿するにはログインしてください。