Best Practices for Designing, Securing and Scaling Java Backend APIs

This article explains how to design robust Java backend APIs, covering interface definition, request/response formats, error handling, token generation, digital signing, interceptor chains, rate limiting, HTTPS migration, and strategies for high concurrency and high availability such as load balancing, clustering and caching.

Top Architect
Top Architect
Top Architect
Best Practices for Designing, Securing and Scaling Java Backend APIs

The author, a senior architect, shares practical experience from building payment‑related services and outlines the essential steps for creating reliable backend APIs in Java.

What is an API? An API is a server endpoint that receives client parameters, processes business logic, and returns data in a defined format (usually JSON or XML).

Development considerations include defining request parameters in documentation, standardising response structures, and using a unified error‑code catalogue. Example response classes:

package com.caiex.vb.model;

import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Result", propOrder = {"resultCode", "resultMsg"})
public class Result implements Serializable {
    private static final long serialVersionUID = 10L;
    protected int resultCode;
    protected String resultMsg;
    public int getResultCode() { return this.resultCode; }
    public void setResultCode(int value) { this.resultCode = value; }
    public String getResultMsg() { return this.resultMsg; }
    public void setResultMsg(String value) { this.resultMsg = value; }
}

public class Response implements Serializable {
    private static final long serialVersionUID = 2360867989280235575L;
    private Result result;
    private Object data;
    public Result getResult() { if (this.result == null) { this.result = new Result(); } return result; }
    public void setResult(Result result) { this.result = result; }
    public Object getData() { return data; }
    public void setData(Object data) { this.data = data; }
}

Common error codes are defined as static constants, for example:

public static int NO_AGENT_RATE = 1119; // 未找到兑换率
public static int SCHEME_COMMIT_FAIL = 4000; // 方案提交失败
public static int SCHEME_CONFIRMATION = 4001; // 方案确认中
public static int SCHEME_NOT_EXIST = 4002; // 方案不存在
public static int SCHEME_CANCEL = 4005; // 方案取消

Unified exception handling is implemented with a @ControllerAdvice class that catches all exceptions and returns a standard Response with resultCode 9999 and message "系统繁忙".

@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    @ExceptionHandler(value = Exception.class)
    public Response allExceptionHandler(HttpServletRequest request, Exception exception) throws Exception {
        logger.error("拦截到异常:", exception);
        Response response = new Response();
        response.setData(null);
        response.getResult().setResultCode(9999);
        response.getResult().setResultMsg("系统繁忙");
        return response;
    }
}

The interceptor chain is configured in a WebMvcConfigurerAdapter subclass, registering validators for common parameters, authentication, rate limiting, and business‑specific checks.

@EnableWebMvc
@Configuration
public class WebAppConfigurer extends WebMvcConfigurerAdapter {
    @Bean public CommonValidator commonInterceptor() { return new CommonValidator(); }
    @Bean public DDSAuthValidator ddsAuthInterceptor() { return new DDSAuthValidator(); }
    @Bean public QueryPriceParamsValidator queryPriceParamsInterceptor() { return new QueryPriceParamsValidator(); }
    @Bean public TradeParamsValidator tradeParamsInterceptor() { return new TradeParamsValidator(); }
    @Bean public APILimitRateValidator aPILimitRateInterceptor() { return new APILimitRateValidator(); }
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(aPILimitRateInterceptor()).addPathPatterns("/*/*");
        registry.addInterceptor(ddsAuthInterceptor()).addPathPatterns("/tradeState/*", "/recycle/*", "/matchInfo/*", "/price/tradeTicketParam");
        registry.addInterceptor(commonInterceptor()).addPathPatterns("/price/tradeTicketParam", "/tradeState/*", "/recycle/*");
        registry.addInterceptor(queryPriceParamsInterceptor()).addPathPatterns("/price/getPriceParam");
        registry.addInterceptor(tradeParamsInterceptor()).addPathPatterns("/price/tradeTicketParam");
        super.addInterceptors(registry);
    }
}

Token creation and digital signing are used to protect API calls. A token is generated by concatenating a secret prefix, the current timestamp and a suffix, then applying MD5:

private String createToken() {
    String utk = "Msk!D*" + System.currentTimeMillis() + "UBR&FLP";
    logger.info("create token   --- " + Md5Util.md5(utk));
    return Md5Util.md5(utk);
}

Signature verification collects all non‑null parameters, sorts them, appends the private key retrieved from Redis, and compares the MD5 hash with the supplied sign value.

To handle high traffic, the article recommends three main techniques: load balancing (weight, ip_hash, least_conn, etc.), clustering (adding more service instances and scaling consumers), and caching (using ConcurrentHashMap or Redis with appropriate expiration). It also discusses rate limiting with Guava, HTTPS migration for data encryption, and ensuring idempotency with Redis SETNX.

Finally, the author summarises key points such as choosing pull vs push data flows, guaranteeing order uniqueness in distributed environments, and setting timeout policies for long‑running requests.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaBackend Developmenthigh availabilitySpring Bootapi-design
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.