😽

【完全初心者による】Go言語でAPIを利用してランダムに抽出した英語の名言をDeepLに流して翻訳する機能を作ってみた

2023/03/12に公開

はじめに

筆者は完全初心者のGo言語の学習者です。普段はC#を使って開発をしています。
情報学に関して深い知見を持っているわけでゃないので、間違っているところがあればご指摘いただけると幸いです。
今回はmain.goにべた書きしているので見苦しいかもしれませんがご了承くださいませ。

今回作成したもの

今回は、API Ninjaを利用してランダムに名言を取得し、DeepLを利用して翻訳する機能を作成しました。

サンプルレポジトリ

(https://github.com/eiei114/go-api-translate-quote)

利用したAPI

構成

  • main.go
  • .env

main.go

ランダムにカテゴリを生成する関数

func getRandomCategory() string {
	categories := []string{
		"age",
		"alone",
//省略-----------------------------------
		"movies",
		"success",
	}
	rand.Seed(time.Now().UnixNano())
	return categories[rand.Intn(len(categories))]
}

func getRandomCategory() string 戻り値をstring方に設定。
categories := []string でカテゴリを配列で定義しています。
rand.Seed(time.Now().UnixNano()) で乱数のシードを設定しています。
rand.Intn(len(categories)) で配列の長さを取得して、その長さの乱数を生成しています。

ランダムに名言を取得する関数

func getQuote(category string) (*Quote, error) {
	apiURL := fmt.Sprintf("https://api.api-ninjas.com/v1/quotes?category=%s", category)
	req, err := http.NewRequest("GET", apiURL, nil)
	if err != nil {
		return nil, err
	}

	req.Header.Set("X-Api-Key", loadEnv("API_NINJA_KEY"))
	client := http.DefaultClient
	res, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	if res.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("API request returned status %d %s", res.StatusCode, res.Status)
	}

	bodyBytes, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

	var quotes []Quote
	err = json.Unmarshal(bodyBytes, &quotes)
	if err != nil {
		return nil, err
	}

	if len(quotes) == 0 {
		return nil, fmt.Errorf("no quotes found for category %s", category)
	}

	return &quotes[0], nil
}

func getQuote(category string) (*Quote, error) 引数をcategory string型、戻り値を*Quote, error型に設定。
apiURL := fmt.Sprintf("https://api.api-ninjas.com/v1/quotes?category=%s", category) でAPIのURLを設定。
req, err := http.NewRequest("GET", apiURL, nil) でリクエストを作成。
req.Header.Set("X-Api-Key", loadEnv("API_NINJA_KEY")) でヘッダーにAPIキーを設定。
client := http.DefaultClient でクライアントを作成。
res, err := client.Do(req) でリクエストを送信。
if res.StatusCode != http.StatusOK { でステータスコードが200以外の場合はエラーを返す。
bodyBytes, err := ioutil.ReadAll(res.Body) で受け取った名言を読み込む。
var quotes []Quote でQuote型の配列を定義。
err = json.Unmarshal(bodyBytes, &quotes) でJSONをパース(整列)。
if len(quotes) == 0 { で配列の長さが0の場合はエラーを返す。
return &quotes[0], nil で配列の0番目を返す。

DeepLに流して翻訳する関数

func translateText(text, sourceLang, targetLang string) (string, error) {
	// 翻訳APIのURLとパラメータ
	apiURL := "https://api-free.deepl.com/v2/translate"
	params := url.Values{}
	params.Set("auth_key", loadEnv("DEEPL_API_KEY"))
	params.Set("source_lang", sourceLang)
	params.Set("target_lang", targetLang)
	params.Set("text", text)

	// 翻訳APIにリクエストを送信
	res, err := http.Get(apiURL + "?" + params.Encode())
	if err != nil {
		return "", fmt.Errorf("failed to send translation request: %v", err)
	}
	defer res.Body.Close()

	// レスポンスのJSONをパースして翻訳結果を取得
	var result struct {
		Translations []struct {
			Text string `json:"text"`
		} `json:"translations"`
	}
	if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
		return "", fmt.Errorf("failed to parse translation response: %v", err)
	}
	if len(result.Translations) == 0 {
		return "", fmt.Errorf("no translations found")
	}
	return result.Translations[0].Text, nil
}
  • func translateText(text, sourceLang, targetLang string) (string, error) 引数をtext(引用文や著者), sourceLang(元の言語), targetLang(翻訳先の言語) string型、戻り値をstring, error型に設定。
  • apiURL := "https://api-free.deepl.com/v2/translate" でAPIのURLを設定。
  • params := url.Values{} で以降のパラメータが設定できるようにする。
  • params.Set("auth_key", loadEnv("DEEPL_API_KEY")) でパラメータにAPIキーを設定。
  • params.Set("source_lang", sourceLang) でパラメータに元の言語を設定。
  • params.Set("target_lang", targetLang) でパラメータに翻訳先の言語を設定。
  • params.Set("text", text) でパラメータに引用文や著者を設定。
  • res, err := http.Get(apiURL + "?" + params.Encode()) でリクエストを送信。
  • var result struct { で翻訳結果を格納する構造体を定義。
  • if err := json.NewDecoder(res.Body).Decode(&result); err != nil { でJSONをパース(整列)。
  • if len(result.Translations) == 0 { で翻訳結果の長さが0の場合はエラーを返す。
  • return result.Translations[0].Text, nil で翻訳結果を返す。

main関数

func main() {
	category := getRandomCategory()
	quote, err := getQuote(category)
	if err != nil {
		fmt.Println(err)
		return
	}

	// 引用文と著者名を翻訳
	translatedQuote, err := translateText(quote.Quote, "en", "ja")
	if err != nil {
		fmt.Printf("Failed to translate quote: %v", err)
		return
	}
	translatedAuthor, err := translateText(quote.Author, "en", "ja")
	if err != nil {
		fmt.Printf("Failed to translate author: %v", err)
		return
	}

	fmt.Printf("%q - %s\n", quote.Quote, quote.Author)
	// 翻訳結果を出力
	fmt.Printf("%q - %s\n", translatedQuote, translatedAuthor)
}
  • func main() エントリーポイントとなる関数。
    • category := getRandomCategory() でランダムなカテゴリーを取得。
    • quote, err := getQuote(category) で引用文と著者名を取得。
    • translatedQuote, err := translateText(quote.Quote, "en", "ja") で引用文を翻訳。英語から日本語へと設定
    • translatedAuthor, err := translateText(quote.Author, "en", "ja") で著者名を翻訳。英語から日本語へと設定
    • fmt.Printf("%q - %s\n", quote.Quote, quote.Author) で原文の引用文と著者名を出力。
      • fmt.Printf("%q - %s\n", translatedQuote, translatedAuthor) で翻訳したものを出力。

Go言語を使ってみた所感

  • C#より若干コードが短く書ける感じがした。
  • Go言語のコードはC#よりも読みにくい気がした。
  • Apiを利用したやり取りだけなので正直あまり違いは感じなかったのが本音。
  • 次回はもう少し規模の大きなプロジェクトを組んでよりGo言語の良さを感じてみたい。
MidraLab(ミドラボ)

Discussion