diff --git a/docs/en/latest/plugins/body-transformer.md b/docs/en/latest/plugins/body-transformer.md index dc1b78632746..fb1b7f0bcdbd 100644 --- a/docs/en/latest/plugins/body-transformer.md +++ b/docs/en/latest/plugins/body-transformer.md @@ -6,7 +6,7 @@ keywords: - Plugin - BODY TRANSFORMER - body-transformer -description: This document contains information about the Apache APISIX body-transformer Plugin. +description: The body-transformer plugin performs template-based transformations to transform the request and/or response bodies from one format to another, for example, from JSON to JSON, JSON to HTML, or XML to YAML. --- -## Description - -This plugin is used to transform the request and/or response body from one -format to another format, e.g. JSON to XML. + + + -Use cases: +## Description -- simple SOAP proxy -- generic template-based transform, e.g. JSON to JSON, JSON to HTML, XML to YAML +The `body-transformer` plugin performs template-based transformations to transform the request and/or response bodies from one format to another, for example, from JSON to JSON, JSON to HTML, or XML to YAML. ## Attributes -| Name | Type | Required | Description | -| ----------- | ----------- | ----------- | ----------- | -| `request` | object | False | request body transformation configuration | -| `request.input_format` | string | False | request body original format, if not specified, it would be determined from `Content-Type` header. | -| `request.template` | string | True | request body transformation template | -| `request.template_is_base64` | boolean | False | Set to true if the template is base64 encoded | -| `response` | object | False | response body transformation configuration | -| `response.input_format` | string | False | response body original format, if not specified, it would be determined from `Content-Type` header. | -| `response.template` | string | True | response body transformation template | -| `response.template_is_base64` | boolean | False | Set to true if the template is base64 encoded | +| Name | Type | Required | Default | Valid values | Description | +| ------------- | ------- | -------- | ------- | ------------ | ------------------------------------------ | +| `request` | object | False | | | Request body transformation configuration. | +| `request.input_format` | string | False | | [`xml`,`json`,`encoded`,`args`,`plain`,`multipart`] | Request body original media type. If unspecified, the value would be determined by the `Content-Type` header to apply the corresponding decoder. The `xml` option corresponds to `text/xml` media type. The `json` option corresponds to `application/json` media type. The `encoded` option corresponds to `application/x-www-form-urlencoded` media type. The `args` option corresponds to GET requests. The `plain` option corresponds to `text/plain` media type. The `multipart` option corresponds to `multipart/related` media type. If the media type is neither type, the value would be left unset and the transformation template will be directly applied. | +| `request.template` | string | True | | | Request body transformation template. The template uses [lua-resty-template](https://github.com/bungle/lua-resty-template) syntax. See the [template syntax](https://github.com/bungle/lua-resty-template#template-syntax) for more details. You can also use auxiliary functions `_escape_json()` and `_escape_xml()` to escape special characters such as double quotes, `_body` to access request body, and `_ctx` to access context variables. | +| `request.template_is_base64` | boolean | False | false | | Set to true if the template is base64 encoded. | +| `response` | object | False | | | Response body transformation configuration. | +| `response.input_format` | string | False | | [`xml`,`json`] | Response body original media type. If unspecified, the value would be determined by the `Content-Type` header to apply the corresponding decoder. If the media type is neither `xml` nor `json`, the value would be left unset and the transformation template will be directly applied. | +| `response.template` | string | True | | | Response body transformation template. | +| `response.template_is_base64` | boolean | False | false | | Set to true if the template is base64 encoded. | -## Enable Plugin +## Examples -You can enable the Plugin on a specific Route as shown below: +The examples below demonstrate how you can configure `body-transformer` for different scenarios. :::note + You can fetch the `admin_key` from `config.yaml` and save to an environment variable with the following command: ```bash @@ -64,227 +63,547 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"/ ::: +The transformation template uses [lua-resty-template](https://github.com/bungle/lua-resty-template) syntax. See the [template syntax](https://github.com/bungle/lua-resty-template#template-syntax) to learn more. + +You can also use auxiliary functions `_escape_json()` and `_escape_xml()` to escape special characters such as double quotes, `_body` to access request body, and `_ctx` to access context variables. + +In all cases, you should ensure that the transformation template is a valid JSON string. + +### Transform between JSON and XML SOAP + +The following example demonstrates how to transform the request body from JSON to XML and the response body from XML to JSON when working with a SOAP upstream service. + +Start the sample SOAP service: + ```shell -curl http://127.0.0.1:9180/apisix/admin/routes/test_ws \ - -H "X-API-KEY: $admin_key" -X PUT -d ' +cd /tmp +git clone https://github.com/spring-guides/gs-soap-service.git +cd gs-soap-service/complete +./mvnw spring-boot:run +``` + +Create the request and response transformation templates: + +```shell +req_template=$(cat < + + + + {{_escape_xml(name)}} + + + +EOF +) + +rsp_template=$(cat < - - - - {{_escape_xml(name)}} - - - -EOF -) +```shell +body=' +foobar: + foo: hello + bar: world' + +curl "http://127.0.0.1:9080/anything" -X POST \ + -d "$body" \ + -H "Content-Type: text/yaml" \ + -i +``` -rsp_template=$(cat < 18 then + context._multipart:set_simple("status", "adult") + else + context._multipart:set_simple("status", "minor") + end + + local body = context._multipart:tostring() +%}{* body *} +EOF +) +``` + +Create a route with `body-transformer`, which sets the `input_format` to `multipart` and uses the previously created request template for transformation: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${ADMIN_API_KEY}" \ + -d '{ + "id": "body-transformer-route", + "uri": "/anything", + "plugins": { + "body-transformer": { + "request": { + "input_format": "multipart", + "template": "'"$req_template"'" } + } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } } -}' + }' +``` + +Send a multipart POST request to the route: + +```shell +curl -X POST \ + -F "name=john" \ + -F "age=10" \ + "http://127.0.0.1:9080/anything" +``` + +You should see a response similar to the following: + +```json +{ + "args": {}, + "data": "", + "files": {}, + "form": { + "age": "10", + "name": "john", + "status": "minor" + }, + "headers": { + "Accept": "*/*", + "Content-Length": "361", + "Content-Type": "multipart/form-data; boundary=------------------------qtPjk4c8ZjmGOXNKzhqnOP", + ... + }, + ... +} ``` diff --git a/docs/zh/latest/config.json b/docs/zh/latest/config.json index d3a8c71232ce..00d89703babb 100644 --- a/docs/zh/latest/config.json +++ b/docs/zh/latest/config.json @@ -82,6 +82,7 @@ "plugins/grpc-web", "plugins/fault-injection", "plugins/mocking", + "plugins/body-transformer", "plugins/attach-consumer-label" ] }, diff --git a/docs/zh/latest/plugins/body-transformer.md b/docs/zh/latest/plugins/body-transformer.md new file mode 100644 index 000000000000..6717dfcf0b13 --- /dev/null +++ b/docs/zh/latest/plugins/body-transformer.md @@ -0,0 +1,609 @@ +--- +title: body-transformer +keywords: + - Apache APISIX + - API 网关 + - Plugin + - BODY TRANSFORMER + - body-transformer +description: body-transformer 插件执行基于模板的转换,将请求和/或响应主体从一种格式转换为另一种格式,例如从 JSON 到 JSON、从 JSON 到 HTML 或从 XML 到 YAML。 +--- + + + + + + + +## 描述 + +`body-transformer` 插件执行基于模板的转换,将请求和/或响应主体从一种格式转换为另一种格式,例如从 JSON 到 JSON、从 JSON 到 HTML 或从 XML 到 YAML。 + +## 属性 + +| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 | +|--------------|----------------------|-------|---------------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------| +| `request` | object | 否 | | | 请求体转换配置。 | +| `request.input_format` | string | 否 | | [`xml`,`json`,`encoded`,`args`,`plain`,`multipart`] | 请求体原始媒体类型。若未指定,则该值将由 `Content-Type` 标头确定以应用相应的解码器。`xml` 选项对应于 `text/xml` 媒体类型。`json` 选项对应于 `application/json` 媒体类型。`encoded` 选项对应于 `application/x-www-form-urlencoded` 媒体类型。`args` 选项对应于 GET 请求。`plain` 选项对应于 `text/plain` 媒体类型。`multipart` 选项对应于 `multipart/related` 媒体类型。如果媒体类型不是这两种类型,则该值将保留未设置状态并直接应用转换模板。 | +| `request.template` | string | True | | | 请求体转换模板。模板使用 [lua-resty-template](https://github.com/bungle/lua-resty-template) 语法。有关更多详细信息,请参阅 [模板语法](https://github.com/bungle/lua-resty-template#template-syntax)。您还可以使用辅助函数 `_escape_json()` 和 `_escape_xml()` 转义双引号等特殊字符,使用 `_body` 访问请求正文,使用 `_ctx` 访问上下文变量。| +| `request.template_is_base64` | boolean | 否 | false | | 如果模板是 base64 编码的,则设置为 true。| +| `response` | object | 否 | | | 响应体转换配置。| +| `response.input_format` | string | 否 | | [`xml`,`json`] | 响应体原始媒体类型。如果未指定,则该值将由 `Content-Type` 标头确定以应用相应的解码器。如果媒体类型既不是 `xml` 也不是 `json`,则该值将保留未设置状态,并直接应用转换模板。| +| `response.template` | string | True | | | 响应主体转换模板。| +| `response.template_is_base64` | boolean | 否 | false | | 如果模板是 base64 编码的,则设置为 true。| + +## 示例 + +以下示例演示了如何针对不同场景配置 `body-transformer`。 + +:::note + +您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量: + +```bash +admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g') +``` + +::: + +转换模板使用 [lua-resty-template](https://github.com/bungle/lua-resty-template) 语法。请参阅 [模板语法](https://github.com/bungle/lua-resty-template#template-syntax) 了解更多信息。 + +您还可以使用辅助函数 `_escape_json()` 和 `_escape_xml()` 转义特殊字符(例如双引号)、`_body` 访问请求正文以及 `_ctx` 访问上下文变量。 + +在所有情况下,您都应确保转换模板是有效的 JSON 字符串。 + +### JSON 和 XML SOAP 之间的转换 + +以下示例演示了在使用 SOAP 上游服务时如何将请求主体从 JSON 转换为 XML,将响应主体从 XML 转换为 JSON。 + +启动示例 SOAP 服务: + +```shell +cd /tmp +git clone https://github.com/spring-guides/gs-soap-service.git +cd gs-soap-service/complete +./mvnw spring-boot:run +``` + +创建请求和响应转换模板: + +```shell +req_template=$(cat < + + + + {{_escape_xml(name)}} + + + +EOF +) + +rsp_template=$(cat < 18 then + context._multipart:set_simple("status", "adult") + else + context._multipart:set_simple("status", "minor") + end + + local body = context._multipart:tostring() +%}{* body *} +EOF +) +``` + +创建一个带有 `body-transformer` 的路由,将 `input_format` 设置为 `multipart`,并使用之前创建的请求模板进行转换: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${ADMIN_API_KEY}" \ + -d '{ + "id": "body-transformer-route", + "uri": "/anything", + "plugins": { + "body-transformer": { + "request": { + "input_format": "multipart", + "template": "'"$req_template"'" + } + } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } + } + }' +``` + +向路由发送多部分 POST 请求: + +```shell +curl -X POST \ + -F "name=john" \ + -F "age=10" \ + "http://127.0.0.1:9080/anything" +``` + +您应该会看到类似以下内容的响应: + +```json +{ + "args": {}, + "data": "", + "files": {}, + "form": { + "age": "10", + "name": "john", + "status": "minor" + }, + "headers": { + "Accept": "*/*", + "Content-Length": "361", + "Content-Type": "multipart/form-data; boundary=------------------------qtPjk4c8ZjmGOXNKzhqnOP", + ... + }, + ... +} +```