[Go] Créez un outil qui renvoie la valeur de course du Pokémon reçu de l'entrée standard

Bonjour, c'est Yamauchi! Une grosse canette a eu lieu dans notre succursale de Fukuoka le 14 novembre 2020. C'est un nom qui semble être quelque chose comme passer la nuit, mais même si je le fais depuis au moins un mois depuis environ un an et demi, je n'ai encore qu'une excursion d'une journée. .. .. Eh bien, mettons-le de côté, et je vais vous présenter l'outil que j'ai créé cette fois! Au fait, je suis un super débutant dans le langage Go, et c'est la première fois que je crée quelque chose comme un outil, donc je pense qu'il y a divers problèmes avec le code.

Une introduction approximative à cet outil

Pour cet outil, j'ai créé l'API et le côté qui la touche séparément. Ceci est le référentiel. API:https://github.com/y-keisuke/pokemon Côté frappant: https://github.com/y-keisuke/pokemon_command Veuillez le regarder avec le sentiment que vous allez l'examiner w

Je voulais vraiment les rassembler dans un référentiel, mais je ne savais pas si c'était possible, alors j'ai divisé les référentiels, donc seules les commandes que j'ai utilisées plus tard ont des commandes attachées aux référentiels. Cela n'a pas d'importance.

C'est pourquoi c'est une introduction approximative, donc le mouvement est comme ça ↓ (Désolé pour le mouvement lent, j'ai frappé un total de 4 fois) pokemon.gif

C'est assez dur, mais ça ressemble à ça.

Introduction côté API

Tout d'abord, côté API, j'ai emprunté json au dépôt ici ↓. https://github.com/fanzeyi/pokemon.json/blob/master/pokedex.json

db.go Je voulais vraiment préparer une base de données, mais c'était gênant, j'ai donc utilisé json tel quel ← C'est «db.go».


package db

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
)

type PokemonCollection struct {
	Pokemons []PokemonData
}

type PokemonData struct {
	Id   int         `json:"id"`
	Name PokemonName `json:"name"`
	Type []string    `json:"type"`
	Base PokemonBase `json:"base"`
}

type PokemonName struct {
	English  string `json:"english"`
	Japanese string `json:"japanese"`
	Chinese  string `json:"chinese"`
	French   string `json:"french"`
}

type PokemonBase struct {
	HP        int `json:"hp"`
	Attack    int `json:"attack"`
	Defense   int `json:"defense"`
	SpAttack  int `json:"spattack"`
	SpDefense int `json:"spdefense"`
	Speed     int `json:"speed"`
}

func GetPokemonCollection() PokemonCollection {
	raw, err := ioutil.ReadFile("./pokedex.json")
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}
	var pokemonCollection PokemonCollection
	json.Unmarshal(raw, &pokemonCollection)

	return pokemonCollection
}

Certaines des structures définies ci-dessus sont exactement les mêmes que celles de json. La structure a légèrement changé par rapport au json emprunté. Le GetPokemonCollection () défini ici place les données json dans la structure. En particulier

json.Unmarshal(raw, &pokemonCollection)

Cette partie est emballée dans la structure. Cette structure est utilisée comme DB.

main.go

Vient ensuite «main.go».

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	pokemon2 "pokemon/pokemon"
)

func pokemonToJson(w http.ResponseWriter, r *http.Request) {
	name := r.FormValue("name")
	pokemon, err := pokemon2.GetPokemonBy(name)

    //Je ne savais pas comment renvoyer json des informations d'erreur ici
	if err != nil {
		log.Writer()
		http.Error(w, fmt.Sprintf("{\"err\":\"%s\"}", err), 200)
		return
	}
	pokemonJson, _ := json.Marshal(pokemon)
	fmt.Fprint(w, fmt.Sprintf("%+v", string(pokemonJson)))
}

func handleRequests() {
	http.HandleFunc("/", pokemonToJson)
	log.Fatal(http.ListenAndServe(":18888", nil))
}

func main() {
	handleRequests()
}

Ce que nous faisons ici, c'est "écouter l'accès sur le port 18888, regarder les paramètres de cet accès, obtenir les données Pokemon et renvoyer la valeur de course avec json".

Tout d'abord, la partie en attente au port 18888

//Écoutez le port 18888
http.ListenAndServe(":18888", nil)

Regardez ensuite les paramètres d'accès

//Récupère le paramètre de la clé appelée nom
name := r.FormValue("name")

De plus, obtenez des données Pokemon

//Obtenez Pokemon avec GetPokemonBy dans pokemon2 (détails ci-dessous)
pokemon, err := pokemon2.GetPokemonBy(name)

Enfin, json renvoie la valeur de race

//Convertir la structure en json puis revenir
pokemonJson, _ := json.Marshal(pokemon)
fmt.Fprint(w, fmt.Sprintf("%+v", string(pokemonJson)))

Aller? Que pouvez-vous en manger? Je suis susceptible d'entendre une voix dire "J'imprime sans revenir!", J'ajouterai donc que Fprint est une fonction qui vous permet de spécifier la destination d'écriture, et cette fois j'écris à w (http.ResponseWriter). , On a l'impression qu'il sera retourné en tant que résultat.

pokemon.go

C'est celui qui dit pokemon2.

package pokemon

import (
	"errors"
	"pokemon/db"
)

type Pokemon struct {
	Name      string `json:"name"`
	HP        int    `json:"hp"`
	Attack    int    `json:"attack"`
	Defense   int    `json:"defense"`
	SpAttack  int    `json:"sp_attack"`
	SpDefense int    `json:"sp_defense"`
	Speed     int    `json:"speed"`
}

func GetPokemonBy(name string) (*Pokemon, error) {
	pokemonCollection := getPokemonCollection()
	for _, pokemon := range pokemonCollection.Pokemons {
		if pokemon.Name.Japanese == name {
			return getPokemonStruct(pokemon), nil
		}
	}
	return nil, errors.New("")
}

func getPokemonCollection() db.PokemonCollection {
	return db.GetPokemonCollection()
}

func getPokemonStruct(pokemon db.PokemonData) *Pokemon {
	return &Pokemon{
		Name: pokemon.Name.Japanese,
		HP: pokemon.Base.HP,
		Attack: pokemon.Base.Attack,
		Defense: pokemon.Base.Defense,
		SpAttack: pokemon.Base.SpAttack,
		SpDefense: pokemon.Base.SpDefense,
		Speed: pokemon.Base.Speed}
}
//
pokemonCollection := getPokemonCollection()

C'est un joli nom NG. Goland a fait du bon travail ... Je ne trouve pas Pokemon Pour le moment, je vais juste expliquer la fonction appelée GetPokemonBy qui a été appelée depuis main.go. J'obtiens la base de données via la fonction privée, mais je ne me souviens pas pourquoi.

for _, pokemon := range pokemonCollection.Pokemons {
	if pokemon.Name.Japanese == name {
		return getPokemonStruct(pokemon), nil
	}
}

Si le nom DB Pokemon acquis correspond au nom Pokemon reçu dans le paramètre, ce Pokemon est emballé dans une nouvelle structure et renvoyé.

En gros, le côté API ressemble à ceci.

Côté frappant

Vient ensuite le côté qui touche l'API.

main.go

Pour le moment, le code source.

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"pokemon_command/input"
	"pokemon_command/pokemon"
)

func main() {
	url := input.CreateUrl()

	resp, _ := http.Get(url)
	defer resp.Body.Close()

	byteArray, _ := ioutil.ReadAll(resp.Body)

	var errCheck map[string]string
	json.Unmarshal(byteArray, &errCheck)
	if val, ok := errCheck["err"]; ok {
		fmt.Println(val)
		return
	}

	pokemonStruct := pokemon.JsonToPokemon(byteArray)

	pokemon.PrintPokemon(pokemonStruct)
}

Ceci est une explication du contenu de la fonction principale.

//Les détails de l'entrée seront décrits plus tard
url := input.CreateUrl()

Ici, nous recevons une entrée standard et générons une URL pour accéder à l'API en fonction de celle-ci.

resp, _ := http.Get(url)
defer resp.Body.Close()

Accédez ensuite à l'URL générée et recevez le résultat.

byteArray, _ := ioutil.ReadAll(resp.Body)

Obtient le corps de la réponse reçue.

var errCheck map[string]string
json.Unmarshal(byteArray, &errCheck)
if val, ok := errCheck["err"]; ok {
	fmt.Println(val)
	return
}

Je fais de la gestion des erreurs ici, mais je ne connais pas la solution optimale. .. ..

//pokemon sera décrit plus tard
pokemonStruct := pokemon.JsonToPokemon(byteArray)
pokemon.PrintPokemon(pokemonStruct)

Le dernier json reçu est stocké dans la structure puis sorti.

main.go ressemble à ceci.

input.go

package input

import (
	"bufio"
	"fmt"
	"os"
)

func CreateUrl() string {
	fmt.Print("Please enter the name of the Pokemon.\n>> ")
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Scan()
	return "http://localhost:18888/?name=" + scanner.Text()
}

Ce n'est pas un gros problème ici, il accepte une entrée standard et génère une URL basée sur cette entrée.

fmt.Print("Please enter the name of the Pokemon.\n>> ")
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()

Ces trois lignes affichent le texte qui vous invite à saisir, et l'entrée standard est obtenue par la fonction du package bufio.

return "http://localhost:8081/?name=" + scanner.Text()

L'URL est générée en combinant les chaînes de caractères obtenues. Je veux écrire quelque chose d'un peu mieux.

pokemon.go

package pokemon

import (
	"encoding/json"
	"fmt"
	"log"
)

type Pokemon struct {
	Name string `json:"name"`
	HP int `json:"hp"`
	Attack int `json:"attack"`
	Defense int `json:"defense"`
	SpAttack int `json:"sp_attack"`
	SpDefense int `json:"sp_defense"`
	Speed int `json:"speed"`
}

func JsonToPokemon(pokemonJson []byte) *Pokemon {
	pokemon := new(Pokemon)
	err := json.Unmarshal(pokemonJson, pokemon)
	if err != nil {
		log.Fatal(err)
	}
	return pokemon
}

func PrintPokemon(pokemon *Pokemon) {
	fmt.Println("Nom: ", pokemon.Name)
	fmt.Println("HP     : ", pokemon.HP)
	fmt.Println("Kogeki: ", pokemon.Attack)
	fmt.Println("Bougyo: ", pokemon.Defense)
	fmt.Println("Tokukou: ", pokemon.SpAttack)
	fmt.Println("Tokubo: ", pokemon.SpDefense)
	fmt.Println("Rapidité: ", pokemon.Speed)
}

Encore une fois, ce n'est pas un gros problème, juste une fonction qui emballe le json reçu dans une structure et une fonction qui sort en fonction de cette structure. Je n'ai rien écrit de vraiment important, je vais donc omettre les détails.

Impressions

C'est un article assez bâclé, mais ← En essayant de faire quelque chose avec GO, je voulais faire quelque chose comme "accepter l'entrée avec l'entrée standard" cette fois, donc pour le moment, je suis content d'avoir pu l'implémenter comme ça. Idéalement, vous devriez créer quelque chose comme la commande pokemon, et l'affichage changera en fonction de l'option. Je veux faire quelque chose comme ça, mais je ferai de mon mieux à un autre moment.

Je voulais accéder à l'API non seulement localement mais à tout moment et n'importe où, alors je me suis inscrit à Sakura VPS et j'ai mis l'API là-bas, alors j'écrirai à ce sujet dans l'article la prochaine fois.

C'est ça!

Recommended Posts

[Go] Créez un outil qui renvoie la valeur de course du Pokémon reçu de l'entrée standard
[Discode Bot] J'ai essayé de créer un Bot qui me dit la valeur de race de Pokemon
Créer un bloc de données à partir des données textuelles de course de bateaux acquises
[Django] Créez un formulaire qui remplit automatiquement l'adresse à partir du code postal
Créez un outil de traduction avec Translate Toolkit
Demandez à python d'analyser le json entré à partir de l'entrée standard
Langage de programmation qui protège les gens de NHK
#Une fonction qui renvoie le code de caractère d'une chaîne de caractères
Créez un chatbot prenant en charge la saisie gratuite avec Word2Vec
Créez un bot qui ne renvoie que le résultat de l'analyse morphologique avec MeCab avec Discord
Un exemple de mécanisme qui renvoie une prédiction par HTTP à partir du résultat de l'apprentissage automatique
J'ai créé un outil pour générer automatiquement un simple diagramme ER à partir de l'instruction CREATE TABLE