Friends of OpenJDK Today

How to Create a Spring Boot Application to Retrieve Data from Evernote

August 28, 2023

Author(s)

I recently started work on a joint project with my colleague, Jason Koo. For this project, we want to import data from second brain apps (such as Obsidian, Notion, Evernote, etc) to Neo4j.

Since I use Evernote, I was tasked with getting my notes out of Evernote.

In this article, I will show you how to use the Evernote API and SDK in a Spring Boot application to retrieve data from Evernote.

Starting steps

I knew nothing about what Evernote provided for developers, so I started by reading the Evernote for Developers documentation. Evernote does seem to have some user experience bugs. Searching for answers to my questions also surfaced user frustration with missing or unreliable features. In my experience so far, things have been ok for what I need. I feel that many data APIs do not provide the best developer experience in one way or another, so I wasn't surprised by this.

To start, I created an account on Evernote's development server in order to test the API. Unfortunately, there doesn't seem to be a way to import production-environment notes into the sandbox, so after I created a sandbox account, I manually copied/pasted the text from a few of my notes. Next, I needed to request an API key. This is just for the development environment, so you have to request a production version when testing is completed. Once your development API key request is approved, you get an API key that you can use to access the data. We also need to request a developer token to authenticate with the Evernote API.

Then, we need to utilize a provided SDK for our preferred language to call the API and retrieve the data. Since I am a Java developer, we will use the Java SDK in this article. The SDK is a Github project that includes a couple of code examples, which was a good start. I would need to make a few tweaks to the sample code, though.

First, I wanted to make use of the Maven dependency to access the functionality in the SDK. I also wanted to use Spring Boot instead of the vanilla Java code. Lastly, in a future piece of this project, I will want to use the Spring Data Neo4j library to import the data to Neo4j. Let’s start with bringing the code over to Spring Boot. The final code for this article is available in a Github repository.

Spring Boot application

The starting place for all of my Spring Boot applications is the Spring Initializr. I only changed a couple of description fields and didn’t add any dependencies yet, as I’ll only need one dependency added manually for now.

Spring

After downloading the project, I opened it in my IDE and added the Evernote dependency to the pom.xml file.

<dependency>
    <groupId>com.evernote</groupId>
    <artifactId>evernote-api</artifactId>
    <version>1.25.1</version>
</dependency>

Evernote’s Java SDK provides a couple of sample code classes, and the EDAMDemo one was pretty similar to what I was looking for. My initial approach for merging the sample Java code with Spring Boot was to copy/paste the entire EDAMDemo.java class into a new class file in the project folder, and then start tweaking broken imports and other issues. However, I quickly realized that this approach was extremely error-prone. Because of the large code blocks, I had trouble running the demo’s main method with Spring Boot’s main(). I also had issues passing the developer token around (should I put it in the Spring Boot main class or this demo class?). I needed to approach this with a different tactic.

After venting about it a bit to Mark Heckler, he reminded me to start super simple and build up. One example he gave was to move the developer token string to the properties file and just return that. So, I cleared out all the copied code and placed the developer token in the application.properties file as shown below.

AUTH_TOKEN=<your developer token here>

Next, I created a new class called EvernoteDemo annotated as a component and implemented the CommandLineRunner interface, so that this class will load on startup.

@Component
public class EvernoteDemo implements CommandLineRunner {
    @Value("${AUTH_TOKEN}")
    private String token;

    @Override
    public void run(String... args) throws Exception {
        System.out.println("Developer token: " + token);
    }
}

When you implement the CommandLineRunner interface, you need to implement the run() method. Once that outline was there, I added Spring’s @Value annotation outside the method to pull in the AUTH_TOKEN from the properties file into a variable token, so we can use it to access the API. Inside the run() method, I printed out the developer token to make sure it was being read from the properties file. I ran the application and saw the token string printed out in the console, so I knew I was on the right track.

Now I could slowly add in pieces of the sample code from the Github project.

Incorporate Evernote SDK Example Code

First, I copied in the main() method from the sample code to my EvernoteDemo class’s run() method.

@Override
public void run(String... args) throws Exception {
    if ("your developer token".equals(token)) {
        System.err.println("Please fill in your developer token");
        System.err
                .println("To get a developer token, go to https://sandbox.evernote.com/api/DeveloperToken.action");
        return;
    }

    EvernoteDemo demo = new EvernoteDemo(token);
    try {
        demo.listNotes();
    } catch (EDAMUserException e) {
        if (e.getErrorCode() == EDAMErrorCode.AUTH_EXPIRED) {
            System.err.println("Your authentication token is expired!");
        } else if (e.getErrorCode() == EDAMErrorCode.INVALID_AUTH) {
            System.err.println("Your authentication token is invalid!");
        } else if (e.getErrorCode() == EDAMErrorCode.QUOTA_REACHED) {
            System.err.println("Your authentication token is invalid!");
        } else {
            System.err.println("Error: " + e.getErrorCode().toString()
                    + " parameter: " + e.getParameter());
        }
    } catch (EDAMSystemException e) {
        System.err.println("System error: " + e.getErrorCode().toString());
    } catch (TTransportException t) {
        System.err.println("Networking error: " + t.getMessage());
    }
}

I removed the first few lines that pull the AUTH_TOKEN from the environment because our @Value annotation handles that now. I also removed some of the method calls in the try block because I still want to start small and build up. Then, the EDAMDemo object (before the try block) needed renamed to match our class name EvernoteDemo. After importing some of the classes referenced in the block, I still had some red-highlighted text. To fix that, I needed to copy over the EDAMDemo constructor and the listNotes() method.

public EvernoteDemo(String token) throws Exception {
    EvernoteAuth evernoteAuth = new EvernoteAuth(EvernoteService.SANDBOX, token);
    ClientFactory factory = new ClientFactory(evernoteAuth);
    userStore = factory.createUserStoreClient();

    boolean versionOk = userStore.checkVersion("Evernote EDAMDemo (Java)",
            com.evernote.edam.userstore.Constants.EDAM_VERSION_MAJOR,
            com.evernote.edam.userstore.Constants.EDAM_VERSION_MINOR);
    if (!versionOk) {
        System.err.println("Incompatible Evernote client protocol version");
        System.exit(1);
    }

    noteStore = factory.createNoteStoreClient();
}

The EDAMDemo constructor from the sample code became the EvernoteDemo constructor in our code. After some imports, almost everything worked except that the token parameter was underlined red with the message Could not autowire. No beans of 'String' type found.. Digging into this, I found that Spring looks for an empty constructor to use when autowiring. So, I added an empty constructor to the EvernoteDemo class, and that solved it!

public EvernoteDemo() {
}

The last piece of code to add is for the listNotes() method.

private void listNotes() throws Exception {
    System.out.println("Listing notes:");

    List<Notebook> notebooks = noteStore.listNotebooks();

    for (Notebook notebook : notebooks) {
      System.out.println("Notebook: " + notebook.getName());

      NoteFilter filter = new NoteFilter();
      filter.setNotebookGuid(notebook.getGuid());
      filter.setOrder(NoteSortOrder.CREATED.getValue());
      filter.setAscending(true);

      NoteList noteList = noteStore.findNotes(filter, 0, 100);
      List<Note> notes = noteList.getNotes();
      for (Note note : notes) {
        System.out.println(" * " + note.getTitle());
      }
    }
    System.out.println();
}

Once I fixed all the imports, all the red highlighting and errors went away. I ran the application and saw the following output:

Listing notes:
Notebook: First Notebook
 * Docker
 * Microservices Project Notes
 * Goodreads data cleaning for db load

The code is working! I’m able to connect to the Evernote API and list out the notes in my account. The next piece I want to work on is getting the note contents from the note so that I can work towards importing notes into Neo4j. That will be a topic for another article, though.

Wrap Up!

In this article, we took the vanilla Java code from the Evernote SDK and migrated it to a Spring Boot application. We saw how copying/pasting large amounts of code and working backwards to integrate it can sometimes be overwhelming and error-prone. Instead, creating a basic piece as a starting point, and then slowly adding in small pieces can work much better and hopefully lower frustration.

In a future article, we’ll work on getting the note contents from the Evernote API and customizing the application to retrieve exactly what we need. Until next time, happy coding!

Resources

Topics:

Related Articles

View All

Author(s)

Comments (0)

Your email address will not be published. Required fields are marked *

Highlight your code snippets using [code lang="language name"] shortcode. Just insert your code between opening and closing tag: [code lang="java"] code [/code]. Or specify another language.

Save my name, email, and website in this browser for the next time I comment.

Subscribe to foojay updates:

https://foojay.io/feed/
Copied to the clipboard