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. Databases
  4. API Execution Context

API Execution Context

The Immutable library generates an immutable implementation context with appropriate builders and getters.

Arun Lingala user avatar by
Arun Lingala
·
Apr. 19, 19 · Tutorial
Like (2)
Save
Tweet
Share
8.17K Views

Join the DZone community and get the full member experience.

Join For Free

What Is Required?

A POJO that composes parameters like user ID, user region, user locale, user location, API invocation ID, etc. that cuts across code layers while an API is being exercised.

Why Is It Required?

  • Any API business logic (BL) operation operates on resources pertaining to a user. User context is inevitable to enforce access control.
  • BL uses API invocation ID to augment logs so that logs pertaining to a API execution are traceable.
  • Many other such parameters might be required for all layers in the code depending on the service.

If one POJO can compose all such parameters, then the POJO can be passed as an argument to all methods instead passing each cross-cutting parameter as an argument. So, the signature of methods would be clean and lean and the POJO can be augmented with more cross-cutting parameters without changing the signature of methods.

How Is It Implemented?

Execution context is:

  • POJO composing cross-cutting parameters.

  • Immutable so that any layer in the service can not manipulate cross cutting parameters.

  • Only service layers like servlet filters can instantiate it with appropriate arguments.

Let's discuss different approaches and decide on one.

Telescoping Constructor Pattern

public final class Context {
 private String apiInvocationId;
 private String userId;
 private String authTicket;
 private String xyz;
 private String abc;

 // initially service needs only tid, realmId
 public Context(String apiInvocationId, String userId) {
  this.apiInvocationId = apiInvocationId;
  this.userId = userId;
 }

 // 3 months down the line, service needs auth ticket to make down stream
 // calls on API caller behalf
 public Context(String apiInvocationId, String userId, String authTicket) {
  this(apiInvocationId, userId);
  this.authTicket = authTicket;
 }

 // down the line need for some more parameters
 public Context(String apiInvocationId, String userId, String authTicket, String xyz, String abc) {
  this(apiInvocationId, userId, authTicket);
  this.xyz = xyz;
  this.abc = abc;
 }

 public String getApiInvocationId() {
  return apiInvocationId;
 }

 public String getUserId() {
  return userId;
 }

 public String getAuthTicket() {
  return authTicket;
 }

 public String getXyz() {
  return xyz;
 }

 public String getAbc() {
  return abc;
 }
}

Pros

  • Context is immutable

Cons

  • When there is a need to keep more parameters, either implement a new constructor that accepts new parameters, or enhance an existing constructor and change the code that instantiates old constructors.
  • If the service provides services using different protocols/authorization schemes, a few parameters may be optional. In this case, instantiation would look like new Context("apiInvocationId", "userId", null, "xyz", null), so it is hard to read/write code that instantiates.

Bottom Line

The pattern works but is hard to maintain.

JavaBeans Pattern

public final class Context {
 private String apiInvocationId;
 private String userId;
 private String authTicket;
 private String xyz;
 private String abc;
 public String getApiInvocationId() {
  return apiInvocationId;
 }
 public void setApiInvocationId(String apiInvocationId) {
  this.apiInvocationId = apiInvocationId;
 }
 public String getUserId() {
  return userId;
 }
 public void setUserId(String userId) {
  this.userId = userId;
 }
 public String getAuthTicket() {
  return authTicket;
 }
 public void setAuthTicket(String authTicket) {
  this.authTicket = authTicket;
 }
 public String getXyz() {
  return xyz;
 }
 public void setXyz(String xyz) {
  this.xyz = xyz;
 }
 public String getAbc() {
  return abc;
 }
 public void setAbc(String abc) {
  this.abc = abc;
 }



}

Pros

  • Solves cons of telescoping constructor pattern because it can be augmented with more setter/getter methods as and when required.

Cons

  • Context is not immutable.

Bottom Line

Violates all constraints in our implementation discussion due to cons.

Builder Pattern

public final class Context {

 private final String userId;
 private final String apiInvocationId;

 public static class Builder {
  private String userId = null;
  private String apiInvocationId = null;

  public Builder() {

  }

  public Builder realmId(String userId) {
   this.userId = userId;
   return this;
  }

  public Builder tid(String apiInvocationId) {
   this.apiInvocationId = apiInvocationId;
   return this;
  }

  public Context build() {
   return new Context(this);
  }

  // Add methods here, if there is need to capture more crosscutting parameters
 }

 private Context(Builder builder) {
  this.userId = builder.userId;
  this.apiInvocationId = builder.apiInvocationId;
  // put more parameters when there is need to to capture more
 }

 public String getUserId() {
  return userId;
 }

 public String getApiInvocationId() {
  return apiInvocationId;
 }

}

Pros

  • Solves cons of telescoping constructor pattern, as it can be augmented with more builder setter methods as and when required.
  • Solves cons of beans pattern also.
  • Context is immutable.
  • Instantiation code much cleaner to read/write with builder methods.

Conclusion

The builder pattern is the optimal pattern to implement execution context for any API in any service. Now, lets discuss how to implemet it using with very less code using the Immutables library.

import org.immutables.value.Value;

@Value.Immutable
@Value.Style(strictBuilder = true)
public interface Context {

    String getUserId();

    String getAPIInvocationId();

    String getAuthTicket();

    String getRegion();

  // keep adding more attributes as and when needed that is all
}

The Immutable library generates an immutable implementation context with appropriate builders and getters. All we need to do is add an attribute (single line) to the interface context as and when needed — that's all. 

API Execution (computing)

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Kotlin Is More Fun Than Java And This Is a Big Deal
  • Implementing Infinite Scroll in jOOQ
  • DevSecOps Benefits and Challenges
  • Hidden Classes in Java 15

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: