当前位置:网站首页>Design and implementation of general interface open platform - (39) simple and crude implementation of API services
Design and implementation of general interface open platform - (39) simple and crude implementation of API services
2022-07-06 12:29:00 【lwq2025】
We are based on netty Component implements message service , Next , Let's start with API service
Let's review API Overall design of service .
API Services are the main part of the general interface platform , External exposure Restful Style data interface , Other application systems call API service , One side , You can query the business data within your permission , On the other hand , It can push the data generated by its own system to the interface platform .
API Services are divided into two parts: service technology framework and specific business function interface , The technical framework is responsible for unified scheduling 、 data validation 、 Identity Authentication 、 safety control 、 Logging and other responsibilities , The specific business function interface is responsible for the actual business interface function processing , The overall processing flow is shown in the figure below :
Based on the overall design , We can be simple and rough , use 1 individual controller To solve
/** * api service controller * * @author wqliu * @date 2021-8-19 13:56 **/
@RestController
@RequestMapping("/api")
@Slf4j
public class ApiRestController {
/** * Valid time */
private static final int VALID_TIME_SPAN = 10;
@Autowired
private ApiServiceService apiServiceService;
@Autowired
private ApiAppService apiAppService;
@Autowired
private ApiServicePermissionService apiServicePermissionService;
@Autowired
private ApiServiceLogService apiServiceLogService;
@PostMapping("/rest")
@AllowAll
public ResponseEntity<ApiResponse> post(@Validated @RequestBody ApiRequest apiRequest) {
// Record the time when the request was received
LocalDateTime receiveTime = LocalDateTime.now();
// Define return
ApiResponse apiResponse = new ApiResponse();
try {
// Validation data
//TODO: Convenient test , Temporarily cancel verification
// validateData(apiRequest);
// Distribution services
ServiceHandler handler = dispatchService(apiRequest);
// Business processing
String responseData = handler.handle(apiRequest.getData());
// Successful implementation
apiResponse.setData(responseData);
apiResponse.setExecuteResult(ApiServiceExecuteResultEnum.SUCCESS.name());
} catch (CustomException ex) {
// Custom exception handling
apiResponse.setExecuteResult(ApiServiceExecuteResultEnum.ERROR.name());
apiResponse.setErrorCode("S00");
apiResponse.setErrorMessage(ex.getMessage());
} catch (ApiException ex) {
// Custom exception handling
apiResponse.setExecuteResult(ApiServiceExecuteResultEnum.ERROR.name());
apiResponse.setErrorCode(ex.getErrorCode());
apiResponse.setErrorMessage(ex.getMessage());
} catch (Exception ex) {
// Unexpected exception handling
apiResponse.setExecuteResult(ApiServiceExecuteResultEnum.ERROR.name());
apiResponse.setErrorCode("S99");
apiResponse.setErrorMessage(" Undefined exception :" + ex.getMessage());
} finally {
// Record request response time
LocalDateTime responseTime = LocalDateTime.now();
// Log
recordLog(apiRequest, apiResponse, receiveTime, responseTime);
}
return new ResponseEntity<ApiResponse>(apiResponse, HttpStatus.OK);
}
/** * Log * * @param apiRequest * @param apiResponse * @param receiveTime */
private void recordLog(ApiRequest apiRequest, ApiResponse apiResponse, LocalDateTime receiveTime, LocalDateTime responseTime) {
ApiServiceLog apiServiceLog = new ApiServiceLog();
apiServiceLog.setAppCode(apiRequest.getAppCode());
apiServiceLog.setServiceCode(apiRequest.getServiceCode());
apiServiceLog.setRequestTime(DateUtils.toLocalDateTime(apiRequest.getRequestTime()));
apiServiceLog.setReceiveTime(receiveTime);
apiServiceLog.setRequestBusinessData(apiRequest.getData());
apiServiceLog.setExecuteResult(apiResponse.getExecuteResult());
apiServiceLog.setErrorCode(apiResponse.getErrorCode());
apiServiceLog.setErrorMessage(apiResponse.getErrorMessage());
apiServiceLog.setResponseTime(responseTime);
apiServiceLog.setResponseBusinessData(apiResponse.getData());
// Calculate execution time
apiServiceLog.setExecutionTime(Duration.between(receiveTime, responseTime).toMillis());
// preservation
apiServiceLogService.add(apiServiceLog);
}
/** * Service distribution according to service code * * @param apiRequest * @return */
private ServiceHandler dispatchService(ApiRequest apiRequest) {
String serviceCode = apiRequest.getServiceCode();
String handlerClass = apiServiceService.lambdaQuery().eq(ApiService::getCode, serviceCode)
.list().get(0).getHandler();
try {
ServiceHandler handler = (ServiceHandler) Class.forName(handlerClass).newInstance();
return handler;
} catch (Exception e) {
throw new ApiException("S60", " The processor corresponding to this service was not found ");
}
}
//region data validation
/** * data validation * * @param apiRequest */
private void validateData(ApiRequest apiRequest) {
// Verify parameters
validateParameter(apiRequest);
// Verify application
validateApp(apiRequest);
// The validation service
validateService(apiRequest);
// Verify permissions
validatePermission(apiRequest);
// Validation timeliness
validateTimeLimitation(apiRequest);
// Verify the signature
validateSign(apiRequest);
}
/** * Verify parameters * * @param apiRequest api request */
private void validateParameter(ApiRequest apiRequest) {
// Parameter validation
// Verify request time
String requestTime = apiRequest.getRequestTime();
Calendar validate = TimeValidator.getInstance().validate(requestTime, DateConstant.DATE_FORMAT_FULL);
if (validate == null) {
throw new ApiException("S01", " The request time format does not meet the requirements ");
}
}
/** * Verify application * * @param apiRequest api request */
private void validateApp(ApiRequest apiRequest) {
// Get application code
String appCode = apiRequest.getAppCode();
// verification
List<ApiApp> list = apiAppService.lambdaQuery().eq(ApiApp::getCode, appCode).list();
if (CollectionUtils.isEmpty(list)) {
throw new ApiException("S10", " Application code does not exist ");
}
if (list.get(0).getStatus().equals(StatusEnum.DEAD.name())) {
throw new ApiException("S11", " App disabled ");
}
}
/** * The validation service * * @param apiRequest api request */
private void validateService(ApiRequest apiRequest) {
// Get the service code
String serviceCode = apiRequest.getServiceCode();
// verification
List<ApiService> list = apiServiceService.lambdaQuery().eq(ApiService::getCode, serviceCode).list();
if (CollectionUtils.isEmpty(list)) {
throw new ApiException("S20", " Service does not exist ");
}
if (list.get(0).getStatus().equals(StatusEnum.DEAD.name())) {
throw new ApiException("S21", " Service disabled ");
}
}
/** * Verify permissions * * @param apiRequest api request */
private void validatePermission(ApiRequest apiRequest) {
// Get app ID
String appCode = apiRequest.getAppCode();
String appId = apiAppService.lambdaQuery().eq(ApiApp::getCode, appCode).list().get(0).getId();
// Get service ID
String serviceCode = apiRequest.getServiceCode();
String serviceId = apiServiceService.lambdaQuery().eq(ApiService::getCode, serviceCode).list().get(0).getId();
// verification
List<ApiServicePermission> list = apiServicePermissionService.lambdaQuery()
.eq(ApiServicePermission::getAppId, appId)
.eq(ApiServicePermission::getServiceId, serviceId)
.list();
if (CollectionUtils.isEmpty(list)) {
throw new ApiException("S30", " No authority ");
}
}
/** * Validation timeliness * * @param apiRequest api request */
private void validateTimeLimitation(ApiRequest apiRequest) {
// Get request time
String requestTimeString = apiRequest.getRequestTime();
// Convert time format
LocalDateTime requestTime = DateUtils.toLocalDateTime(requestTimeString);
// Get the current time
LocalDateTime now = LocalDateTime.now();
// Get the time difference
Duration duration = Duration.between(requestTime, now);
if (Math.abs(duration.toMinutes()) > VALID_TIME_SPAN) {
throw new ApiException("S40", " The request time is beyond a reasonable range ");
}
}
/** * Verify the signature * * @param apiRequest api request */
private void validateSign(ApiRequest apiRequest) {
// Parameters enter map, And automatically sort
TreeMap<String, String> requestDataMap = new TreeMap<>();
requestDataMap.put("appCode", apiRequest.getAppCode());
requestDataMap.put("data", apiRequest.getData());
requestDataMap.put("requestTime", apiRequest.getRequestTime());
requestDataMap.put("serviceCode", apiRequest.getServiceCode());
requestDataMap.put("signMethod", apiRequest.getSignMethod());
// To get the key
String appSecret = apiAppService.lambdaQuery().eq(ApiApp::getCode, apiRequest.getAppCode()).list().get(0).getSecret();
// Assemble parameters and keys
StringBuffer sb = new StringBuffer();
sb.append(appSecret);
Iterator<String> iterator = requestDataMap.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
sb.append(key).append("=").append(requestDataMap.get(key));
}
sb.append(appSecret);
String param = sb.toString();
// To sign
String sign = DigestUtils.md5Hex(param);
log.info(" Signature :{}", sign);
// Signature comparison
if (!sign.equals(apiRequest.getSign())) {
throw new ApiException("S50", " Signature verification failed ");
}
}
//endregion
}
Although the function can be realized , But the disadvantages are obvious , This class is close to 300 That's ok , It contains a lot of business logic , Flexibility and scalability are obviously a weakness , Can we learn from netty Excellent design ideas , Adopt the design mode of responsibility chain , To realize the flexible assembly and data processing of the interface processor ?
Next, we will carry out such transformation .
边栏推荐
- [Offer29] 排序的循环链表
- PT OSC deadlock analysis
- JS变量类型以及常用类型转换
- Vscode basic configuration
- (1) Introduction Guide to R language - the first step of data analysis
- [Offer18]删除链表的节点
- Esp8266 connects to bafayun (TCP maker cloud) through Arduino IED
- JS variable types and common type conversions
- [esp32 learning-2] esp32 address mapping
- 基于Redis的分布式ID生成器
猜你喜欢
Esp8266 connect onenet (old mqtt mode)
Redis based distributed locks and ultra detailed improvement ideas
Fashion-Gen: The Generative Fashion Dataset and Challenge 论文解读&数据集介绍
(3) Introduction to bioinformatics of R language - function, data Frame, simple DNA reading and analysis
Esp8266 uses Arduino to connect Alibaba cloud Internet of things
Cannot change version of project facet Dynamic Web Module to 2.3.
Classification, understanding and application of common methods of JS array
SVN更新后不出现红色感叹号
First use of dosbox
(三)R语言的生物信息学入门——Function, data.frame, 简单DNA读取与分析
随机推荐
程序员老鸟都会搞错的问题 C语言基础 指针和数组
dosbox第一次使用
map文件粗略分析
JS数组常用方法的分类、理解和运用
Important methods of array and string
Redis based distributed ID generator
基于Redis的分布式ID生成器
Expected value (EV)
Kaggle competition two Sigma connect: rental listing inquiries (xgboost)
The dolphin scheduler remotely executes shell scripts through the expect command
Whistle+switchyomega configure web proxy
MySQL時間、時區、自動填充0的問題
程序设计大作业:教务管理系统(C语言)
Get the position of the nth occurrence of the string
Cannot change version of project facet Dynamic Web Module to 2.3.
idea中导包方法
(五)R语言入门生物信息学——ORF和序列分析
AMBA、AHB、APB、AXI的理解
[leetcode19] delete the penultimate node in the linked list
JS function promotion and declaration promotion of VaR variable