当前位置:网站首页>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 :
image.png

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 .

原网站

版权声明
本文为[lwq2025]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202131533479037.html