DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Data Engineering
  3. Data
  4. How Simple a Todo Backend App Can Be

How Simple a Todo Backend App Can Be

Learn how to use one of the newer frameworks in the Todo-Backend project, and significantly decrease your lines of code while not skimping on the quality of your app.

Gelin Luo user avatar by
Gelin Luo
CORE ·
Feb. 28, 17 · Tutorial
Like (1)
Save
Tweet
Share
5.87K Views

Join the DZone community and get the full member experience.

Join For Free

The Todo-Backend project provides an arena to showcase backend tech stacks. It defines a simple web API in the form of a to-do list and users can create their own identical APIs using various tech stacks.

As for now, there are over 80 Todo-Backend projects implemented in a wide range of tech/framework combinations, including JVM (Java/Scala/Kotlin/Closure), C#/.Net, Ruby, Python, PHP, Golang, Haskell, and a lot more. On each language/platform, there are one or more implementations based on different framework/data persist solution combinations.

I am the author of ActFramework, and just finished the Act implementation of Todo-Backend. As ActFramework is designed to boost developer productivity and enable express functions in less code without sacrificing readability, I was curious to see how Act's implementation compared to other implementations in terms of expressiveness, or simply speaking, the line of code. I did my homework to get the LOC data from some commonly used tech stacks and compiled the result into the following table:

Language/Platform Implementation Data Persistent Line of Code
Java/JVM ActFramework MongoDB 64
Java/JVM Spring4 + Boot Java Set 200
Java/JVM vertx MongoDB 241
Java/JVM Dropwizard Java Map 115
Java/JVM Jooby Java Map 231
Java/JVM SparkFramework PostgreSQL 348
Kotlin/JVM Rapidoid Java Map 81
Closure/JVM Closure PostgreSql 142
Scala/JVM Scala/Play2.5 PostgreSql 136
Golang Gin Map in memory 128
Golang stdlib In memory data structure 238
JavaScript/NodeJs express PostgreSql 130
Python webpy Array in memory 32
Python django sqllite 164
Ruby rails PostgreSql 311
PHP symfony2 sqlite 130 
Haskell Snap Sqlite 98
C#/.Net Asp.Net Web API In memory list 215
C#/.Net Asp.Net core ? (Entity Framework) 887
Swift Kitura MongoDB 473


Obviously, Act's implementation is very concise in comparison to other implementations, as it uses only 64 lines of code. Consider that normal Java implementations take up to 200 lines of code and that Act in the Java language was implemented in Dropwizard and used a HashMap as a data persist, which nearly doubled the size of Act's codebase - and it still had only 64 lines of code!

How ActFramework Can Make it So Compact

This is a simple project consisting of a model and a service (AKA controller). We will check the source code of these components to understand Act's implementation.

1. The Model

We chose MongoDB as our data persistent store. Act provides awesome integration with MongoDB through the act-morphia plugin, which relies on the official Morphia object document mapper layer.

An innovative feature Act brings to developers on top of Morphia is called AdaptiveRecord  which allows the backend developer to declare only the fields needed to participate in backend logic. For any fields required by frontend and not used in a Java app, just ignore them. Thus here is our entity model class for Todo :

@Entity(value = "todo", noClassnameStored = true)
public class Todo extends MorphiaAdaptiveRecordWithLongId<Todo> {

    // needs to define this property to make it comply with todobackend spec
    // unless https://github.com/TodoBackend/todo-backend-js-spec/issues/6
    // is accepted
    public boolean completed;

    // url is required as per backend test spec. However it is not required
    // to put into the database. So we mark it as Transient property
    @Transient
    public String url;

    // We will generate the derived property `url` after
    // saving the model and loading the model
    @PostLoad
    @PostPersist
    private void updateUrl() {
        url = Act.app().router().fullUrl(S.concat("/todo/", getIdAsStr()));
    }
}

We don't need to declare all fields presented on the front end, e.g.  title , order  and completed, which is declared in the source code because of this issue in the test spec.

Note the  url  is not part of the data to persist into our data store, instead, it is a derived property that concatenates the GET action URL path and the entity's id. We rely on Morphia's PostLoad  and PostPersist  lifecycle callback method to init the property.

2. The Service

It is very unusual to get a service class nested into the entity model class like what we did in this implementation:

@Entity(value = "todo", noClassnameStored = true)
public class Todo extends MorphiaAdaptiveRecordWithLongId<Todo> {

    // needs to define this property to make it comply with todobackend spec
    // unless https://github.com/TodoBackend/todo-backend-js-spec/issues/6
    // is accepted
    public boolean completed;

    ....

    @Controller("/todo")
    @Produces(H.MediaType.JSON)
    public static class Service extends MorphiaDaoWithLongId<Todo> {

        @PostAction
        public Todo create(Todo todo, Router router) {
            return save(todo);
        }

        @GetAction("{id}")
        public Todo show(long id) {
            return findById(id);
        }
        ...
    }
}

However, in the TODO application, we think it is not a bad choice, because our TODO service only operates on a single resource type, i.e. the TODO item. Actually, it is encouraged in this case because:

  • The operation (service endpoint logic) and the data (entity model) sit together, meaning high cohesion in the app. The design mimics the Object Oriented Programming that encapsulates the data and the operation on the data into a single module.

  • It improves readability, as we don't need to switch between classes or even packages to find the data model when reading the service that manipulates the data.

Also, we can even take out the  @Produces(H.MediaType.JSON)  line if the test spec accepted and fixed this issue.

3. CORS Code

It is required by Todo-Backend that a showcase application must enable CORS. Thus we see code like:

Java 8 with Spring 4 Boot implementation

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    HttpServletResponse response = (HttpServletResponse) res;
    response.setHeader("Access-Control-Allow-Origin", "*");
    response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PATCH");
    response.setHeader("Access-Control-Max-Age", "3600");
    response.setHeader("Access-Control-Allow-Headers", "x-requested-with, origin, content-type, accept");
    chain.doFilter(req, res);
}

Or Java with Dropwizard implementation

private void addCorsHeader(Environment environment) {
    FilterRegistration.Dynamic filter = environment.servlets().addFilter("CORS", CrossOriginFilter.class);
    filter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
    filter.setInitParameter("allowedOrigins", "*");
    filter.setInitParameter("allowedMethods", "GET,PUT,POST,DELETE,OPTIONS,HEAD,PATCH");
}


However, we don't see any of these CORS relevant codes in the ActFramework implementation. The only thing we've done is added  cors=true  into the config file. This is another cool aspect of Act, it integrates utilities supporting common features in a web app including CORS, CSRF, etc.

In summary, ActFramework provides a flexible and powerful infrastructure that supports creating RESTful service in a much simpler way. With ActFramework, the developer just needs to focus on business logic, not plumbing.

app Implementation Data (computing) Java (programming language) Data structure

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Streamlining Your Workflow With the Jenkins HTTP Request Plugin: A Guide to Replacing CURL in Scripts
  • Automated Performance Testing With ArgoCD and Iter8
  • Load Balancing Pattern
  • RabbitMQ vs. Memphis.dev

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: