package api import ( "errors" "github.com/gin-gonic/gin" "github.com/rs/zerolog/log" "net" "net/http" "thuanle.me/ip-info/internal/data" ) func HandleJson(c *gin.Context) { ip := c.ClientIP() HandleIpInfo(c, ip) } func HandleOtherIp(c *gin.Context) { ip := c.Param("ip") if net.ParseIP(ip) == nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid ip", "ip": ip}) return } HandleIpInfo(c, ip) } func HandleIpInfo(c *gin.Context, ip string) { if !data.Ins().IsLoaded() { log.Error().Msg("DB is not loaded") c.JSON(http.StatusServiceUnavailable, gin.H{ "error": "service unavailable, db still loading", "ip": ip, }) return } ipData, _, err := data.Ins().Query(ip) if err != nil { // Distinguish "not found" (valid IP, absent from DB) from other errors. if isNotFound(err) { c.JSON(http.StatusNotFound, gin.H{"error": "not found", "ip": ip}) return } log.Err(err).Msg("Failed to query IP") c.JSON(http.StatusInternalServerError, gin.H{"error": "internal error", "ip": ip}) return } ipData["ip"] = ip c.JSON(http.StatusOK, ipData) } // isNotFound reports whether the query error means the IP was not present in // the DB (as opposed to an invalid IP or an internal lookup failure). func isNotFound(err error) bool { return errors.Is(err, data.ErrNotFound) }