Solucionado (ver solução)
Solucionado
(ver solução)
1
resposta

Tratamento de erro ao consultar API CheapShark

Olá,

conforme os colegas estão relatando, aparentemente a API alterou o comportamento de consultas a id's inexistentes. Nesse ponto surge uma dúvida: Para esses casos, o correto não seria gerar uma nova versão da API?

Entendo que como é um serviço de terceiro, temos pouco controle sobre isso, mas a dúvida seria mais para quando estivermos desenvolvendo nossa própria API.

Apesar do desafio servir como um aprendizado a todos que estão no curso, acredito que o ideal, e certamente será feito, uma atualização no curso para contornar o problema.

Nesse sentido, tentei também resolver do meu jeito e gostaria de sugestões de possíveis melhorias. Segue meu código:


package net.lucianodacunha.alugames.main
import net.lucianodacunha.alugames.model.Jogo
import net.lucianodacunha.alugames.service.ConsumerAPI


fun main(){
    print("Entre com um código de jogo para buscar: ")
    val codigo = readln()

    var resultadoDaBusca = runCatching {
        // pelo que pesquisei, é necessário um cast explícito aqui.
        ConsumerAPI.findGame(codigo) as Jogo
    }

    // Aparentemente, caso falhar, o retorno será um objeto Exception
    // nesse caso, imprimo a mensagem de erro.
    resultadoDaBusca.onFailure {
        print(it.message)
    }

    resultadoDaBusca.onSuccess {
        println("Deseja atribuir uma nova descrição ao jogo [s/N]?")
        val resposta = readln()
        it.descricao = when (resposta) {
            "s" -> {
                print("Entre com a descrição desejada: ")
                readln()
            }
            else -> {
                it.titulo
            }
        }
        println(it)
    }
}

package net.lucianodacunha.alugames.service

import com.google.gson.Gson
import net.lucianodacunha.alugames.model.InfoJogo
import net.lucianodacunha.alugames.model.Jogo
import java.lang.Exception
import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse

/**
 * Deixei static por enquanto mais por questões práticas de testes.
 * Acredito que essa não seja a melhor abordagem por outras questões
 */
object ConsumerAPI {
    fun findGame(id: String) : Any {
        val endpoint = "https://www.cheapshark.com/api/1.0/games?id=$id"
        val client: HttpClient = HttpClient.newHttpClient()
        val request = HttpRequest.newBuilder()
            .uri(URI.create(endpoint))
            .build()

        val response = client
            .send(request, BodyHandlers.ofString())
        val json = response.body()

        val gson = Gson()

        // não consegui implementar outro tipo de tratamento aqui.
        return try {
            val resultadoDaDeserializacao = gson.fromJson(json, InfoJogo::class.java)
            Jogo(
                resultadoDaDeserializacao.info.title,
                resultadoDaDeserializacao.info.thumb
            )
        } catch (e: Exception){
            throw Exception("Falha ao buscar pelo id. Tente outro...")
        }
    }
}

Até +.

1 resposta
solução!

Olá, Luciano! Tudo bem com você?

Você levantou uma questão muito relevante sobre a gestão de APIs. Realmente, em uma situação ideal, se uma API muda seu comportamento, o mais adequado seria gerar uma nova versão para não impactar os sistemas que já a utilizam. No entanto, como você mesmo mencionou, quando se trata de um serviço de terceiros, temos pouco controle sobre isso.

Quanto ao seu código, achei a sua solução bastante criativa e eficiente. No entanto, tenho algumas sugestões que podem aprimorar ainda mais o seu código.

1 - Tratamento de erros: Você está correto ao usar o runCatching para tratar possíveis erros durante a execução do código. No entanto, ao invés de retornar uma Exception genérica, você poderia criar uma exceção personalizada para tratar especificamente erros de busca na API. Isso tornaria o código mais legível e fácil de manter. Aqui está um exemplo de como você poderia fazer isso:

class GameNotFoundException(message: String): Exception(message)

object ConsumerAPI {
    fun findGame(id: String) : Any {
        // ... código omitido para brevidade
        return try {
            // ... código omitido para brevidade
        } catch (e: Exception){
            throw GameNotFoundException("Falha ao buscar pelo id. Tente outro...")
        }
    }
}

2 - Casting explícito: Você mencionou que precisou fazer um cast explícito na chamada ConsumerAPI.findGame(codigo) as Jogo. Isso ocorre porque a função findGame está retornando Any, que é a superclasse de todas as classes em Kotlin. Para evitar esse cast, você poderia alterar a função findGame para retornar um Jogo diretamente. Desta forma, o compilador já sabe o tipo de objeto que a função retorna e você não precisa fazer o cast.

object ConsumerAPI {
    fun findGame(id: String) : Jogo {
        // ... código omitido para brevidade
        return try {
            // ... código omitido para brevidade
            Jogo(
                resultadoDaDeserializacao.info.title,
                resultadoDaDeserializacao.info.thumb
            )
        } catch (e: Exception){
            throw GameNotFoundException("Falha ao buscar pelo id. Tente outro...")
        }
    }
}

Espero que essas dicas possam lhe ajudar.

Grande abraço e bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.