Giter Club home page Giter Club logo

dnsimple-java's Introduction

DNSimple Java Client

A Java client for the DNSimple API v2.

Build Status

Requirements

This library is tested with Java 17 (Temurin 21) and built for Java 17 JVMs.

You must also have an activated DNSimple account to access the DNSimple API.

Installation

Maven

Add this dependency to your project's POM:

<dependency>
  <groupId>com.dnsimple</groupId>
  <artifactId>dnsimple-java</artifactId>
  <version>X.X.X</version>
</dependency>

Gradle

Add this dependency to your build.gradle file:

compile 'com.dnsimple:dnsimple-java:X.X.X'

Usage

This library is a Java client you can use to interact with the DNSimple API v2.

The examples below demonstrate basic usage.

package myapp;

import com.dnsimple.Client;
import com.dnsimple.data.Account;
import com.dnsimple.data.User;
import com.dnsimple.data.WhoamiData;
import com.dnsimple.response.SimpleResponse;

public class MyApp {
    public static void main(String[] args) {
        Client client = new Client.Builder()
                .sandbox()
                .accessToken("YOUR-ACCESS-TOKEN")
                .extraUserAgent("your-user-agent")
                .build();
        SimpleResponse<WhoamiData> response = client.identity.whoami();
        Account account = response.getData().getAccount();
        User user = response.getData().getUser();
        System.out.println("Account: " + (account != null ? account.getEmail() : "N/A"));
        System.out.println("User: " + (user != null ? user.getEmail() : "N/A"));
    }
}

The user agent value will be prepended to additional user-agent information set by default in this library. While it is not strictly necessary to set the user agent, it is often helpful for the team at DNSimple when debugging, so please consider setting it.

List request options

For endpoints that support it, you can set options to filter, limit, and sort the results that the API produces thanks to the ListOptions class.

package myapp;

import com.dnsimple.Client;
import com.dnsimple.data.Certificate;
import com.dnsimple.request.ListOptions;
import com.dnsimple.response.ListResponse;

public class MyApp {
  public static void main(String[] args) {
    //...

    // Use the ListOptions.Builder class to get an create a ListOptions object
    ListOptions options = ListOptions.empty()
                    .page(2, 10) // Get the second page of 10 items
                    .sortAsc("state") // Sort by state in ascendant order
                    .filter("autoRenew", "true"); // Filter certificates with enabled auto-renew
    ListResponse<Certificate> response = client.certificates.listCertificates(1, "1", options);
    //...
  }
}

Sandbox Usage

If you would like to test in the DNSimple sandbox environment then add the sandbox() builder method to your client:

package myapp;

import com.dnsimple.Dnsimple;
import com.dnsimple.Client;

public class MyApp {
  public static void main(String[] args) {
    Client client = new Client.Builder()
                              .sandbox()
                              .accessToken("YOUR-ACCESS-TOKEN")
                              .userAgent("your-user-agent")
                              .build();
    // ...
  }
}

You will need to ensure you are using an access token created in the sandbox environment. Production tokens will not work in the sandbox environment.

Stub for Testing

When developing unit tests for your application, you should stub responses from this client to avoid making any network calls.

License

Copyright (c) 2016-2022 DNSimple Corporation. This is Free Software distributed under the MIT license.

dnsimple-java's People

Contributors

aeden avatar ags4no avatar cristiangreco avatar dependabot-preview[bot] avatar dependabot[bot] avatar duduribeiro avatar dxtimer avatar ecomba avatar ggalmazor avatar github-actions[bot] avatar jacegu avatar jodosha avatar nestorsalceda avatar olemchls avatar san983 avatar weppos avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dnsimple-java's Issues

Model options used for pagination and other common tasks for endpoint calls

Other DNSimple API clients provide specific models for common tasks such as defining pagination parameters. We should have those in this client to avoid having to directly deal with maps and reduce the chance for accidental errors due to typos in key names or data types.

This issue should probably be combined with a review of the arg types of all endpoint methods using the Go client as a baseline, although I would suggest a deviation on the ID args that we know positively that are numbers, which in the Go client are String. I propose we use Long to make our output data classes interoperable with API calls as in: get account and use the account object to update the account without requiring to cast or transform values.

Publish to Maven Central

Hello,

Please publish this library to the maven central repositories to make it easier to include it in the projects.

Thanks

Setup CI

Setup CI via Travis to run automatically on commits.

Avoid global state

Our client relies on global state in the form of the Dnsimple class for some of the configuration concerns during the instantiation of our Client.

We shouldn't rely on global state and, on top of that, there should be a single point in the system to provide configuration, preferably through a constructor's args.

Change Certificates

The methods downloadCertificate and getCertificatePrivateKey both return a CertificateBundle object.

The issue here is that if I am downloading and I access the getPrivateKey method on the CertificateBundle, I'll be greeted with a juicy Null.

It would be way better to separate the CertificateBundle into (at least) two objects so that there are no surprises for the developer working with our Java client.

Here is a case where this was misused, and worst of all, we show it when we showcase how our Java client works! In our API showcase, if you click on Java and then SSL Certificates, you will see the last example is wrong and will result in a Null being returned and not the desired private key! You can actually see it in the dnsimple app as well

How to set access token?

How do I set the access token I generated from my account page?

The read me usage does not make any sense.

Client client = new Client();
WhoamiResponse response = client.identity.whoami();
Account account = response.getData().getAccount();
System.out.println("Account: " + account);

How can you get information about the current authenticated context when no authentication was seemingly done?

Review and normalize data class property types

Current data classes have non-coherent property types when compared to each other. For example, the id of a zone record is an int on creation and a string on deletion. An account's id can also be long and string depending on the circumstance.

Data class property types:

  • should be coherent from a domain's perspective e.g. an account's id must be of the same type regardless of the data class where it's living.
  • should be coherent from a technical perspective e.g. all ids, dates, times, etc. should be of the same type across all data classes

We should base our changes on the Go client, which is the most exigent client regarding data types.

Extract an interface that users can extend to provide their own HTTP client implementations

Out current design forces our users to import Google API's HTTP client library, which is great if they previously were using it but a game-stopper if not.

To stop doing this we need to:

  • Provide an extension point (an interface) so that users can provide their own implementations
  • Change all inner workings of this library so that we don't make any assumption about how the HTTP calls are made. i.e. no part of our library should be coupled to a third-party library except for the class implementing the interface defining the extension point.

Update docs

README.md, CONTRIBUTING.md, and CHANGELOG should be updated with all the adaptations required for v1.0.0

Bug - incorrect regions validation

It is possible for me to add A record using curl, however when using Java client API and specifically running this line:
dnsClient.zones .createZoneRecord(clientId, myDomain, ZoneRecordOptions .of("ABC", "A", "1.2.3.4"))
I get 400 Http Status. After debugging very deep the client library, I found the following error message:
"Regions are not allowed in Your plan"
I am not setting up any region explicitly - in the debug mode I see that the Java Client placed here "global" as written in the documentation. I think there is a bug in the library as it adds the "global" region, but then it validates the request against the plan and reject it, due to the regions value specified.
When I set the value of regions to null explicitly via Java reflection mechanism, everything works fine

Automate versioning changes

Each time we need to release a new version, we need to update the version of the project twice. Gradle has plugins to automate that process. We should investigate and put in place the simplest possible system that helps us reduce work during releases.

Migrate all tests to end-to-end integration tests

While working on #30 I concept-tested a new kind of test that, instead of using the mocks in place - which parse and manipulate fixtures, introducing false positives, it spun up a lightweight HTTP server to replay untampered fixtures.

This test avoids the introduction of false positives by putting in motion the full HTTP stack of our client without requiring live requests to our API.

We should migrate the full test suite to this kind of test to uncover and fix any remaining false positives.

Regions on Sandbox

Hello,

I'm trying to create a zone record on my sandbox environment but I get an error:
"Regions are not allowed for your plan."

        ZoneRecordOptions zoneRecordOptions = ZoneRecordOptions.of(subdomain, "A", ip);
        dnsimpleClient.zones.createZoneRecord(dnsimpleConfig.getAccountId(),
                dnsimpleConfig.getMainDomain(), zoneRecordOptions);

So it seems by default the API uses the region global and there is no way at least of my knowledge to set to null the region.

    public static ZoneRecordOptions of(String name, String type, String content) {
        return new ZoneRecordOptions(name, type, content, null, null, singletonList("global"));
    }

Thanks

Fix data classes

Current data classes have a series of flaws:

  • They are coupled to third party libraries, which makes our users have to deal with the libraries we've chosen to implement the client.
  • They are mutable, which is confusing and promotes unwanted use of our library.

Our data classes should be:

  • Immutable. They should be considered static, fixed values that our API provides. No user should be able to tamper with values generated by us based on API call responses
  • They should be POJOs that don't know anything about how they are created. Therefore, they should have no dependencies on third-party libraries whatsoever.

The client doesn't support PATCH HTTP requests

The Google HTTP client library we're using uses an HttpTransport implementation that doesn't support the PATCH HTTP method, which would make all our API methods requiring it impossible to be used with this client.

This example test method can be used to reproduce the error:

package com.dnsimple.regression;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

import com.dnsimple.Client;
import com.dnsimple.Dnsimple;
import com.dnsimple.exception.DnsimpleException;
import com.dnsimple.response.UpdateContactResponse;
import java.io.IOException;
import java.util.Collections;
import org.junit.Test;

public class UpdateContactTest {
  @Test
  public void HTTP_method_PATCH_not_supported() throws IOException, DnsimpleException {
    Dnsimple.setApiBase("https://api.sandbox.dnsimple.com");
    Client client = new Client();
    client.setAccessToken("YOUR TOKEN");

    UpdateContactResponse response = client.contacts.updateContact("2622", "1324", Collections.singletonMap("label", "chuchu"));
    assertThat(response.getData().getLabel(), is("chuchu"));
  }
}

This is the stacktrace:

java.lang.IllegalArgumentException: HTTP method PATCH not supported

	at com.google.common.base.Preconditions.checkArgument(Preconditions.java:164)
	at com.google.api.client.util.Preconditions.checkArgument(Preconditions.java:67)
	at com.google.api.client.http.javanet.NetHttpTransport.buildRequest(NetHttpTransport.java:146)
	at com.google.api.client.http.javanet.NetHttpTransport.buildRequest(NetHttpTransport.java:55)
	at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:889)
	at com.dnsimple.endpoints.http.HttpEndpointClient.request(HttpEndpointClient.java:150)
	at com.dnsimple.endpoints.http.HttpEndpointClient.patch(HttpEndpointClient.java:111)
	at com.dnsimple.endpoints.http.HttpEndpointClient.patch(HttpEndpointClient.java:107)
	at com.dnsimple.endpoints.http.ContactsEndpoint.updateContact(ContactsEndpoint.java:48)
	at com.dnsimple.regression.UpdateContactTest.issue_13_deleteZoneRecord_throws_IllegalArgumentException(UpdateContactTest.java:24)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)

The fix for this is to add a new dependency that bridges Google HTTP client library requests through the Apache HTTP client library, and setting the transport to an instance of ApacheHTTPTransport:

public class HttpEndpointClient {

  // ...

  public HttpEndpointClient() {
    this.transport = new ApacheHttpTransport();
  }

  // ...
}

(and, in the pom.xml)

    <dependency>
      <groupId>com.google.http-client</groupId>
      <artifactId>google-http-client-apache-v2</artifactId>
      <version>1.35.0</version>
    </dependency>

Automate process of refreshing test fixture files

We should have an automated process that deals with refreshing the fixture files. Such a process should/could/would:

  • Download the fixtures from https://github.com/dnsimple/dnsimple-developer
  • Compare downloaded fixtures with present fixtures and provide a report with new, changed, removed, unknown (as in fixtures that have been created only in this repo) fixtures
  • Run the tests and report back if any test breaks due to changes on the fixtures
  • Stash all the changes, commit and even push them

Fix the error types

Current error types have a series of flaws:

  • The base class DnsimpleException it's a checked exception class, and it has a non-standard constructors scheme with args that suggest we would be providing some details about errors that ultimately we're not filling in when creating exception instances.
  • There's a specific ResourceNotFoundException class for HTTP 404s, but DnsimpleException is used otherwise, which makes it difficult to make sense of errors and their context.

Exceptions should be:

  • Unchecked
  • Follow the standard constructor guidelines from Throwable
  • Be as specific as possible

deleteZoneRecord throws exception even when call to API is successful

Using 0.6.0

While invoking com.dnsimple.Zones#deleteZoneRecord against the production API I keep getting an exception even when the underlying HTTP call returns a successful 204 response and the corresponding zone record is deleted (no longer visible in the dnsimple.com UI)

Within com.dnsimple.endpoints.http.HttpEndpointClient#parseResponse an exception is thrown as it attempts to parse JSON from the response body, however there is none present in this call (the API documentation notes it just returns a 204 when successful).

The exception thrown is: java.lang.IllegalArgumentException: no JSON input found

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.