Skip to content

Commit

Permalink
[ISSUE apache#4494] RESTful API framework for EventMeshAdmin (apache#…
Browse files Browse the repository at this point in the history
…4498)

* restful response optimize part1

* restful response optimize part2

* restful response optimize part3

* restful response optimize part4

* exception handling

* exception handling part2

* exception handling part3

* exception handling part4

* exception handling part5

* add error type to error displaying

* warp json message response instead of string
  • Loading branch information
Pil0tXia authored Oct 20, 2023
1 parent 1b3e496 commit 62935c4
Show file tree
Hide file tree
Showing 16 changed files with 516 additions and 130 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
* limitations under the License.
*/

package org.apache.eventmesh.admin.config;
package org.apache.eventmesh.admin.common;

public class Constants {
public class ConfigConst {

// config
// yml config
public static final String ADMIN_PROPS_PREFIX = "eventmesh";
public static final String META_TYPE_NACOS = "nacos";
public static final String META_TYPE_ETCD = "etcd";
Expand All @@ -28,7 +28,10 @@ public class Constants {
public static final String HTTP_PREFIX = "http://";
public static final String HTTPS_PREFIX = "https://";

// Nacos
public static final String NACOS_LOGIN_API = "/nacos/v1/auth/login";
public static final String NACOS_CONFIGS_API = "/nacos/v1/cs/configs";
// common
/**
* colon with space
*/
public static final String COLON = ": ";

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.eventmesh.admin.common;

public class NacosConst {

public static final String LOGIN_API = "/nacos/v1/auth/login";

public static final String LOGIN_REQ_USERNAME = "username";
public static final String LOGIN_REQ_PASSWORD = "password";

public static final String LOGIN_RESP_TOKEN = "accessToken";

public static final String CONFIGS_API = "/nacos/v1/cs/configs";

public static final String CONFIGS_REQ_PAGE = "pageNo";
public static final String CONFIGS_REQ_PAGE_SIZE = "pageSize";
public static final String CONFIGS_REQ_DATAID = "dataId";
public static final String CONFIGS_REQ_GROUP = "group";
public static final String CONFIGS_REQ_SEARCH = "search";
public static final String CONFIGS_REQ_TOKEN = "accessToken";

public static final String CONFIGS_RESP_CONTENT_LIST = "pageItems"; // json page data list field
public static final String CONFIGS_RESP_CONTENT = "content"; // json page data field
public static final String CONFIGS_RESP_PAGES = "pagesAvailable"; // json total pages field
public static final String CONFIGS_RESP_DATAID = "dataId";
public static final String CONFIGS_RESP_GROUP = "group";
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@

package org.apache.eventmesh.admin.config;

import org.apache.eventmesh.admin.common.ConfigConst;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import lombok.Data;

@Data
@Component
@ConfigurationProperties(prefix = Constants.ADMIN_PROPS_PREFIX)
@ConfigurationProperties(prefix = ConfigConst.ADMIN_PROPS_PREFIX)
public class AdminProperties {

private MetaProperties meta = new MetaProperties();
Expand All @@ -34,7 +36,7 @@ public class AdminProperties {
@Data
public static class MetaProperties {

private String type = Constants.META_TYPE_NACOS;
private String type = ConfigConst.META_TYPE_NACOS;

private NacosProperties nacos = new NacosProperties();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@

package org.apache.eventmesh.admin.config;

import static org.apache.eventmesh.admin.config.Constants.META_TYPE_ETCD;
import static org.apache.eventmesh.admin.config.Constants.META_TYPE_NACOS;
import static org.apache.eventmesh.admin.common.ConfigConst.META_TYPE_ETCD;
import static org.apache.eventmesh.admin.common.ConfigConst.META_TYPE_NACOS;

import org.apache.eventmesh.admin.service.ConnectionService;
import org.apache.eventmesh.admin.service.SubscriptionService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@

package org.apache.eventmesh.admin.controller;

import org.apache.eventmesh.admin.dto.SubscriptionResponse;
import org.apache.eventmesh.admin.exception.EventMeshAdminException;
import org.apache.eventmesh.admin.dto.Result;
import org.apache.eventmesh.admin.model.SubscriptionInfo;
import org.apache.eventmesh.admin.service.SubscriptionService;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
Expand All @@ -50,12 +50,8 @@ public class SubscriptionController {
* @return config content
*/
@GetMapping("/subscription")
public ResponseEntity<String> retrieveSubscription(@RequestParam("dataId") String dataId, @RequestParam("group") String group) {
try {
return ResponseEntity.ok(subscriptionService.retrieveConfig(dataId, group));
} catch (EventMeshAdminException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
}
public Result<String> retrieveSubscription(@RequestParam("dataId") String dataId, @RequestParam("group") String group) {
return Result.success(subscriptionService.retrieveConfig(dataId, group));
}

/**
Expand All @@ -68,16 +64,12 @@ public ResponseEntity<String> retrieveSubscription(@RequestParam("dataId") Strin
* @return config properties and base64 encoded config content
*/
@GetMapping("/subscriptions")
public ResponseEntity<SubscriptionResponse> listSubscriptions(
public Result<List<SubscriptionInfo>> listSubscriptions(
@RequestParam(name = "page", defaultValue = "1") Integer page,
@RequestParam(name = "size", defaultValue = "10") Integer size,
@RequestParam(name = "dataId", defaultValue = CLIENT_DATA_ID_PATTERN) String dataId,
@RequestParam(name = "group", defaultValue = "") String group) {
try {
return ResponseEntity.ok(subscriptionService.retrieveConfigs(page, size, dataId, group));
} catch (EventMeshAdminException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new SubscriptionResponse(e.getMessage()));
}
return Result.success(subscriptionService.retrieveConfigs(page, size, dataId, group));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.eventmesh.admin.dto;

import static org.apache.eventmesh.admin.enums.Errors.SUCCESS;

import org.apache.eventmesh.admin.enums.Errors;
import org.apache.eventmesh.admin.exception.BaseException;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* A RESTful response DTO.
*/

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {

private T data;

private Integer pages;

private Message message;

public Result(Message message) {
this.message = message;
}

public Result(T data, Integer pages) {
this.data = data;
this.pages = pages;
}

/**
* The request is valid and the result is wrapped in {@link Result}.
*/
public static <T> Result<T> success() {
return new Result<>(new Message(SUCCESS));
}

public static <T> Result<T> success(Result<T> result) {
result.setMessage(new Message(SUCCESS));
return result;
}

public static <T> Result<T> success(T data) {
return new Result<>(data, null, new Message(SUCCESS));
}

/**
* The request is valid and the result is returned in {@link ResponseEntity}.
* Logic issues should use 422 Unprocessable Entity instead of 200 OK.
*/
public static <T> ResponseEntity<Result<T>> ok() {
return ResponseEntity.ok(new Result<>(new Message(SUCCESS)));
}

public static <T> ResponseEntity<Result<T>> ok(Result<T> result) {
result.setMessage(new Message(SUCCESS));
return ResponseEntity.ok(result);
}

/**
* The request is invalid.
*/
public static <T> ResponseEntity<Result<T>> badRequest(String message) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new Result<>(new Message(message)));
}

/**
* The request is valid but cannot be processed due to business logic issues.
*/
public static <T> ResponseEntity<Result<T>> unprocessable(String message) {
return ResponseEntity.status(HttpStatus.UNPROCESSABLE_ENTITY).body(new Result<>(new Message(message)));
}

/**
* Uncaught exception happened in EventMeshAdmin application.
*/
public static <T> ResponseEntity<Result<T>> internalError(String message) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new Result<>(new Message(message)));
}

/**
* Upstream service unavailable such as Meta.
*/
public static <T> ResponseEntity<Result<T>> badGateway(String message) {
return ResponseEntity.status(HttpStatus.BAD_GATEWAY).body(new Result<>(new Message(message)));
}

@Data
public static class Message {

private String name;

private String type;

private String desc;

public Message(BaseException e) {
this.name = e.getErrors().name();
this.type = e.getErrors().getType().name();
this.desc = e.getMessage();
}

/**
* Only recommended for returning successful results,
* the stack trace cannot be displayed when returning unsuccessful results.
*/
public Message(Errors errors) {
this.name = errors.name();
this.type = errors.getType().name();
this.desc = errors.getDesc(); // no stack trace
}

public Message(String desc) {
this.desc = desc;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.eventmesh.admin.enums;

import static org.apache.eventmesh.admin.common.ConfigConst.COLON;

import org.springframework.http.HttpStatus;

import lombok.Getter;

/**
* An enumeration class that conforms to the RESTful specifications and custom error reporting requirements.
* <ul>
* <li>The 'code' field is used to return the HTTP status code using {@link HttpStatus}.</li>
* <li>The 'type' field represents the major category of the error.</li>
* <li>the 'desc' field represents the detailed subcategory and information of the error.</li>
* </ul>
*/

@Getter
public enum Errors {

SUCCESS(HttpStatus.OK, Types.SUCCESS, "Operation success."),

NACOS_SDK_CONFIG_ERR(HttpStatus.INTERNAL_SERVER_ERROR, Types.SDK_CONFIG_ERR,
"Failed to create Nacos ConfigService. Please check EventMeshAdmin application configuration."),

NACOS_GET_CONFIGS_ERR(HttpStatus.BAD_GATEWAY, Types.META_COM_ERR, "Failed to retrieve Nacos config(s)."),

NACOS_EMPTY_RESP_ERR(HttpStatus.BAD_GATEWAY, Types.META_COM_ERR, "No result returned by Nacos. Please check Nacos."),

NACOS_LOGIN_ERR(HttpStatus.UNAUTHORIZED, Types.META_COM_ERR, "Nacos login failed."),

NACOS_LOGIN_EMPTY_RESP_ERR(HttpStatus.BAD_GATEWAY, Types.META_COM_ERR, "Nacos didn't return accessToken. Please check Nacos status."),
;

// error code
private final HttpStatus code;

// error type
private final Types type;

// error message
private final String desc;

Errors(HttpStatus code, Types type, String desc) {
this.code = code;
this.type = type;
this.desc = desc;
}

@Override
public String toString() {
return name() + " of " + type + COLON + desc;
}

@Getter
public enum Types {

SUCCESS("Successfully received and processed"),

SDK_CONFIG_ERR("The Meta SDK config in EventMeshAdmin application.yml error"),

META_COM_ERR("Network communication to Meta error"),
;

/**
* Helpful for understanding and not used for now
*/
private final String desc;

Types(String desc) {
this.desc = desc;
}
}
}
Loading

0 comments on commit 62935c4

Please sign in to comment.