Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Java JsonBin
# JSONBin.io Java SDK

[![codecov](https://codecov.io/gh/OdunlamiZO/java-jsonbin/graph/badge.svg?token=HULR9R4NAH)](https://codecov.io/gh/OdunlamiZO/java-jsonbin)

12 changes: 6 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,22 @@
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.17.1</version>
<version>2.19.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.0</version>
<version>2.19.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.18.0</version>
<version>2.19.1</version>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>3.0.2</version>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.19.1</version>
</dependency>
<dependency>
<groupId>io.github.cdimascio</groupId>
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/io/github/odunlamizo/jsonbin/App.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
package io.github.odunlamizo.jsonbin;

import io.github.cdimascio.dotenv.Dotenv;
import io.github.odunlamizo.jsonbin.model.Bin;
import io.github.odunlamizo.jsonbin.model.UserList;
import io.github.odunlamizo.jsonbin.okhttp.JsonBinOkHttp;

public class App {

public static void main(String[] args) {
// Load environment variables from .env file
Dotenv dotenv = Dotenv.configure().load();

// Get master key from .env
String masterKey = dotenv.get("JSONBIN_MASTER_KEY");

// Check if the master key exists
if (masterKey == null || masterKey.isEmpty()) {
System.err.println("Error: JSONBIN_MASTER_KEY not found in .env file");
System.exit(1);
}

JsonBin<UserList> jsonBin = new JsonBinOkHttp<>(masterKey);
Bin<UserList> bin = jsonBin.readBin("687644d36063391d31ae163f");
System.out.println(bin);
}
}
20 changes: 20 additions & 0 deletions src/main/java/io/github/odunlamizo/jsonbin/JsonBin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.github.odunlamizo.jsonbin;

import io.github.odunlamizo.jsonbin.model.Bin;
import lombok.NonNull;

/** JSONBin.io Java SDK */
public interface JsonBin<T> {

/**
* Reads the contents of a bin from JSONBin.io using its unique identifier.
*
* <p>This method fetches the bin data from the remote JSONBin.io API and deserializes it into a
* strongly-typed {@link Bin} object containing the expected data type {@code T}.
*
* @param binId the unique identifier of the bin to retrieve; must not be {@code null}
* @return a {@link Bin} object containing the deserialized data
* @throws JsonBinException if the request fails, the bin is not found, or deserialization fails
*/
Bin<T> readBin(@NonNull String binId) throws JsonBinException;
}
26 changes: 26 additions & 0 deletions src/main/java/io/github/odunlamizo/jsonbin/model/Bin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.github.odunlamizo.jsonbin.model;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

/**
* Represents a response wrapper from JSONBin.io containing both the data record and its metadata.
*
* <p>This generic class is used to hold the actual data stored in the bin (as {@code record}) and
* additional information about the bin such as creation time, visibility, and name (as {@link
* Metadata}).
*
* @param <T> the type of the data record stored in the bin
*/
@Getter
@Setter
@ToString
public class Bin<T> {

/** The actual content or data retrieved from the bin. */
private T record;

/** Metadata information about the bin, such as its ID, name, visibility, and timestamps. */
private Metadata metadata;
}
11 changes: 11 additions & 0 deletions src/main/java/io/github/odunlamizo/jsonbin/model/Error.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.github.odunlamizo.jsonbin.model;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class Error {

private String message;
}
41 changes: 41 additions & 0 deletions src/main/java/io/github/odunlamizo/jsonbin/model/Metadata.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package io.github.odunlamizo.jsonbin.model;

import com.fasterxml.jackson.annotation.JsonProperty;
import java.time.ZonedDateTime;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

/**
* Represents metadata information returned from a JSONBin.io response.
*
* <p>This includes details such as the bin's unique identifier, visibility, creation timestamp, and
* assigned name.
*/
@Getter
@Setter
@ToString
public class Metadata {

/** The unique identifier of the bin. */
private String id;

/**
* Indicates whether the bin is private.
*
* <p>Uses @JsonProperty to map from the JSON key {@code "private"} since it is a reserved
* keyword in Java.
*/
@JsonProperty("private")
private boolean _private;

/**
* The timestamp when the bin was created.
*
* <p>Expected in ISO 8601 format with timezone information.
*/
private ZonedDateTime createdAt;

/** The human-readable name assigned to the bin. */
private String name;
}
13 changes: 13 additions & 0 deletions src/main/java/io/github/odunlamizo/jsonbin/model/User.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.github.odunlamizo.jsonbin.model;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class User {

private String name;

private int age;
}
12 changes: 12 additions & 0 deletions src/main/java/io/github/odunlamizo/jsonbin/model/UserList.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.github.odunlamizo.jsonbin.model;

import java.util.List;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class UserList {

private List<User> users;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package io.github.odunlamizo.jsonbin.okhttp;

import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

class AuthInterceptor implements Interceptor {

private final String masterKey;

private final String accessKey;

public AuthInterceptor(String masterKey, String accessKey) {
this.masterKey = masterKey;
this.accessKey = accessKey;
}

@Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();

boolean hasAccessKey = accessKey != null && !accessKey.isBlank();

Request requestWithAuth =
original.newBuilder()
.header(
hasAccessKey ? "x-access-key" : "x-master-key",
hasAccessKey ? accessKey : masterKey)
.build();

return chain.proceed(requestWithAuth);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package io.github.odunlamizo.jsonbin.okhttp;

import com.fasterxml.jackson.core.type.TypeReference;
import io.github.odunlamizo.jsonbin.JsonBin;
import io.github.odunlamizo.jsonbin.JsonBinException;
import io.github.odunlamizo.jsonbin.model.Bin;
import io.github.odunlamizo.jsonbin.model.Error;
import io.github.odunlamizo.jsonbin.util.JsonUtil;
import java.io.IOException;
import lombok.NonNull;
import okhttp3.OkHttpClient;
import okhttp3.Request;

/** JSONBin.io Java SDK implementation powered by OkHttp */
public class JsonBinOkHttp<T> implements JsonBin<T> {

private final OkHttpClient client;

private final String baseUrl;

private final TypeReference<Bin<T>> typeReference;

public JsonBinOkHttp(@NonNull String masterKey) {
this(masterKey, "https://api.jsonbin.io/v3");
}

public JsonBinOkHttp(@NonNull String masterKey, @NonNull String baseUrl) {
this.baseUrl = baseUrl;
this.typeReference = new TypeReference<Bin<T>>() {};
this.client =
new OkHttpClient.Builder()
.addInterceptor(new AuthInterceptor(masterKey, null))
.build();
}

@Override
public Bin<T> readBin(@NonNull String binId) throws JsonBinException {
final String URL = String.format("%s/b/%s", baseUrl, binId);
Request request = new Request.Builder().url(URL).build();

return newCall(request);
}

private Bin<T> newCall(Request request) {
try (okhttp3.Response response = client.newCall(request).execute()) {

String json = response.body().string();

if (!response.isSuccessful()) {
Error errorResponse = JsonUtil.toValue(json, new TypeReference<Error>() {});
throw new JsonBinException(errorResponse.getMessage());
}

return JsonUtil.toValue(json, typeReference);
} catch (IOException exception) {
throw new JsonBinException(exception.getMessage(), exception.getCause());
}
}
}
52 changes: 0 additions & 52 deletions src/test/java/io/github/odunlamizo/jsonbin/util/JsonUtilTest.java

This file was deleted.