Browse Source
* Provides decoder and encoder for JSON-java * Rename feign-json to feign-org.json, add link to JSON web-site to README, use instanceof instead of references (JsonEncoder) * Return back feign-json, JSON-java * Fix parent version * Added JSON-java decoder to decoders list * Increase coverage: empty response body, parsing exception is caused by another exception * Use isAssignableFrom to allow methods return extended JSONObject and JSONArray classes Co-authored-by: Marvin Froeder <marvin.froeder@dovetailstudios.com>pull/1455/head
Witalij Berdinskich
3 years ago
committed by
GitHub
11 changed files with 1305 additions and 0 deletions
@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
|
||||
JSON-java Codec |
||||
=================== |
||||
|
||||
This module adds support for encoding and decoding [JSON][] via [JSON-java][]. |
||||
|
||||
Add `JsonEncoder` and/or `JsonDecoder` to your `Feign.Builder` like so: |
||||
|
||||
```java |
||||
api = Feign.builder() |
||||
.decoder(new JsonDecoder()) |
||||
.encoder(new JsonEncoder()) |
||||
.target(GitHub.class, "https://api"); |
||||
``` |
||||
|
||||
[JSON]: https://www.json.org/json-en.html |
||||
[JSON-java]: https://github.com/stleary/JSON-java |
@ -0,0 +1,69 @@
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
|
||||
Copyright 2012-2021 The Feign Authors |
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
||||
in compliance with the License. You may obtain a copy of the License at |
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License |
||||
is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
||||
or implied. See the License for the specific language governing permissions and limitations under |
||||
the License. |
||||
|
||||
--> |
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
<parent> |
||||
<groupId>io.github.openfeign</groupId> |
||||
<artifactId>parent</artifactId> |
||||
<version>11.3-SNAPSHOT</version> |
||||
</parent> |
||||
|
||||
<artifactId>feign-json</artifactId> |
||||
<name>Feign JSON-java</name> |
||||
<description>Feign JSON-java</description> |
||||
|
||||
<properties> |
||||
<main.basedir>${project.basedir}/..</main.basedir> |
||||
<hamcrest.version>1.3</hamcrest.version> |
||||
<mockito.version>1.10.19</mockito.version> |
||||
</properties> |
||||
|
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>${project.groupId}</groupId> |
||||
<artifactId>feign-core</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.json</groupId> |
||||
<artifactId>json</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.hamcrest</groupId> |
||||
<artifactId>hamcrest-core</artifactId> |
||||
<version>${hamcrest.version}</version> |
||||
<scope>test</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.hamcrest</groupId> |
||||
<artifactId>hamcrest-library</artifactId> |
||||
<version>${hamcrest.version}</version> |
||||
<scope>test</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.mockito</groupId> |
||||
<artifactId>mockito-all</artifactId> |
||||
<version>${mockito.version}</version> |
||||
<scope>test</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>${project.groupId}</groupId> |
||||
<artifactId>feign-mock</artifactId> |
||||
<scope>test</scope> |
||||
</dependency> |
||||
</dependencies> |
||||
</project> |
@ -0,0 +1,86 @@
@@ -0,0 +1,86 @@
|
||||
/** |
||||
* Copyright 2012-2021 The Feign Authors |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
||||
* in compliance with the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License |
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
||||
* or implied. See the License for the specific language governing permissions and limitations under |
||||
* the License. |
||||
*/ |
||||
package feign.json; |
||||
|
||||
import feign.Response; |
||||
import feign.codec.DecodeException; |
||||
import feign.codec.Decoder; |
||||
import org.json.JSONArray; |
||||
import org.json.JSONException; |
||||
import org.json.JSONObject; |
||||
import org.json.JSONTokener; |
||||
import java.io.BufferedReader; |
||||
import java.io.IOException; |
||||
import java.io.Reader; |
||||
import java.lang.reflect.Type; |
||||
import static feign.Util.UTF_8; |
||||
import static java.lang.String.format; |
||||
|
||||
/** |
||||
* Decodes responses using JSON-java. |
||||
* <p> |
||||
* Basic example with {@link feign.Feign.Builder}: |
||||
* |
||||
* <pre> |
||||
* interface GitHub { |
||||
* |
||||
* {@literal @}RequestLine("GET /repos/{owner}/{repo}/contributors") |
||||
* JSONArray contributors({@literal @}Param("owner") String owner, {@literal @}Param("repo") String repo); |
||||
* |
||||
* } |
||||
* |
||||
* GitHub github = Feign.builder() |
||||
* .decoder(new JsonDecoder()) |
||||
* .target(GitHub.class, "https://api.github.com"); |
||||
* |
||||
* JSONArray contributors = github.contributors("openfeign", "feign"); |
||||
* |
||||
* System.out.println(contributors.getJSONObject(0).getString("login")); |
||||
* </pre> |
||||
*/ |
||||
public class JsonDecoder implements Decoder { |
||||
|
||||
@Override |
||||
public Object decode(Response response, Type type) throws IOException, DecodeException { |
||||
if (response.body() == null) |
||||
return null; |
||||
try (Reader reader = response.body().asReader(response.charset())) { |
||||
Reader bodyReader = (reader.markSupported()) ? reader : new BufferedReader(reader); |
||||
bodyReader.mark(1); |
||||
if (bodyReader.read() == -1) { |
||||
return null; // Empty body
|
||||
} |
||||
bodyReader.reset(); |
||||
return decodeJSON(response, type, bodyReader); |
||||
} catch (JSONException jsonException) { |
||||
if (jsonException.getCause() != null && jsonException.getCause() instanceof IOException) { |
||||
throw (IOException) jsonException.getCause(); |
||||
} |
||||
throw new DecodeException(response.status(), jsonException.getMessage(), response.request(), |
||||
jsonException); |
||||
} |
||||
} |
||||
|
||||
private Object decodeJSON(Response response, Type type, Reader reader) { |
||||
JSONTokener tokenizer = new JSONTokener(reader); |
||||
if (JSONObject.class.isAssignableFrom((Class<?>) type)) |
||||
return new JSONObject(tokenizer); |
||||
else if (JSONArray.class.isAssignableFrom((Class<?>) type)) |
||||
return new JSONArray(tokenizer); |
||||
else |
||||
throw new DecodeException(response.status(), |
||||
format("%s is not a type supported by this decoder.", type), response.request()); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,65 @@
@@ -0,0 +1,65 @@
|
||||
/** |
||||
* Copyright 2012-2021 The Feign Authors |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
||||
* in compliance with the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License |
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
||||
* or implied. See the License for the specific language governing permissions and limitations under |
||||
* the License. |
||||
*/ |
||||
package feign.json; |
||||
|
||||
import feign.RequestTemplate; |
||||
import feign.codec.EncodeException; |
||||
import feign.codec.Encoder; |
||||
import org.json.JSONArray; |
||||
import org.json.JSONObject; |
||||
import java.lang.reflect.Type; |
||||
import static java.lang.String.format; |
||||
|
||||
/** |
||||
* Encodes requests using JSON-java. |
||||
* <p> |
||||
* Basic example with {@link feign.Feign.Builder}: |
||||
* |
||||
* <pre> |
||||
* interface GitHub { |
||||
* |
||||
* {@literal @}RequestLine("POST /repos/{owner}/{repo}/contributors") |
||||
* JSONObject create({@literal @}Param("owner") String owner, |
||||
* {@literal @}@Param("repo") String repo, |
||||
* JSONObject contributor); |
||||
* |
||||
* } |
||||
* |
||||
* GitHub github = Feign.builder() |
||||
* .decoder(new JsonDecoder()) |
||||
* .encoder(new JsonEncoder()) |
||||
* .target(GitHub.class, "https://api.github.com"); |
||||
* |
||||
* JSONObject contributor = new JSONObject(); |
||||
* |
||||
* contributor.put("login", "radio-rogal"); |
||||
* contributor.put("contributions", 0); |
||||
* github.create("openfeign", "feign", contributor); |
||||
* </pre> |
||||
*/ |
||||
public class JsonEncoder implements Encoder { |
||||
|
||||
@Override |
||||
public void encode(Object object, Type bodyType, RequestTemplate template) |
||||
throws EncodeException { |
||||
if (object == null) |
||||
return; |
||||
if (object instanceof JSONArray || object instanceof JSONObject) { |
||||
template.body(object.toString()); |
||||
} else { |
||||
throw new EncodeException(format("%s is not a type supported by this encoder.", bodyType)); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,93 @@
@@ -0,0 +1,93 @@
|
||||
/** |
||||
* Copyright 2012-2021 The Feign Authors |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
||||
* in compliance with the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License |
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
||||
* or implied. See the License for the specific language governing permissions and limitations under |
||||
* the License. |
||||
*/ |
||||
package feign.json; |
||||
|
||||
import feign.Feign; |
||||
import feign.Param; |
||||
import feign.Request; |
||||
import feign.RequestLine; |
||||
import feign.mock.HttpMethod; |
||||
import feign.mock.MockClient; |
||||
import feign.mock.MockTarget; |
||||
import org.json.JSONArray; |
||||
import org.json.JSONObject; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import static feign.Util.toByteArray; |
||||
import static org.hamcrest.MatcherAssert.assertThat; |
||||
import static org.hamcrest.Matchers.containsString; |
||||
import static org.hamcrest.Matchers.hasSize; |
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertNotNull; |
||||
|
||||
|
||||
interface GitHub { |
||||
|
||||
@RequestLine("GET /repos/{owner}/{repo}/contributors") |
||||
JSONArray contributors(@Param("owner") String owner, @Param("repo") String repo); |
||||
|
||||
@RequestLine("POST /repos/{owner}/{repo}/contributors") |
||||
JSONObject create(@Param("owner") String owner, |
||||
@Param("repo") String repo, |
||||
JSONObject contributor); |
||||
|
||||
} |
||||
|
||||
|
||||
public class JsonCodecTest { |
||||
|
||||
private GitHub github; |
||||
private MockClient mockClient; |
||||
|
||||
@Before |
||||
public void setUp() { |
||||
mockClient = new MockClient(); |
||||
github = Feign.builder() |
||||
.decoder(new JsonDecoder()) |
||||
.encoder(new JsonEncoder()) |
||||
.client(mockClient) |
||||
.target(new MockTarget<>(GitHub.class)); |
||||
} |
||||
|
||||
@Test |
||||
public void decodes() throws IOException { |
||||
try (InputStream input = getClass().getResourceAsStream("/fixtures/contributors.json")) { |
||||
byte[] response = toByteArray(input); |
||||
mockClient.ok(HttpMethod.GET, "/repos/openfeign/feign/contributors", response); |
||||
JSONArray contributors = github.contributors("openfeign", "feign"); |
||||
assertThat(contributors.toList(), hasSize(30)); |
||||
contributors.forEach(contributor -> ((JSONObject) contributor).getString("login")); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void encodes() { |
||||
JSONObject contributor = new JSONObject(); |
||||
contributor.put("login", "radio-rogal"); |
||||
contributor.put("contributions", 0); |
||||
mockClient.ok(HttpMethod.POST, "/repos/openfeign/feign/contributors", |
||||
"{\"login\":\"radio-rogal\",\"contributions\":0}"); |
||||
JSONObject response = github.create("openfeign", "feign", contributor); |
||||
Request request = mockClient.verifyOne(HttpMethod.POST, "/repos/openfeign/feign/contributors"); |
||||
assertNotNull(request.body()); |
||||
String json = new String(request.body()); |
||||
assertThat(json, containsString("\"login\":\"radio-rogal\"")); |
||||
assertThat(json, containsString("\"contributions\":0")); |
||||
assertEquals("radio-rogal", response.getString("login")); |
||||
assertEquals(0, response.getInt("contributions")); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,218 @@
@@ -0,0 +1,218 @@
|
||||
/** |
||||
* Copyright 2012-2021 The Feign Authors |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
||||
* in compliance with the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License |
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
||||
* or implied. See the License for the specific language governing permissions and limitations under |
||||
* the License. |
||||
*/ |
||||
package feign.json; |
||||
|
||||
import feign.Request; |
||||
import feign.Response; |
||||
import feign.codec.DecodeException; |
||||
import org.json.JSONArray; |
||||
import org.json.JSONException; |
||||
import org.json.JSONObject; |
||||
import org.junit.BeforeClass; |
||||
import org.junit.Test; |
||||
import java.io.IOException; |
||||
import java.nio.charset.StandardCharsets; |
||||
import java.util.Collections; |
||||
import java.util.Date; |
||||
import static feign.Util.UTF_8; |
||||
import static org.junit.Assert.*; |
||||
import static org.mockito.Matchers.any; |
||||
import static org.mockito.Mockito.mock; |
||||
import static org.mockito.Mockito.when; |
||||
|
||||
public class JsonDecoderTest { |
||||
|
||||
private static JSONArray jsonArray; |
||||
private static JSONObject jsonObject; |
||||
private static Request request; |
||||
|
||||
@BeforeClass |
||||
public static void setUpClass() { |
||||
jsonObject = new JSONObject(); |
||||
jsonObject.put("a", "b"); |
||||
jsonObject.put("c", 1); |
||||
jsonArray = new JSONArray(); |
||||
jsonArray.put(jsonObject); |
||||
jsonArray.put(123); |
||||
request = Request.create(Request.HttpMethod.GET, "/qwerty", Collections.emptyMap(), |
||||
"xyz".getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8, null); |
||||
} |
||||
|
||||
@Test |
||||
public void decodesArray() throws IOException { |
||||
String json = "[{\"a\":\"b\",\"c\":1},123]"; |
||||
Response response = Response.builder() |
||||
.status(204) |
||||
.reason("OK") |
||||
.headers(Collections.emptyMap()) |
||||
.body(json, UTF_8) |
||||
.request(request) |
||||
.build(); |
||||
assertTrue(jsonArray.similar(new JsonDecoder().decode(response, JSONArray.class))); |
||||
} |
||||
|
||||
@Test |
||||
public void decodesObject() throws IOException { |
||||
String json = "{\"a\":\"b\",\"c\":1}"; |
||||
Response response = Response.builder() |
||||
.status(204) |
||||
.reason("OK") |
||||
.headers(Collections.emptyMap()) |
||||
.body(json, UTF_8) |
||||
.request(request) |
||||
.build(); |
||||
assertTrue(jsonObject.similar(new JsonDecoder().decode(response, JSONObject.class))); |
||||
} |
||||
|
||||
@Test |
||||
public void nullBodyDecodesToNull() throws IOException { |
||||
Response response = Response.builder() |
||||
.status(204) |
||||
.reason("OK") |
||||
.headers(Collections.emptyMap()) |
||||
.request(request) |
||||
.build(); |
||||
assertNull(new JsonDecoder().decode(response, JSONObject.class)); |
||||
} |
||||
|
||||
@Test |
||||
public void emptyBodyDecodesToNull() throws IOException { |
||||
Response response = Response.builder() |
||||
.status(204) |
||||
.reason("OK") |
||||
.headers(Collections.emptyMap()) |
||||
.body("", UTF_8) |
||||
.request(request) |
||||
.build(); |
||||
assertNull(new JsonDecoder().decode(response, JSONObject.class)); |
||||
} |
||||
|
||||
@Test |
||||
public void unknownTypeThrowsDecodeException() throws IOException { |
||||
String json = "[{\"a\":\"b\",\"c\":1},123]"; |
||||
Response response = Response.builder() |
||||
.status(204) |
||||
.reason("OK") |
||||
.headers(Collections.emptyMap()) |
||||
.body(json, UTF_8) |
||||
.request(request) |
||||
.build(); |
||||
Exception exception = assertThrows(DecodeException.class, |
||||
() -> new JsonDecoder().decode(response, Date.class)); |
||||
assertEquals("class java.util.Date is not a type supported by this decoder.", |
||||
exception.getMessage()); |
||||
} |
||||
|
||||
@Test |
||||
public void badJsonThrowsWrappedJSONException() throws IOException { |
||||
String json = "{\"a\":\"b\",\"c\":1}"; |
||||
Response response = Response.builder() |
||||
.status(204) |
||||
.reason("OK") |
||||
.headers(Collections.emptyMap()) |
||||
.body(json, UTF_8) |
||||
.request(request) |
||||
.build(); |
||||
Exception exception = assertThrows(DecodeException.class, |
||||
() -> new JsonDecoder().decode(response, JSONArray.class)); |
||||
assertEquals("A JSONArray text must start with '[' at 1 [character 2 line 1]", |
||||
exception.getMessage()); |
||||
assertTrue(exception.getCause() instanceof JSONException); |
||||
} |
||||
|
||||
@Test |
||||
public void causedByCommonException() throws IOException { |
||||
Response.Body body = mock(Response.Body.class); |
||||
when(body.asReader(any())).thenThrow(new JSONException("test exception", |
||||
new Exception("test cause exception"))); |
||||
Response response = Response.builder() |
||||
.status(204) |
||||
.reason("OK") |
||||
.headers(Collections.emptyMap()) |
||||
.body(body) |
||||
.request(request) |
||||
.build(); |
||||
Exception exception = assertThrows(DecodeException.class, |
||||
() -> new JsonDecoder().decode(response, JSONArray.class)); |
||||
assertEquals("test exception", exception.getMessage()); |
||||
} |
||||
|
||||
@Test |
||||
public void causedByIOException() throws IOException { |
||||
Response.Body body = mock(Response.Body.class); |
||||
when(body.asReader(any())).thenThrow(new JSONException("test exception", |
||||
new IOException("test cause exception"))); |
||||
Response response = Response.builder() |
||||
.status(204) |
||||
.reason("OK") |
||||
.headers(Collections.emptyMap()) |
||||
.body(body) |
||||
.request(request) |
||||
.build(); |
||||
Exception exception = assertThrows(IOException.class, |
||||
() -> new JsonDecoder().decode(response, JSONArray.class)); |
||||
assertEquals("test cause exception", exception.getMessage()); |
||||
} |
||||
|
||||
@Test |
||||
public void checkedException() throws IOException { |
||||
Response.Body body = mock(Response.Body.class); |
||||
when(body.asReader(any())).thenThrow(new IOException("test exception")); |
||||
Response response = Response.builder() |
||||
.status(204) |
||||
.reason("OK") |
||||
.headers(Collections.emptyMap()) |
||||
.body(body) |
||||
.request(request) |
||||
.build(); |
||||
Exception exception = assertThrows(IOException.class, |
||||
() -> new JsonDecoder().decode(response, JSONArray.class)); |
||||
assertEquals("test exception", exception.getMessage()); |
||||
} |
||||
|
||||
@Test |
||||
public void decodesExtendedArray() throws IOException { |
||||
String json = "[{\"a\":\"b\",\"c\":1},123]"; |
||||
Response response = Response.builder() |
||||
.status(204) |
||||
.reason("OK") |
||||
.headers(Collections.emptyMap()) |
||||
.body(json, UTF_8) |
||||
.request(request) |
||||
.build(); |
||||
assertTrue(jsonArray.similar(new JsonDecoder().decode(response, ExtendedJSONArray.class))); |
||||
} |
||||
|
||||
@Test |
||||
public void decodeExtendedObject() throws IOException { |
||||
String json = "{\"a\":\"b\",\"c\":1}"; |
||||
Response response = Response.builder() |
||||
.status(204) |
||||
.reason("OK") |
||||
.headers(Collections.emptyMap()) |
||||
.body(json, UTF_8) |
||||
.request(request) |
||||
.build(); |
||||
assertTrue(jsonObject.similar(new JsonDecoder().decode(response, ExtendedJSONObject.class))); |
||||
} |
||||
|
||||
static class ExtendedJSONArray extends JSONArray { |
||||
|
||||
} |
||||
|
||||
static class ExtendedJSONObject extends JSONObject { |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,69 @@
@@ -0,0 +1,69 @@
|
||||
/** |
||||
* Copyright 2012-2021 The Feign Authors |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
||||
* in compliance with the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License |
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
||||
* or implied. See the License for the specific language governing permissions and limitations under |
||||
* the License. |
||||
*/ |
||||
package feign.json; |
||||
|
||||
import feign.RequestTemplate; |
||||
import feign.codec.EncodeException; |
||||
import org.json.JSONArray; |
||||
import org.json.JSONObject; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import java.util.Date; |
||||
import static feign.Util.UTF_8; |
||||
import static org.junit.Assert.*; |
||||
|
||||
public class JsonEncoderTest { |
||||
|
||||
private JSONArray jsonArray; |
||||
private JSONObject jsonObject; |
||||
private RequestTemplate requestTemplate; |
||||
|
||||
@Before |
||||
public void setUp() { |
||||
jsonObject = new JSONObject(); |
||||
jsonObject.put("a", "b"); |
||||
jsonObject.put("c", 1); |
||||
jsonArray = new JSONArray(); |
||||
jsonArray.put(jsonObject); |
||||
jsonArray.put(123); |
||||
requestTemplate = new RequestTemplate(); |
||||
} |
||||
|
||||
@Test |
||||
public void encodesArray() { |
||||
new JsonEncoder().encode(jsonArray, JSONArray.class, requestTemplate); |
||||
assertEquals("[{\"a\":\"b\",\"c\":1},123]", new String(requestTemplate.body(), UTF_8)); |
||||
} |
||||
|
||||
@Test |
||||
public void encodesObject() { |
||||
new JsonEncoder().encode(jsonObject, JSONObject.class, requestTemplate); |
||||
assertEquals("{\"a\":\"b\",\"c\":1}", new String(requestTemplate.body(), UTF_8)); |
||||
} |
||||
|
||||
@Test |
||||
public void encodesNull() { |
||||
new JsonEncoder().encode(null, JSONObject.class, new RequestTemplate()); |
||||
assertNull(requestTemplate.body()); |
||||
} |
||||
|
||||
@Test |
||||
public void unknownTypeThrowsEncodeException() { |
||||
Exception exception = assertThrows(EncodeException.class, |
||||
() -> new JsonEncoder().encode("qwerty", Date.class, new RequestTemplate())); |
||||
assertEquals("class java.util.Date is not a type supported by this encoder.", |
||||
exception.getMessage()); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,48 @@
@@ -0,0 +1,48 @@
|
||||
/** |
||||
* Copyright 2012-2021 The Feign Authors |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
||||
* in compliance with the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License |
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
||||
* or implied. See the License for the specific language governing permissions and limitations under |
||||
* the License. |
||||
*/ |
||||
package feign.json.examples; |
||||
|
||||
import feign.Feign; |
||||
import feign.Param; |
||||
import feign.RequestLine; |
||||
import feign.json.JsonDecoder; |
||||
import org.json.JSONArray; |
||||
import org.json.JSONObject; |
||||
|
||||
interface GitHub { |
||||
|
||||
@RequestLine("GET /repos/{owner}/{repo}/contributors") |
||||
JSONArray contributors(@Param("owner") String owner, @Param("repo") String repo); |
||||
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* adapted from {@code com.example.retrofit.GitHubClient} |
||||
*/ |
||||
public class GitHubExample { |
||||
|
||||
public static void main(String... args) { |
||||
GitHub github = Feign.builder() |
||||
.decoder(new JsonDecoder()) |
||||
.target(GitHub.class, "https://api.github.com"); |
||||
|
||||
System.out.println("Let's fetch and print a list of the contributors to this library."); |
||||
JSONArray contributors = github.contributors("netflix", "feign"); |
||||
contributors.forEach(contributor -> { |
||||
System.out.println(((JSONObject) contributor).getString("login")); |
||||
}); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,632 @@
@@ -0,0 +1,632 @@
|
||||
[ |
||||
{ |
||||
"login": "kdavisk6", |
||||
"id": 6013627, |
||||
"node_id": "MDQ6VXNlcjYwMTM2Mjc=", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/6013627?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/kdavisk6", |
||||
"html_url": "https://github.com/kdavisk6", |
||||
"followers_url": "https://api.github.com/users/kdavisk6/followers", |
||||
"following_url": "https://api.github.com/users/kdavisk6/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/kdavisk6/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/kdavisk6/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/kdavisk6/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/kdavisk6/orgs", |
||||
"repos_url": "https://api.github.com/users/kdavisk6/repos", |
||||
"events_url": "https://api.github.com/users/kdavisk6/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/kdavisk6/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 115 |
||||
}, |
||||
{ |
||||
"login": "velo", |
||||
"id": 136590, |
||||
"node_id": "MDQ6VXNlcjEzNjU5MA==", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/136590?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/velo", |
||||
"html_url": "https://github.com/velo", |
||||
"followers_url": "https://api.github.com/users/velo/followers", |
||||
"following_url": "https://api.github.com/users/velo/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/velo/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/velo/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/velo/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/velo/orgs", |
||||
"repos_url": "https://api.github.com/users/velo/repos", |
||||
"events_url": "https://api.github.com/users/velo/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/velo/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 98 |
||||
}, |
||||
{ |
||||
"login": "quidryan", |
||||
"id": 360255, |
||||
"node_id": "MDQ6VXNlcjM2MDI1NQ==", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/360255?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/quidryan", |
||||
"html_url": "https://github.com/quidryan", |
||||
"followers_url": "https://api.github.com/users/quidryan/followers", |
||||
"following_url": "https://api.github.com/users/quidryan/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/quidryan/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/quidryan/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/quidryan/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/quidryan/orgs", |
||||
"repos_url": "https://api.github.com/users/quidryan/repos", |
||||
"events_url": "https://api.github.com/users/quidryan/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/quidryan/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 43 |
||||
}, |
||||
{ |
||||
"login": "snyk-bot", |
||||
"id": 19733683, |
||||
"node_id": "MDQ6VXNlcjE5NzMzNjgz", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19733683?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/snyk-bot", |
||||
"html_url": "https://github.com/snyk-bot", |
||||
"followers_url": "https://api.github.com/users/snyk-bot/followers", |
||||
"following_url": "https://api.github.com/users/snyk-bot/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/snyk-bot/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/snyk-bot/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/snyk-bot/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/snyk-bot/orgs", |
||||
"repos_url": "https://api.github.com/users/snyk-bot/repos", |
||||
"events_url": "https://api.github.com/users/snyk-bot/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/snyk-bot/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 16 |
||||
}, |
||||
{ |
||||
"login": "rspieldenner", |
||||
"id": 782102, |
||||
"node_id": "MDQ6VXNlcjc4MjEwMg==", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/782102?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/rspieldenner", |
||||
"html_url": "https://github.com/rspieldenner", |
||||
"followers_url": "https://api.github.com/users/rspieldenner/followers", |
||||
"following_url": "https://api.github.com/users/rspieldenner/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/rspieldenner/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/rspieldenner/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/rspieldenner/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/rspieldenner/orgs", |
||||
"repos_url": "https://api.github.com/users/rspieldenner/repos", |
||||
"events_url": "https://api.github.com/users/rspieldenner/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/rspieldenner/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 14 |
||||
}, |
||||
{ |
||||
"login": "davidmc24", |
||||
"id": 447825, |
||||
"node_id": "MDQ6VXNlcjQ0NzgyNQ==", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/447825?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/davidmc24", |
||||
"html_url": "https://github.com/davidmc24", |
||||
"followers_url": "https://api.github.com/users/davidmc24/followers", |
||||
"following_url": "https://api.github.com/users/davidmc24/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/davidmc24/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/davidmc24/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/davidmc24/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/davidmc24/orgs", |
||||
"repos_url": "https://api.github.com/users/davidmc24/repos", |
||||
"events_url": "https://api.github.com/users/davidmc24/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/davidmc24/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 12 |
||||
}, |
||||
{ |
||||
"login": "ahus1", |
||||
"id": 3957921, |
||||
"node_id": "MDQ6VXNlcjM5NTc5MjE=", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/3957921?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/ahus1", |
||||
"html_url": "https://github.com/ahus1", |
||||
"followers_url": "https://api.github.com/users/ahus1/followers", |
||||
"following_url": "https://api.github.com/users/ahus1/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/ahus1/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/ahus1/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/ahus1/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/ahus1/orgs", |
||||
"repos_url": "https://api.github.com/users/ahus1/repos", |
||||
"events_url": "https://api.github.com/users/ahus1/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/ahus1/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 6 |
||||
}, |
||||
{ |
||||
"login": "carterkozak", |
||||
"id": 3854321, |
||||
"node_id": "MDQ6VXNlcjM4NTQzMjE=", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/3854321?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/carterkozak", |
||||
"html_url": "https://github.com/carterkozak", |
||||
"followers_url": "https://api.github.com/users/carterkozak/followers", |
||||
"following_url": "https://api.github.com/users/carterkozak/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/carterkozak/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/carterkozak/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/carterkozak/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/carterkozak/orgs", |
||||
"repos_url": "https://api.github.com/users/carterkozak/repos", |
||||
"events_url": "https://api.github.com/users/carterkozak/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/carterkozak/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 5 |
||||
}, |
||||
{ |
||||
"login": "spencergibb", |
||||
"id": 594085, |
||||
"node_id": "MDQ6VXNlcjU5NDA4NQ==", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/594085?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/spencergibb", |
||||
"html_url": "https://github.com/spencergibb", |
||||
"followers_url": "https://api.github.com/users/spencergibb/followers", |
||||
"following_url": "https://api.github.com/users/spencergibb/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/spencergibb/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/spencergibb/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/spencergibb/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/spencergibb/orgs", |
||||
"repos_url": "https://api.github.com/users/spencergibb/repos", |
||||
"events_url": "https://api.github.com/users/spencergibb/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/spencergibb/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 5 |
||||
}, |
||||
{ |
||||
"login": "allenxwang", |
||||
"id": 1728105, |
||||
"node_id": "MDQ6VXNlcjE3MjgxMDU=", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1728105?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/allenxwang", |
||||
"html_url": "https://github.com/allenxwang", |
||||
"followers_url": "https://api.github.com/users/allenxwang/followers", |
||||
"following_url": "https://api.github.com/users/allenxwang/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/allenxwang/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/allenxwang/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/allenxwang/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/allenxwang/orgs", |
||||
"repos_url": "https://api.github.com/users/allenxwang/repos", |
||||
"events_url": "https://api.github.com/users/allenxwang/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/allenxwang/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 5 |
||||
}, |
||||
{ |
||||
"login": "gimbimloki", |
||||
"id": 4572139, |
||||
"node_id": "MDQ6VXNlcjQ1NzIxMzk=", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/4572139?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/gimbimloki", |
||||
"html_url": "https://github.com/gimbimloki", |
||||
"followers_url": "https://api.github.com/users/gimbimloki/followers", |
||||
"following_url": "https://api.github.com/users/gimbimloki/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/gimbimloki/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/gimbimloki/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/gimbimloki/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/gimbimloki/orgs", |
||||
"repos_url": "https://api.github.com/users/gimbimloki/repos", |
||||
"events_url": "https://api.github.com/users/gimbimloki/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/gimbimloki/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 4 |
||||
}, |
||||
{ |
||||
"login": "jkschneider", |
||||
"id": 1697736, |
||||
"node_id": "MDQ6VXNlcjE2OTc3MzY=", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1697736?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/jkschneider", |
||||
"html_url": "https://github.com/jkschneider", |
||||
"followers_url": "https://api.github.com/users/jkschneider/followers", |
||||
"following_url": "https://api.github.com/users/jkschneider/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/jkschneider/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/jkschneider/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/jkschneider/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/jkschneider/orgs", |
||||
"repos_url": "https://api.github.com/users/jkschneider/repos", |
||||
"events_url": "https://api.github.com/users/jkschneider/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/jkschneider/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 4 |
||||
}, |
||||
{ |
||||
"login": "nmiyake", |
||||
"id": 4267425, |
||||
"node_id": "MDQ6VXNlcjQyNjc0MjU=", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/4267425?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/nmiyake", |
||||
"html_url": "https://github.com/nmiyake", |
||||
"followers_url": "https://api.github.com/users/nmiyake/followers", |
||||
"following_url": "https://api.github.com/users/nmiyake/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/nmiyake/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/nmiyake/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/nmiyake/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/nmiyake/orgs", |
||||
"repos_url": "https://api.github.com/users/nmiyake/repos", |
||||
"events_url": "https://api.github.com/users/nmiyake/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/nmiyake/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 4 |
||||
}, |
||||
{ |
||||
"login": "rfalke", |
||||
"id": 1261007, |
||||
"node_id": "MDQ6VXNlcjEyNjEwMDc=", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1261007?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/rfalke", |
||||
"html_url": "https://github.com/rfalke", |
||||
"followers_url": "https://api.github.com/users/rfalke/followers", |
||||
"following_url": "https://api.github.com/users/rfalke/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/rfalke/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/rfalke/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/rfalke/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/rfalke/orgs", |
||||
"repos_url": "https://api.github.com/users/rfalke/repos", |
||||
"events_url": "https://api.github.com/users/rfalke/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/rfalke/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 4 |
||||
}, |
||||
{ |
||||
"login": "SimY4", |
||||
"id": 1394639, |
||||
"node_id": "MDQ6VXNlcjEzOTQ2Mzk=", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1394639?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/SimY4", |
||||
"html_url": "https://github.com/SimY4", |
||||
"followers_url": "https://api.github.com/users/SimY4/followers", |
||||
"following_url": "https://api.github.com/users/SimY4/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/SimY4/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/SimY4/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/SimY4/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/SimY4/orgs", |
||||
"repos_url": "https://api.github.com/users/SimY4/repos", |
||||
"events_url": "https://api.github.com/users/SimY4/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/SimY4/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 3 |
||||
}, |
||||
{ |
||||
"login": "bstick12", |
||||
"id": 1146861, |
||||
"node_id": "MDQ6VXNlcjExNDY4NjE=", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1146861?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/bstick12", |
||||
"html_url": "https://github.com/bstick12", |
||||
"followers_url": "https://api.github.com/users/bstick12/followers", |
||||
"following_url": "https://api.github.com/users/bstick12/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/bstick12/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/bstick12/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/bstick12/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/bstick12/orgs", |
||||
"repos_url": "https://api.github.com/users/bstick12/repos", |
||||
"events_url": "https://api.github.com/users/bstick12/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/bstick12/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 3 |
||||
}, |
||||
{ |
||||
"login": "mstrYoda", |
||||
"id": 12763626, |
||||
"node_id": "MDQ6VXNlcjEyNzYzNjI2", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/12763626?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/mstrYoda", |
||||
"html_url": "https://github.com/mstrYoda", |
||||
"followers_url": "https://api.github.com/users/mstrYoda/followers", |
||||
"following_url": "https://api.github.com/users/mstrYoda/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/mstrYoda/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/mstrYoda/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/mstrYoda/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/mstrYoda/orgs", |
||||
"repos_url": "https://api.github.com/users/mstrYoda/repos", |
||||
"events_url": "https://api.github.com/users/mstrYoda/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/mstrYoda/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 3 |
||||
}, |
||||
{ |
||||
"login": "jacob-meacham", |
||||
"id": 1624811, |
||||
"node_id": "MDQ6VXNlcjE2MjQ4MTE=", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1624811?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/jacob-meacham", |
||||
"html_url": "https://github.com/jacob-meacham", |
||||
"followers_url": "https://api.github.com/users/jacob-meacham/followers", |
||||
"following_url": "https://api.github.com/users/jacob-meacham/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/jacob-meacham/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/jacob-meacham/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/jacob-meacham/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/jacob-meacham/orgs", |
||||
"repos_url": "https://api.github.com/users/jacob-meacham/repos", |
||||
"events_url": "https://api.github.com/users/jacob-meacham/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/jacob-meacham/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 3 |
||||
}, |
||||
{ |
||||
"login": "pnepywoda", |
||||
"id": 13909400, |
||||
"node_id": "MDQ6VXNlcjEzOTA5NDAw", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/13909400?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/pnepywoda", |
||||
"html_url": "https://github.com/pnepywoda", |
||||
"followers_url": "https://api.github.com/users/pnepywoda/followers", |
||||
"following_url": "https://api.github.com/users/pnepywoda/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/pnepywoda/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/pnepywoda/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/pnepywoda/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/pnepywoda/orgs", |
||||
"repos_url": "https://api.github.com/users/pnepywoda/repos", |
||||
"events_url": "https://api.github.com/users/pnepywoda/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/pnepywoda/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 3 |
||||
}, |
||||
{ |
||||
"login": "santhosh-tekuri", |
||||
"id": 1112271, |
||||
"node_id": "MDQ6VXNlcjExMTIyNzE=", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1112271?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/santhosh-tekuri", |
||||
"html_url": "https://github.com/santhosh-tekuri", |
||||
"followers_url": "https://api.github.com/users/santhosh-tekuri/followers", |
||||
"following_url": "https://api.github.com/users/santhosh-tekuri/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/santhosh-tekuri/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/santhosh-tekuri/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/santhosh-tekuri/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/santhosh-tekuri/orgs", |
||||
"repos_url": "https://api.github.com/users/santhosh-tekuri/repos", |
||||
"events_url": "https://api.github.com/users/santhosh-tekuri/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/santhosh-tekuri/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 3 |
||||
}, |
||||
{ |
||||
"login": "jerzykrlk", |
||||
"id": 4005877, |
||||
"node_id": "MDQ6VXNlcjQwMDU4Nzc=", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/4005877?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/jerzykrlk", |
||||
"html_url": "https://github.com/jerzykrlk", |
||||
"followers_url": "https://api.github.com/users/jerzykrlk/followers", |
||||
"following_url": "https://api.github.com/users/jerzykrlk/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/jerzykrlk/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/jerzykrlk/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/jerzykrlk/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/jerzykrlk/orgs", |
||||
"repos_url": "https://api.github.com/users/jerzykrlk/repos", |
||||
"events_url": "https://api.github.com/users/jerzykrlk/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/jerzykrlk/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 3 |
||||
}, |
||||
{ |
||||
"login": "benmanbs", |
||||
"id": 1074810, |
||||
"node_id": "MDQ6VXNlcjEwNzQ4MTA=", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1074810?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/benmanbs", |
||||
"html_url": "https://github.com/benmanbs", |
||||
"followers_url": "https://api.github.com/users/benmanbs/followers", |
||||
"following_url": "https://api.github.com/users/benmanbs/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/benmanbs/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/benmanbs/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/benmanbs/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/benmanbs/orgs", |
||||
"repos_url": "https://api.github.com/users/benmanbs/repos", |
||||
"events_url": "https://api.github.com/users/benmanbs/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/benmanbs/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 2 |
||||
}, |
||||
{ |
||||
"login": "schlosna", |
||||
"id": 54594, |
||||
"node_id": "MDQ6VXNlcjU0NTk0", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/54594?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/schlosna", |
||||
"html_url": "https://github.com/schlosna", |
||||
"followers_url": "https://api.github.com/users/schlosna/followers", |
||||
"following_url": "https://api.github.com/users/schlosna/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/schlosna/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/schlosna/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/schlosna/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/schlosna/orgs", |
||||
"repos_url": "https://api.github.com/users/schlosna/repos", |
||||
"events_url": "https://api.github.com/users/schlosna/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/schlosna/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 2 |
||||
}, |
||||
{ |
||||
"login": "dharmeshjogadia", |
||||
"id": 6071120, |
||||
"node_id": "MDQ6VXNlcjYwNzExMjA=", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/6071120?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/dharmeshjogadia", |
||||
"html_url": "https://github.com/dharmeshjogadia", |
||||
"followers_url": "https://api.github.com/users/dharmeshjogadia/followers", |
||||
"following_url": "https://api.github.com/users/dharmeshjogadia/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/dharmeshjogadia/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/dharmeshjogadia/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/dharmeshjogadia/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/dharmeshjogadia/orgs", |
||||
"repos_url": "https://api.github.com/users/dharmeshjogadia/repos", |
||||
"events_url": "https://api.github.com/users/dharmeshjogadia/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/dharmeshjogadia/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 2 |
||||
}, |
||||
{ |
||||
"login": "edio", |
||||
"id": 787439, |
||||
"node_id": "MDQ6VXNlcjc4NzQzOQ==", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/787439?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/edio", |
||||
"html_url": "https://github.com/edio", |
||||
"followers_url": "https://api.github.com/users/edio/followers", |
||||
"following_url": "https://api.github.com/users/edio/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/edio/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/edio/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/edio/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/edio/orgs", |
||||
"repos_url": "https://api.github.com/users/edio/repos", |
||||
"events_url": "https://api.github.com/users/edio/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/edio/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 2 |
||||
}, |
||||
{ |
||||
"login": "androidfred", |
||||
"id": 870822, |
||||
"node_id": "MDQ6VXNlcjg3MDgyMg==", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/870822?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/androidfred", |
||||
"html_url": "https://github.com/androidfred", |
||||
"followers_url": "https://api.github.com/users/androidfred/followers", |
||||
"following_url": "https://api.github.com/users/androidfred/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/androidfred/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/androidfred/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/androidfred/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/androidfred/orgs", |
||||
"repos_url": "https://api.github.com/users/androidfred/repos", |
||||
"events_url": "https://api.github.com/users/androidfred/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/androidfred/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 2 |
||||
}, |
||||
{ |
||||
"login": "stromnet", |
||||
"id": 668449, |
||||
"node_id": "MDQ6VXNlcjY2ODQ0OQ==", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/668449?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/stromnet", |
||||
"html_url": "https://github.com/stromnet", |
||||
"followers_url": "https://api.github.com/users/stromnet/followers", |
||||
"following_url": "https://api.github.com/users/stromnet/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/stromnet/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/stromnet/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/stromnet/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/stromnet/orgs", |
||||
"repos_url": "https://api.github.com/users/stromnet/repos", |
||||
"events_url": "https://api.github.com/users/stromnet/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/stromnet/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 2 |
||||
}, |
||||
{ |
||||
"login": "JonathanO", |
||||
"id": 1206546, |
||||
"node_id": "MDQ6VXNlcjEyMDY1NDY=", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1206546?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/JonathanO", |
||||
"html_url": "https://github.com/JonathanO", |
||||
"followers_url": "https://api.github.com/users/JonathanO/followers", |
||||
"following_url": "https://api.github.com/users/JonathanO/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/JonathanO/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/JonathanO/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/JonathanO/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/JonathanO/orgs", |
||||
"repos_url": "https://api.github.com/users/JonathanO/repos", |
||||
"events_url": "https://api.github.com/users/JonathanO/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/JonathanO/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 2 |
||||
}, |
||||
{ |
||||
"login": "finnetrolle", |
||||
"id": 6028373, |
||||
"node_id": "MDQ6VXNlcjYwMjgzNzM=", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/6028373?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/finnetrolle", |
||||
"html_url": "https://github.com/finnetrolle", |
||||
"followers_url": "https://api.github.com/users/finnetrolle/followers", |
||||
"following_url": "https://api.github.com/users/finnetrolle/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/finnetrolle/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/finnetrolle/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/finnetrolle/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/finnetrolle/orgs", |
||||
"repos_url": "https://api.github.com/users/finnetrolle/repos", |
||||
"events_url": "https://api.github.com/users/finnetrolle/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/finnetrolle/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 2 |
||||
}, |
||||
{ |
||||
"login": "padilo", |
||||
"id": 783959, |
||||
"node_id": "MDQ6VXNlcjc4Mzk1OQ==", |
||||
"avatar_url": "https://avatars.githubusercontent.com/u/783959?v=4", |
||||
"gravatar_id": "", |
||||
"url": "https://api.github.com/users/padilo", |
||||
"html_url": "https://github.com/padilo", |
||||
"followers_url": "https://api.github.com/users/padilo/followers", |
||||
"following_url": "https://api.github.com/users/padilo/following{/other_user}", |
||||
"gists_url": "https://api.github.com/users/padilo/gists{/gist_id}", |
||||
"starred_url": "https://api.github.com/users/padilo/starred{/owner}{/repo}", |
||||
"subscriptions_url": "https://api.github.com/users/padilo/subscriptions", |
||||
"organizations_url": "https://api.github.com/users/padilo/orgs", |
||||
"repos_url": "https://api.github.com/users/padilo/repos", |
||||
"events_url": "https://api.github.com/users/padilo/events{/privacy}", |
||||
"received_events_url": "https://api.github.com/users/padilo/received_events", |
||||
"type": "User", |
||||
"site_admin": false, |
||||
"contributions": 2 |
||||
} |
||||
] |
Loading…
Reference in new issue