loading...

Create light weight api server using Spark Java [3]

silentsudo profile image Ashish Agre ・3 min read

Hi everyone,

Continuing from previous section https://dev.to/silentsudo/create-light-weight-api-server-using-spark-java-2

We are done setting up our urls, now lets create our routers using Spark Java, we will join router-service-db in following sequence

  • Database
  • Service
  • Router

Lets see database:
As discussed we will create light weight in-memory database using collections framework.
There will a database class and respective table, we can call them datastores of specific type like User, Tweet, Like.

Below is our database and datastores classes.
AppDatabase.java

package in.silentsudo.blabber.database;

public final class AppDatabase {
    private static AppDatabase ourInstance = new AppDatabase();

    public static AppDatabase getInstance() {
        return ourInstance;
    }

    private UsersStore usersStore;
    private TweetsStore tweetsStore;
    private LikesStore likesStore;

    private AppDatabase() {
        usersStore = new UsersStore();
        tweetsStore = new TweetsStore();
        likesStore = new LikesStore();
    }

    public UsersStore getUsersStore() {
        return usersStore;
    }

    public TweetsStore getTweetsStore() {
        return tweetsStore;
    }

    public LikesStore getLikesStore() {
        return likesStore;
    }
}

Datastores classes below:

UsersStore.java

package in.silentsudo.blabber.database;

import in.silentsudo.blabber.models.User;

import java.util.LinkedList;
import java.util.List;

public final class UsersStore {

    private List<User> users = new LinkedList<>();

    UsersStore() {
        //Alert, always use some encryption while storing ans distributing password
        //This is dummy data
        users.add(new User("ashish@ashish.com", "qwerty"));
    }

    public User findUser(final User user) {
        return this.users.stream()
                .filter(u ->
                        u.getEmail().equalsIgnoreCase(user.getEmail()) &&
                                u.getPassword().equalsIgnoreCase(user.getPassword())
                )
                .findFirst()
                .orElse(null);
    }
}

TweetsStore

package in.silentsudo.blabber.database;

import in.silentsudo.blabber.models.Tweet;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

public final class TweetsStore {

    private List<Tweet> tweets = new LinkedList<>();

    TweetsStore() {
    }


    public void addTweet(Tweet tweet) {
        tweets.add(tweet);
    }

    public List<Tweet> getAllTweets() {
        return Collections.unmodifiableList(this.tweets);
    }

    public void deleteTweet(Tweet tweet) {
        if (this.tweets.contains(tweet)) {
            this.tweets.remove(tweet);
        }
    }
}

and finally LikesStore

package in.silentsudo.blabber.database;

import in.silentsudo.blabber.models.Like;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

public final class LikesStore {
    private static final Logger logger = Logger.getLogger(LikesStore.class.getSimpleName());
    private List<Like> likes = new LinkedList<>();

    LikesStore() {
        logger.setLevel(Level.ALL);
    }

    public void addLike(Like like) {
        if (like.getTweetId() == null || like.getUserId() == null) {
            logger.warning("Invalid like details");
            return;
        }
        likes.add(like);
    }

    public void delete(Like like) {
        if (likes.contains(like)) {
            likes.remove(like);
        }
    }

    public List<Like> getAll(Long tweetId) {

        return Collections.unmodifiableList(
                this.likes.stream()
                        .filter(like -> like.getTweetId().equals(tweetId))
                        .collect(Collectors.toList())
        );
    }
}

Core functionality of UsersStores is find user if exists and then return result to service classes which then inreturn result to router and finally to client.

Next we will see how service are calling this db and operating on them:
I will give example of only TweetsService as of now(entire projects source code can be found on this link)

There are certain db operation which we are going to do on Tweet and Like data and they seems common, so we will separate out this contract in an interface and for better redability let service classes implement them and operate.

Here is AbstractService.java

package in.silentsudo.blabber.services;

import java.util.List;

public interface AbstractService<E> {
    Object add(E e);

    void delete(E e);

    List<E> getAll();

    List<E> getAll(Long id);

}

And TweetsService.java is the implementor of this interface and provide its own implementation.

package in.silentsudo.blabber.services;

import in.silentsudo.blabber.database.TweetsStore;
import in.silentsudo.blabber.models.Tweet;

import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public final class TweetsService implements AbstractService<Tweet> {
    private static final Logger logger = Logger.getLogger(TweetsService.class.getSimpleName());

    private final TweetsStore tweetsStore;

    public TweetsService(TweetsStore tweetsStore) {
        this.tweetsStore = tweetsStore;
        logger.setLevel(Level.ALL);
    }

    @Override
    public Object add(Tweet tweet) {
        if (tweet != null && tweet.getId() != null &&
                tweet.getUserId() != null && tweet.getContent() != null) {
            tweetsStore.addTweet(tweet);
            logger.info("added");
            return new Object();
        } else {
            logger.info("Few values are null");
            return null;
        }
    }

    @Override
    public void delete(Tweet tweet) {
        tweetsStore.deleteTweet(tweet);
    }

    @Override
    public List<Tweet> getAll() {
        return tweetsStore.getAllTweets();
    }

    @Override
    public List<Tweet> getAll(Long id) {
        return tweetsStore.getAllTweets();
    }
}

Our services and database are ready to use with router, in the next section we will see how to connect all these pieces together and produce api response.

Thank you for reading!

Discussion

pic
Editor guide