Skip to content

Implement generic function and interface for API endpoint calls #208

@digitalghost-dev

Description

@digitalghost-dev

Currently, in the connections/connections.go file, the same logic for each API endpoint is repeated several times. For example:

Repeated Code Example
func PokemonApiCall(endpoint string, pokemonName string, baseURL string) (structs.PokemonJSONStruct, string, error) {
	fullURL := baseURL + endpoint + "/" + pokemonName

	var pokemonStruct structs.PokemonJSONStruct
	err := ApiCallSetup(fullURL, &pokemonStruct, false)

	if err != nil {
		errMessage := styling.ErrorBorder.Render(
			styling.ErrorColor.Render("✖ Error!"),
			"\nPokémon not found.\n\u2022 Perhaps a typo?\n\u2022 Missing a hyphen instead of a space?",
		)
		return structs.PokemonJSONStruct{}, "", fmt.Errorf("%s", errMessage)
	}

	return pokemonStruct, pokemonStruct.Name, nil
}

func PokemonSpeciesApiCall(endpoint string, pokemonSpeciesName string, baseURL string) (structs.PokemonSpeciesJSONStruct, error) {
	fullURL := baseURL + endpoint + "/" + pokemonSpeciesName

	var pokemonSpeciesStruct structs.PokemonSpeciesJSONStruct
	err := ApiCallSetup(fullURL, &pokemonSpeciesStruct, false)

	if err != nil {
		errMessage := styling.ErrorBorder.Render(
			styling.ErrorColor.Render("✖ Error!"),
			"\nPokémon not found.\n\u2022 Perhaps a typo?\n\u2022 Missing a hyphen instead of a space?",
		)
		return structs.PokemonSpeciesJSONStruct{}, fmt.Errorf("%s", errMessage)
	}

	return pokemonSpeciesStruct, nil
}

Using a generic function with an interface{} constraint will reduce code duplication by handling the fetch/error logic once instead of repeating it for each resource type.

type EndpointResource interface {
	GetResourceName() string
}

func FetchEndpoint[T EndpointResource](endpoint, resourceName, baseURL, resourceType string) (T, string, error) {
	var zero T
	fullURL := baseURL + endpoint + "/" + resourceName

	var result T
	err := ApiCallSetup(fullURL, &result, false)

	if err != nil {
		errMessage := styling.ErrorBorder.Render(
			styling.ErrorColor.Render("✖ Error!"),
			fmt.Sprintf("\n%s not found.\n• Perhaps a typo?\n• Missing a hyphen instead of a space?", resourceType),
		)
		return zero, "", fmt.Errorf("%s", errMessage)
	}

	return result, result.GetResourceName(), nil
}

Then, the existing API endpoint calling functions can be refactored to:

func PokemonApiCall(endpoint string, pokemonName string, baseURL string) (structs.PokemonJSONStruct, string, error) {
	return FetchEndpoint[structs.PokemonJSONStruct](endpoint, pokemonName, baseURL, "Pokemon")
}

func PokemonSpeciesApiCall(endpoint string, pokemonSpeciesName string, baseURL string) (structs.PokemonSpeciesJSONStruct, string, error) {
	return FetchEndpoint[structs.PokemonSpeciesJSONStruct](endpoint, pokemonSpeciesName, baseURL, "PokemonSpecies")
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    refactorRefactoring existing code.

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions