From 06e73c0acaa25bf8cfe686cd614e1e97165f1ce7 Mon Sep 17 00:00:00 2001 From: Silvano Cerza Date: Fri, 1 Aug 2025 17:56:28 +0200 Subject: [PATCH 1/5] Bump dependencies versions --- pom.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 45f6328..a4f2dcc 100644 --- a/pom.xml +++ b/pom.xml @@ -68,35 +68,35 @@ io.ipinfo ipinfo-api - 2.2.1 + 3.1.0 compile com.google.code.gson gson - 2.8.7 + 2.13.1 compile org.junit.jupiter junit-jupiter-api - 5.2.0 + 6.0.0-M2 test org.springframework spring-webmvc - 6.0.10 + 7.0.0-M7 org.springframework spring-core - 6.0.10 + 7.0.0-M7 org.apache.tomcat.embed tomcat-embed-core - 10.1.11 + 11.0.9 From 1b6f03acc786b7832f68cdcac22db6d5ad7be9e8 Mon Sep 17 00:00:00 2001 From: Silvano Cerza Date: Fri, 1 Aug 2025 17:57:12 +0200 Subject: [PATCH 2/5] Add tests --- pom.xml | 24 +++ .../io/ipinfo/spring/IPinfoSpringTest.java | 169 ++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 src/test/java/io/ipinfo/spring/IPinfoSpringTest.java diff --git a/pom.xml b/pom.xml index a4f2dcc..ab69513 100644 --- a/pom.xml +++ b/pom.xml @@ -98,6 +98,30 @@ tomcat-embed-core 11.0.9 + + org.junit.jupiter + junit-jupiter-engine + 6.0.0-M2 + test + + + org.mockito + mockito-core + 5.18.0 + test + + + org.mockito + mockito-junit-jupiter + 5.18.0 + test + + + org.springframework + spring-test + 7.0.0-M7 + test + diff --git a/src/test/java/io/ipinfo/spring/IPinfoSpringTest.java b/src/test/java/io/ipinfo/spring/IPinfoSpringTest.java new file mode 100644 index 0000000..a9bfc49 --- /dev/null +++ b/src/test/java/io/ipinfo/spring/IPinfoSpringTest.java @@ -0,0 +1,169 @@ +package io.ipinfo.spring; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +import io.ipinfo.api.IPinfo; +import io.ipinfo.api.errors.RateLimitedException; +import io.ipinfo.api.model.IPResponse; +import io.ipinfo.spring.strategies.attribute.AttributeStrategy; +import io.ipinfo.spring.strategies.interceptor.InterceptorStrategy; +import io.ipinfo.spring.strategies.ip.IPStrategy; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +@ExtendWith(MockitoExtension.class) +class IPinfoSpringTest { + + @Mock + private IPinfo mockIPinfoClient; + + @Mock + private AttributeStrategy mockAttributeStrategy; + + @Mock + private IPStrategy mockIpStrategy; + + @Mock + private InterceptorStrategy mockInterceptorStrategy; + + @InjectMocks + private IPinfoSpring ipinfoSpring; + + private MockHttpServletRequest request; + private MockHttpServletResponse response; + private Object handler; + + private IPResponse dummyIPResponse; + + @BeforeEach + void setUp() { + request = new MockHttpServletRequest(); + response = new MockHttpServletResponse(); + handler = new Object(); + + dummyIPResponse = new IPResponse( + "8.8.8.8", + "dns.google", + false, + false, + false, + "Mountain View", + "CA", + "United States", + "37.40599,-122.07851", + "AS15169 Google LLC", + "94043", + "America/Los_Angeles", + null, + null, + null, + null, + null, + null + ); + } + + @Test + @DisplayName("should skip processing if interceptorStrategy returns false") + void preHandle_shouldSkipIfInterceptorStrategyFalse() throws Exception { + when(mockInterceptorStrategy.shouldRun(request)).thenReturn(false); + + boolean result = ipinfoSpring.preHandle(request, response, handler); + + assertTrue(result, "preHandle should return true to continue chain"); + // Verify that no other strategies were called if shouldRun returned false + verify(mockInterceptorStrategy).shouldRun(request); + verifyNoInteractions( + mockAttributeStrategy, + mockIpStrategy, + mockIPinfoClient + ); + } + + @Test + @DisplayName( + "should skip processing if attributeStrategy already has attribute" + ) + void preHandle_shouldSkipIfHasAttribute() throws Exception { + when(mockInterceptorStrategy.shouldRun(request)).thenReturn(true); + when(mockAttributeStrategy.hasAttribute(request)).thenReturn(true); + + boolean result = ipinfoSpring.preHandle(request, response, handler); + + assertTrue(result, "preHandle should return true to continue chain"); + verify(mockInterceptorStrategy).shouldRun(request); + verify(mockAttributeStrategy).hasAttribute(request); + // Verify no IP lookup or storage occurred + verifyNoInteractions(mockIpStrategy, mockIPinfoClient); + } + + @Test + @DisplayName("should skip processing if IPStrategy returns null IP") + void preHandle_shouldSkipIfIpIsNull() throws Exception { + when(mockInterceptorStrategy.shouldRun(request)).thenReturn(true); + when(mockAttributeStrategy.hasAttribute(request)).thenReturn(false); + when(mockIpStrategy.getIPAddress(request)).thenReturn(null); + + boolean result = ipinfoSpring.preHandle(request, response, handler); + + assertTrue(result, "preHandle should return true to continue chain"); + verify(mockInterceptorStrategy).shouldRun(request); + verify(mockAttributeStrategy).hasAttribute(request); + verify(mockIpStrategy).getIPAddress(request); + // Verify no IP lookup or storage occurred + verifyNoInteractions(mockIPinfoClient); + verify(mockAttributeStrategy, never()).storeAttribute(any(), any()); + } + + @Test + @DisplayName( + "should perform IP lookup and store attribute if all conditions met" + ) + void preHandle_shouldProcessAndStore() throws Exception { + String testIp = "8.8.8.8"; + when(mockInterceptorStrategy.shouldRun(request)).thenReturn(true); + when(mockAttributeStrategy.hasAttribute(request)).thenReturn(false); + when(mockIpStrategy.getIPAddress(request)).thenReturn(testIp); + when(mockIPinfoClient.lookupIP(testIp)).thenReturn(dummyIPResponse); + + boolean result = ipinfoSpring.preHandle(request, response, handler); + + assertTrue(result, "preHandle should return true to continue chain"); + verify(mockInterceptorStrategy).shouldRun(request); + verify(mockAttributeStrategy).hasAttribute(request); + verify(mockIpStrategy).getIPAddress(request); + verify(mockIPinfoClient).lookupIP(testIp); + verify(mockAttributeStrategy).storeAttribute(request, dummyIPResponse); + } + + @Test + @DisplayName("should rethrow RateLimitedException during lookup") + void preHandle_shouldRethrowRateLimitedException() throws Exception { + String testIp = "invalid.ip"; + when(mockInterceptorStrategy.shouldRun(request)).thenReturn(true); + when(mockAttributeStrategy.hasAttribute(request)).thenReturn(false); + when(mockIpStrategy.getIPAddress(request)).thenReturn(testIp); + // Simulate a RateLimitedException during lookup + when(mockIPinfoClient.lookupIP(testIp)).thenThrow( + new RateLimitedException() + ); + + assertThrows(RateLimitedException.class, () -> + ipinfoSpring.preHandle(request, response, handler) + ); + + verify(mockInterceptorStrategy).shouldRun(request); + verify(mockAttributeStrategy).hasAttribute(request); + verify(mockIpStrategy).getIPAddress(request); + verify(mockIPinfoClient).lookupIP(testIp); + verify(mockAttributeStrategy, never()).storeAttribute(any(), any()); + } +} From 73b6066ab56ceaae26d63e16d7d4f055660f8285 Mon Sep 17 00:00:00 2001 From: Silvano Cerza Date: Fri, 1 Aug 2025 18:16:01 +0200 Subject: [PATCH 3/5] Add support for Lite API --- .../io/ipinfo/spring/IPinfoLiteSpring.java | 111 ++++++++++++ .../attribute/AttributeStrategy.java | 21 ++- .../attribute/RequestAttributeStrategy.java | 24 ++- .../attribute/SessionAttributeStrategy.java | 30 +++- .../ipinfo/spring/IPinfoLiteSpringTest.java | 162 ++++++++++++++++++ 5 files changed, 342 insertions(+), 6 deletions(-) create mode 100644 src/main/java/io/ipinfo/spring/IPinfoLiteSpring.java create mode 100644 src/test/java/io/ipinfo/spring/IPinfoLiteSpringTest.java diff --git a/src/main/java/io/ipinfo/spring/IPinfoLiteSpring.java b/src/main/java/io/ipinfo/spring/IPinfoLiteSpring.java new file mode 100644 index 0000000..b66fe06 --- /dev/null +++ b/src/main/java/io/ipinfo/spring/IPinfoLiteSpring.java @@ -0,0 +1,111 @@ +package io.ipinfo.spring; + +import io.ipinfo.api.IPinfoLite; +import io.ipinfo.api.model.IPResponseLite; +import io.ipinfo.spring.strategies.attribute.AttributeStrategy; +import io.ipinfo.spring.strategies.attribute.SessionAttributeStrategy; +import io.ipinfo.spring.strategies.interceptor.BotInterceptorStrategy; +import io.ipinfo.spring.strategies.interceptor.InterceptorStrategy; +import io.ipinfo.spring.strategies.ip.IPStrategy; +import io.ipinfo.spring.strategies.ip.SimpleIPStrategy; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.servlet.HandlerInterceptor; + +public class IPinfoLiteSpring implements HandlerInterceptor { + + public static final String ATTRIBUTE_KEY = + "IPinfoOfficialSparkWrapper.IPResponseLite"; + private final IPinfoLite ii; + private final AttributeStrategy attributeStrategy; + private final IPStrategy ipStrategy; + private final InterceptorStrategy interceptorStrategy; + + IPinfoLiteSpring( + IPinfoLite ii, + AttributeStrategy attributeStrategy, + IPStrategy ipStrategy, + InterceptorStrategy interceptorStrategy + ) { + this.ii = ii; + this.attributeStrategy = attributeStrategy; + this.ipStrategy = ipStrategy; + this.interceptorStrategy = interceptorStrategy; + } + + public static void main(String... args) { + System.out.println( + "This library is not meant to be run as a standalone jar." + ); + System.exit(0); + } + + @Override + public boolean preHandle( + HttpServletRequest request, + HttpServletResponse response, + Object handler + ) throws Exception { + if (!interceptorStrategy.shouldRun(request)) { + return true; + } + + // Don't waste an API call if we already have it. + // This should only happen for RequestAttributeStrategy and potentially + // other implementations. + if (attributeStrategy.hasLiteAttribute(request)) { + return true; + } + + String ip = ipStrategy.getIPAddress(request); + if (ip == null) { + return true; + } + + IPResponseLite ipResponse = ii.lookupIP(ip); + attributeStrategy.storeLiteAttribute(request, ipResponse); + + return true; + } + + public static class Builder { + + private IPinfoLite ii = new IPinfoLite.Builder().build(); + private AttributeStrategy attributeStrategy = + new SessionAttributeStrategy(); + private IPStrategy ipStrategy = new SimpleIPStrategy(); + private InterceptorStrategy interceptorStrategy = + new BotInterceptorStrategy(); + + public Builder setIPinfo(IPinfoLite ii) { + this.ii = ii; + return this; + } + + public Builder attributeStrategy(AttributeStrategy attributeStrategy) { + this.attributeStrategy = attributeStrategy; + return this; + } + + public Builder ipStrategy(IPStrategy ipStrategy) { + this.ipStrategy = ipStrategy; + return this; + } + + public Builder interceptorStrategy( + InterceptorStrategy interceptorStrategy + ) { + this.interceptorStrategy = interceptorStrategy; + return this; + } + + public IPinfoLiteSpring build() { + return new IPinfoLiteSpring( + ii, + attributeStrategy, + ipStrategy, + interceptorStrategy + ); + } + } +} diff --git a/src/main/java/io/ipinfo/spring/strategies/attribute/AttributeStrategy.java b/src/main/java/io/ipinfo/spring/strategies/attribute/AttributeStrategy.java index 56abcfd..24fced4 100644 --- a/src/main/java/io/ipinfo/spring/strategies/attribute/AttributeStrategy.java +++ b/src/main/java/io/ipinfo/spring/strategies/attribute/AttributeStrategy.java @@ -1,7 +1,7 @@ package io.ipinfo.spring.strategies.attribute; import io.ipinfo.api.model.IPResponse; - +import io.ipinfo.api.model.IPResponseLite; import jakarta.servlet.http.HttpServletRequest; public interface AttributeStrategy { @@ -16,4 +16,23 @@ default boolean hasAttribute(HttpServletRequest request) { return false; } + + default void storeLiteAttribute( + HttpServletRequest request, + IPResponseLite response + ) { + throw new UnsupportedOperationException( + "This strategy does not support IPResponseLite." + ); + } + + default IPResponseLite getLiteAttribute(HttpServletRequest request) { + throw new UnsupportedOperationException( + "This strategy does not support IPResponseLite." + ); + } + + default boolean hasLiteAttribute(HttpServletRequest request) { + return getLiteAttribute(request) != null; + } } diff --git a/src/main/java/io/ipinfo/spring/strategies/attribute/RequestAttributeStrategy.java b/src/main/java/io/ipinfo/spring/strategies/attribute/RequestAttributeStrategy.java index afbf081..4143154 100644 --- a/src/main/java/io/ipinfo/spring/strategies/attribute/RequestAttributeStrategy.java +++ b/src/main/java/io/ipinfo/spring/strategies/attribute/RequestAttributeStrategy.java @@ -1,13 +1,18 @@ package io.ipinfo.spring.strategies.attribute; import io.ipinfo.api.model.IPResponse; +import io.ipinfo.api.model.IPResponseLite; +import io.ipinfo.spring.IPinfoLiteSpring; import io.ipinfo.spring.IPinfoSpring; - import jakarta.servlet.http.HttpServletRequest; public class RequestAttributeStrategy implements AttributeStrategy { + @Override - public void storeAttribute(HttpServletRequest request, IPResponse response) { + public void storeAttribute( + HttpServletRequest request, + IPResponse response + ) { request.setAttribute(IPinfoSpring.ATTRIBUTE_KEY, response); } @@ -15,4 +20,19 @@ public void storeAttribute(HttpServletRequest request, IPResponse response) { public IPResponse getAttribute(HttpServletRequest request) { return (IPResponse) request.getAttribute(IPinfoSpring.ATTRIBUTE_KEY); } + + @Override + public void storeLiteAttribute( + HttpServletRequest request, + IPResponseLite response + ) { + request.setAttribute(IPinfoLiteSpring.ATTRIBUTE_KEY, response); + } + + @Override + public IPResponseLite getLiteAttribute(HttpServletRequest request) { + return (IPResponseLite) request.getAttribute( + IPinfoLiteSpring.ATTRIBUTE_KEY + ); + } } diff --git a/src/main/java/io/ipinfo/spring/strategies/attribute/SessionAttributeStrategy.java b/src/main/java/io/ipinfo/spring/strategies/attribute/SessionAttributeStrategy.java index f1bb6fa..b83cac2 100644 --- a/src/main/java/io/ipinfo/spring/strategies/attribute/SessionAttributeStrategy.java +++ b/src/main/java/io/ipinfo/spring/strategies/attribute/SessionAttributeStrategy.java @@ -1,18 +1,42 @@ package io.ipinfo.spring.strategies.attribute; import io.ipinfo.api.model.IPResponse; +import io.ipinfo.api.model.IPResponseLite; +import io.ipinfo.spring.IPinfoLiteSpring; import io.ipinfo.spring.IPinfoSpring; - import jakarta.servlet.http.HttpServletRequest; public class SessionAttributeStrategy implements AttributeStrategy { + @Override - public void storeAttribute(HttpServletRequest request, IPResponse response) { + public void storeAttribute( + HttpServletRequest request, + IPResponse response + ) { request.getSession().setAttribute(IPinfoSpring.ATTRIBUTE_KEY, response); } @Override public IPResponse getAttribute(HttpServletRequest request) { - return (IPResponse) request.getSession().getAttribute(IPinfoSpring.ATTRIBUTE_KEY); + return (IPResponse) request + .getSession() + .getAttribute(IPinfoSpring.ATTRIBUTE_KEY); + } + + @Override + public void storeLiteAttribute( + HttpServletRequest request, + IPResponseLite response + ) { + request + .getSession() + .setAttribute(IPinfoLiteSpring.ATTRIBUTE_KEY, response); + } + + @Override + public IPResponseLite getLiteAttribute(HttpServletRequest request) { + return (IPResponseLite) request + .getSession() + .getAttribute(IPinfoLiteSpring.ATTRIBUTE_KEY); } } diff --git a/src/test/java/io/ipinfo/spring/IPinfoLiteSpringTest.java b/src/test/java/io/ipinfo/spring/IPinfoLiteSpringTest.java new file mode 100644 index 0000000..60a5956 --- /dev/null +++ b/src/test/java/io/ipinfo/spring/IPinfoLiteSpringTest.java @@ -0,0 +1,162 @@ +package io.ipinfo.spring; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +import io.ipinfo.api.IPinfoLite; +import io.ipinfo.api.errors.RateLimitedException; +import io.ipinfo.api.model.IPResponseLite; +import io.ipinfo.spring.strategies.attribute.AttributeStrategy; +import io.ipinfo.spring.strategies.interceptor.InterceptorStrategy; +import io.ipinfo.spring.strategies.ip.IPStrategy; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +@ExtendWith(MockitoExtension.class) +class IPinfoLiteSpringTest { + + @Mock + private IPinfoLite mockIPinfoClient; + + @Mock + private AttributeStrategy mockAttributeStrategy; + + @Mock + private IPStrategy mockIpStrategy; + + @Mock + private InterceptorStrategy mockInterceptorStrategy; + + @InjectMocks + private IPinfoLiteSpring ipinfoSpring; + + private MockHttpServletRequest request; + private MockHttpServletResponse response; + private Object handler; + + private IPResponseLite dummyIPResponse; + + @BeforeEach + void setUp() { + request = new MockHttpServletRequest(); + response = new MockHttpServletResponse(); + handler = new Object(); + + dummyIPResponse = new IPResponseLite( + "8.8.8.8", + "AS15169", + "Google LLC", + "google.com", + "US", + "United States", + "NA", + "North America" + ); + } + + @Test + @DisplayName("should skip processing if interceptorStrategy returns false") + void preHandle_shouldSkipIfInterceptorStrategyFalse() throws Exception { + when(mockInterceptorStrategy.shouldRun(request)).thenReturn(false); + + boolean result = ipinfoSpring.preHandle(request, response, handler); + + assertTrue(result, "preHandle should return true to continue chain"); + // Verify that no other strategies were called if shouldRun returned false + verify(mockInterceptorStrategy).shouldRun(request); + verifyNoInteractions( + mockAttributeStrategy, + mockIpStrategy, + mockIPinfoClient + ); + } + + @Test + @DisplayName( + "should skip processing if attributeStrategy already has attribute" + ) + void preHandle_shouldSkipIfHasLiteAttribute() throws Exception { + when(mockInterceptorStrategy.shouldRun(request)).thenReturn(true); + when(mockAttributeStrategy.hasLiteAttribute(request)).thenReturn(true); + + boolean result = ipinfoSpring.preHandle(request, response, handler); + + assertTrue(result, "preHandle should return true to continue chain"); + verify(mockInterceptorStrategy).shouldRun(request); + verify(mockAttributeStrategy).hasLiteAttribute(request); + // Verify no IP lookup or storage occurred + verifyNoInteractions(mockIpStrategy, mockIPinfoClient); + } + + @Test + @DisplayName("should skip processing if IPStrategy returns null IP") + void preHandle_shouldSkipIfIpIsNull() throws Exception { + when(mockInterceptorStrategy.shouldRun(request)).thenReturn(true); + when(mockAttributeStrategy.hasLiteAttribute(request)).thenReturn(false); + when(mockIpStrategy.getIPAddress(request)).thenReturn(null); + + boolean result = ipinfoSpring.preHandle(request, response, handler); + + assertTrue(result, "preHandle should return true to continue chain"); + verify(mockInterceptorStrategy).shouldRun(request); + verify(mockAttributeStrategy).hasLiteAttribute(request); + verify(mockIpStrategy).getIPAddress(request); + // Verify no IP lookup or storage occurred + verifyNoInteractions(mockIPinfoClient); + verify(mockAttributeStrategy, never()).storeLiteAttribute(any(), any()); + } + + @Test + @DisplayName( + "should perform IP lookup and store attribute if all conditions met" + ) + void preHandle_shouldProcessAndStore() throws Exception { + String testIp = "8.8.8.8"; + when(mockInterceptorStrategy.shouldRun(request)).thenReturn(true); + when(mockAttributeStrategy.hasLiteAttribute(request)).thenReturn(false); + when(mockIpStrategy.getIPAddress(request)).thenReturn(testIp); + when(mockIPinfoClient.lookupIP(testIp)).thenReturn(dummyIPResponse); + + boolean result = ipinfoSpring.preHandle(request, response, handler); + + assertTrue(result, "preHandle should return true to continue chain"); + verify(mockInterceptorStrategy).shouldRun(request); + verify(mockAttributeStrategy).hasLiteAttribute(request); + verify(mockIpStrategy).getIPAddress(request); + verify(mockIPinfoClient).lookupIP(testIp); + verify(mockAttributeStrategy).storeLiteAttribute( + request, + dummyIPResponse + ); + } + + @Test + @DisplayName("should rethrow RateLimitedException during lookup") + void preHandle_shouldRethrowRateLimitedException() throws Exception { + String testIp = "invalid.ip"; + when(mockInterceptorStrategy.shouldRun(request)).thenReturn(true); + when(mockAttributeStrategy.hasLiteAttribute(request)).thenReturn(false); + when(mockIpStrategy.getIPAddress(request)).thenReturn(testIp); + // Simulate a RateLimitedException during lookup + when(mockIPinfoClient.lookupIP(testIp)).thenThrow( + new RateLimitedException() + ); + + assertThrows(RateLimitedException.class, () -> + ipinfoSpring.preHandle(request, response, handler) + ); + + verify(mockInterceptorStrategy).shouldRun(request); + verify(mockAttributeStrategy).hasLiteAttribute(request); + verify(mockIpStrategy).getIPAddress(request); + verify(mockIPinfoClient).lookupIP(testIp); + verify(mockAttributeStrategy, never()).storeLiteAttribute(any(), any()); + } +} From 82f4a9e34d61e5824deacf35351769b2f1039e54 Mon Sep 17 00:00:00 2001 From: Silvano Cerza Date: Fri, 1 Aug 2025 18:18:08 +0200 Subject: [PATCH 4/5] Add test workflow --- .github/workflows/test.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..b36d753 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,26 @@ +name: Test + +on: + push: + branches: + - "master" + pull_request: + branches: + - "master" + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: "17" + distribution: "temurin" + cache: maven + + - name: Run Maven Tests + run: mvn -B test From 306d044cba481361408834204ef5cce9deb0efc1 Mon Sep 17 00:00:00 2001 From: Silvano Cerza Date: Fri, 1 Aug 2025 18:20:37 +0200 Subject: [PATCH 5/5] Update README.md --- README.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fcf10ee..11b190f 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ fields and additional request volumes see [Click here to view the Java Spring SDK's API documentation](https://ipinfo.github.io/spring/). -⚠️ Note: This library does not currently support our newest free API https://ipinfo.io/lite. If you’d like to use IPinfo Lite, you can call the [endpoint directly](https://ipinfo.io/developers/lite-api) using your preferred HTTP client. Developers are also welcome to contribute support for Lite by submitting a pull request. +The library also supports the Lite API, see the [Lite API section](#lite-api) for more info. ## Usage @@ -174,6 +174,30 @@ The `AttributeStrategy` allows the middleware to know where to store the Any exceptions such as `RateLimitedException` is passed through Spring's error handling system. +### Lite API + +The library gives the possibility to use the [Lite API](https://ipinfo.io/developers/lite-api) too, authentication with your token is still required. + +The returned details are slightly different from the Core API. + +To use the Lite API you must use the `IPinfoLiteSpring`, it works in the same way as the `IPinfoSpring` class. + +```java + IPinfoLiteSpring ipinfoSpring = new IPinfoLiteSpring.Builder() + // Set the IPinfo instance. By default we provide one, however you're + // allowed to change this here. Also provide your IPinfo Access Token here. + .setIPinfo(new IPinfoLite.Builder().setToken("IPINFO ACCESS TOKEN").build()) + // Set the InterceptorStrategy. By default we use + // BotInterceptorStrategy. + .interceptorStrategy(new BotInterceptorStrategy()) + // Set the IPStrategy. By default we use SimpleIPStrategy. + .ipStrategy(new SimpleIPStrategy()) + // Set the AttributeStrategy. By default we use SessionAttributeStrategy. + .attributeStrategy(new SessionAttributeStrategy()) + // Finally build it. + .build(); +``` + ### Other Libraries There are [official IPinfo client libraries](https://ipinfo.io/developers/libraries) available for many languages including PHP, Python, Go, Java, Ruby, and many popular frameworks such as Django, Rails, and Laravel. There are also many third-party libraries and integrations available for our API.