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 @@ |
|||||||
|
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 @@ |
|||||||
|
<?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 @@ |
|||||||
|
/** |
||||||
|
* 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 @@ |
|||||||
|
/** |
||||||
|
* 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 @@ |
|||||||
|
/** |
||||||
|
* 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 @@ |
|||||||
|
/** |
||||||
|
* 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 @@ |
|||||||
|
/** |
||||||
|
* 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 @@ |
|||||||
|
/** |
||||||
|
* 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 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"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