当前位置:网站首页>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 .
边栏推荐
- ES6 grammar summary -- Part 2 (advanced part es6~es11)
- Vscode basic configuration
- Redis 缓存更新策略,缓存穿透、雪崩、击穿问题
- [Offer18]删除链表的节点
- ES6 grammar summary -- Part I (basic)
- Basic operations of databases and tables ----- modifying data tables
- Common properties of location
- ESP学习问题记录
- Intermediate use tutorial of postman [environment variables, test scripts, assertions, interface documents, etc.]
- . elf . map . list . Hex file
猜你喜欢

MySQL takes up too much memory solution

JS function promotion and declaration promotion of VaR variable

ESP8266连接onenet(旧版MQTT方式)

Kaggle competition two Sigma connect: rental listing inquiries (xgboost)

Arm pc=pc+8 is the most understandable explanation

JS正则表达式基础知识学习

First use of dosbox

Remember an experience of ECS being blown up by passwords - closing a small black house, changing passwords, and changing ports

Stm32f1+bc20+mqtt+freertos system is connected to Alibaba cloud to transmit temperature and humidity and control LED lights

(四)R语言的数据可视化——矩阵图、柱状图、饼图、散点图与线性回归、带状图
随机推荐
(四)R语言的数据可视化——矩阵图、柱状图、饼图、散点图与线性回归、带状图
Redis cache update strategy, cache penetration, avalanche, breakdown problems
How to add music playback function to Arduino project
MySQL占用内存过大解决方案
Servlet
Arm pc=pc+8 is the most understandable explanation
PT OSC deadlock analysis
idea中好用的快捷键
Rough analysis of map file
Redis 缓存更新策略,缓存穿透、雪崩、击穿问题
Programmers can make mistakes. Basic pointers and arrays of C language
(1) Introduction Guide to R language - the first step of data analysis
HCIP Day 12
Symbolic representation of functions in deep learning papers
Walk into WPF's drawing Bing Dwen Dwen
JS變量類型以及常用類型轉換
ESP学习问题记录
(5) Introduction to R language bioinformatics -- ORF and sequence analysis
Esp8266 connects to onenet cloud platform (mqtt) through Arduino IDE
Amba, ahb, APB, Axi Understanding