如何从包含 url 的文件自动生成 REST 端点?

问题描述 投票:0回答:3

我有一个文件,其中包含必须在 REST API 上公开的 URL。所有 URL 都代表不同的资源,必须单独记录它们。该文件包含数百个 URL,例如:

/p1
/p1/p2
/p1/p2/p3
/t1
/t1/t2
/t1/t2/t3

我想自动/以编程方式生成 REST 端点,以便我能够调用:

GET on https://host/p1/
GET on https://host/p1/p2
GET on https://host/p1/p3

... and so on ...

处理请求背后的逻辑对于每个路径都是相似的,因此 /p1、/p1/p2、/t1 等可以由接收整个路径的单个函数来处理。为了处理请求,我有一个这样的函数:

function handleRequest(url) {
    // this function should be called for every GET request on any of those endpoints
    // perform the business logic here 
}

数据存储在树形数据结构中,因此获取树中的路径并返回路径指向的节点下的数据是有意义的。然而,所有这些路径都是单独的资源。

我正在用Java编写代码,但目前语言并不重要。我会在 Spring 中生成一个 REST 端点,如下所示:

    @RequestMapping(
        path = "/t1",
        method = RequestMethod.GET,
        produces = MediaType.APPLICATION_JSON_VALUE,
        consumes = MediaType.APPLICATION_JSON_VALUE,
        headers = "Accept=application/json"
    )
    public ResponseEntity getT1() {
       // handle request here
    }

但是,由于必须通过API公开的资源数量非常多,当处理请求的逻辑相同时,像上面这样的函数要编写数百次或数千次是极其困难的。

我发现的一个解决方案是使用PathPatterns。这需要有一个像“/commonPath/**”这样的 url 的 RequestMapping。该解决方案的缺点是我无法通过 Swagger 自动为 API 生成文档,因为只有一个入口点。

如何自动生成所有这些端点?

编辑

文档基本上可以归结为有一种自动方式告诉用户可以调用哪些可用端点。我不想手动编写/维护它,因为 URL 的数量非常多。使用 Swagger,这非常简单。只需注释端点,就会为 API 的客户端自动生成用户界面。

java spring swagger documentation
3个回答
3
投票

我希望了解有关您的情况的更多详细信息,但根据目前给定的信息,以下是可能的选项。

解决方案1:如果您的输入文件是静态的,并且您需要基于静态输入文件公开API,那么此解决方案可能会很有效。只需编写一个程序即可根据该文件生成控制器类。

@RestController
public class MyMultiPathApiController {

    @AutoWired
    private RestApiHandlerService restApiHandlerService

    @RequestMapping(
  value = { "/p1", "/p1/p2", "/p1/p2/p3" }, 
  method = GET)
    public ResponseEntity<?> myMultiRestApi() {
        return restApiHandlerService.handleApiLogic();
    }
}

请求映射也接受正则表达式。根据您给出的示例,您也可以想出正则表达式。

解决方案2(推荐解决方案):

如果您的文件预计会更改并且您想动态公开 API,那么您需要调整 spring 框架的

RequestMappingHandlerMapping
类。扩展类
RequestMappingHandlerMapping
并编写你想要编写的逻辑。您可以在应用程序启动时读取该文件并将其缓存。您可以参考一些编写自定义 RequestMappingHandlerMapping 类的示例here

我相信这些信息很有帮助。如果您有任何后续问题,请告诉我。


0
投票

我将使用 java 注释处理器以及像 mustache 这样的模板框架或像 javapoet

这样的 java 代码发射器来生成 spring 控制器

0
投票

感谢@Lokesh 的回答。不幸的是,我无法完全理解 RequestMappingHandlerMapping 并构建一个完整的工作示例。答案与评论中@Andrew S的建议类似。

我构建了一个类,它通过 2 个模板文件为所有路径生成代码,并将生成的 java 类保存在项目中。

我创建了一个类模板,它只是一个文本文件:

package a.b.c.d;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@Api (description = "Resource controller")
@RestController
@RequestMapping (path = "REQUEST_MAPPING_BASE_PATH")
public class Resources {
  REQUEST_METHODS
}

然后我创建了一个方法模板,它也是一个文本文件:

@RequestMapping (
  path = "REQUEST_MAPPING_PATH",
  method = RequestMethod.REQUEST_HTTP_METHOD,
  produces = MediaType.ALL_VALUE,
  consumes = MediaType.ALL_VALUE,
  headers = "Accept=application/json"
)
@ApiOperation (
  value = "REQUEST_METHOD_DESCRIPTION",
  response = ResponseEntity.class
)
public ResponseEntity REQUEST_METHOD_NAME (HttpServletRequest request) {
  String path = request.getRequestURI();
  return new GraphResourceHandler(path).execute();
}

GraphResourceHandler 是执行每个路径逻辑的类:

public class GraphResourceHandler {
    private final String path;

    public GraphResourceHandler(String path) {
        this.path = path;
    }

    public ResponseEntity execute() {
        //TODO implement logic
    }

    public String getPath() {
        return path;
    }
}

生成包含所有资源的 .java 文件就很简单了。我只会提供伪代码:

class GenerateResources {

    public static void main(String[] args) {
        readFileContainingPaths();
        
        // holds method definitions as string
        String methods = "";

        foreach(resource in paths) {
            //simply perform string replacement for variables in method template
            // eg. replace REQUEST_METHOD_NAME with a custom name
            methods += generateMethodFromResource(resource);
        }
        
        // replace REQUEST_METHODS variable to the contents of 'methods' variable
        addResourceMethodsToClassTemplate()
        writeResultingStringClassToJavaFile()
     }
}

编译项目即可。当然,每当您向文件添加新值时,必须重新运行此类,但我认为它可以进一步自动化。好处是我不用写几千行代码,而且 Swagger 知道如何自动生成资源。

© www.soinside.com 2019 - 2024. All rights reserved.