Help us understand the problem. What is going on with this article?

Goで外部コマンドを呼び出すのをHTTPリクエスト越しに実行してみる(Ginを使って)

More than 1 year has passed since last update.

概要

このエントリは、Goを使い、外部コマンドを呼び出すこと、それをHTTPリクエスト越しに実行してみることをやってみたので、メモとして残すものです。コンテナにもできます。
表題のことをやってみようかなと思った方への参考の一つとして紹介します。

前提

想定読者

  • Go言語で、"A tour of Go"を少しやったことがある人

利用するもの

以下を利用します

  • HTTPサーバとして、gin
  • 動作環境は*nix系(コマンド実行)

ソース

リリースv0.1.0がGitHubにあります。
https://github.com/hrkt/cmd-exec-server/releases/tag/0.1.0

ベースとなるもの

以前書いたQiitaのエントリ「Go-lang+GinでAPIサーバを作る一歩目~EHW2018「アプリ②」」で作ってあったものをforkしました。

今できること

  1. app-settings.jsonを編集して

see: "app-settings.json" paragraph in this README.

  1. サーバを実行して
$ make run
  1. サーバ側でコマンドを実行するため、ボディに標準入力を渡し、HTTP POST リクエストを飛ばすと、標準出力がJSONファイルの中の文字列として返ってきます。 (バッファサイズは2048byteに絞ってあります)
$ curl -X POST localhost:8080/api/exec -d "some input"
{"result":"SOME INPUT"}

(で、README.mdにあるように"make build-container"すると、コンテナになります)

書いたもの

Router

"/api/exec"でコマンドを実行できるように指定しています。

POSTリクエストを受け取り、リクエストのボディ部をstringとして格納しています。
(ここのバッファは今は固定長。2048byte。)

func setupRouter() *gin.Engine {
    router := gin.Default()

    // Global middleware
    router.Use(gin.Logger())

    // Routing
    router.StaticFile("/", "./index.html")

    router.POST("/api/exec", func(ctx *gin.Context) {
        buf := make([]byte, RequestBodyBufferSize)
        n, _ := ctx.Request.Body.Read(buf)
        body := string(buf[0:n])

        res := executeIt(body)

        ctx.JSON(200, gin.H{
            "result": res,
        })
    })

    return router
}

外部コマンドの実行

app-config.jsonで指定したコマンドを実行します。

Go-langのos/execを使います。

(今の実装では出力を区切っていないため、出力が多いコマンドだとサーバが止まるでしょう)

func executeIt(requestBody string) string {
    cmd := exec.Command(appConfig.Command, appConfig.Arguments[:]...)
    cmd.Stdin = strings.NewReader(requestBody)
    var out bytes.Buffer
    cmd.Stdout = &out
    err := cmd.Run()
    if err != nil {
        log.Fatal(err)
    }
    return out.String()
}

おわりに

このエントリでは、Goで外部コマンドを呼び出すのをHTTPリクエスト越しに実行してみることを紹介しました。何かのご参考になれば幸いです。

補足:エントリを書くきっかけ

Pythonで、"$ python -m CGIHTTPServer"などでお手軽サーバを作るような感じをGoでやったらどうなるかなと思って書いてみました。

hrkt
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away