{"id":13485951,"url":"https://github.com/membrane/api-gateway","last_synced_at":"2026-02-26T11:02:07.721Z","repository":{"id":5162364,"uuid":"6332635","full_name":"membrane/api-gateway","owner":"membrane","description":"API gateway for REST, OpenAPI, GraphQL and SOAP written in Java.","archived":false,"fork":false,"pushed_at":"2025-05-05T14:43:07.000Z","size":51600,"stargazers_count":479,"open_issues_count":12,"forks_count":140,"subscribers_count":43,"default_branch":"master","last_synced_at":"2025-05-05T14:51:57.146Z","etag":null,"topics":["api","api-gateway","authentication","http-proxy","java","oauth2","proxy","rest","reverse-proxy","ssl"],"latest_commit_sha":null,"homepage":"https://membrane-api.io","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"copy/v86","license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/membrane.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"docs/SECURITY.md","support":null,"governance":null,"roadmap":"docs/ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2012-10-22T09:39:24.000Z","updated_at":"2025-05-05T14:43:10.000Z","dependencies_parsed_at":"2023-09-18T08:44:48.889Z","dependency_job_id":"900918a4-ab54-493f-945a-7553ea6e5281","html_url":"https://github.com/membrane/api-gateway","commit_stats":null,"previous_names":["membrane/api-gateway","membrane/service-proxy"],"tags_count":130,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/membrane%2Fapi-gateway","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/membrane%2Fapi-gateway/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/membrane%2Fapi-gateway/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/membrane%2Fapi-gateway/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/membrane","download_url":"https://codeload.github.com/membrane/api-gateway/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254209859,"owners_count":22032897,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","api-gateway","authentication","http-proxy","java","oauth2","proxy","rest","reverse-proxy","ssl"],"created_at":"2024-07-31T18:00:34.881Z","updated_at":"2026-02-26T11:02:06.438Z","avatar_url":"https://github.com/membrane.png","language":"Java","readme":"![Membrane Logo](distribution/media/membrane-logo-m-text.svg)\n\n# API Gateway\n\n[![GitHub release](https://img.shields.io/github/v/release/membrane/api-gateway?display_name=tag)](https://github.com/membrane/api-gateway/releases/latest)\n[![Build](https://img.shields.io/github/actions/workflow/status/membrane/api-gateway/build-and-test.yml?branch=master)](https://github.com/membrane/api-gateway/actions)\n[![Docker Pulls](https://img.shields.io/docker/pulls/predic8/membrane)](https://hub.docker.com/r/predic8/membrane)\n[![Hex.pm](https://img.shields.io/hexpm/l/plug.svg)](https://raw.githubusercontent.com/membrane/api-gateway/master/distribution/router/LICENSE.txt)\n\n\u003cimg src=\"docs/images/api-gateway-demo.gif\" alt=\"Animated demo of Membrane API Gateway\" width=\"800\"\u003e\n\nLightweight **API Gateway** for **REST**, **GraphQL** and **legacy Web Services**, easily extended with powerful plugins.\n\nBased on the Java platform, Membrane integrates smoothly with major enterprise technologies. Load tests show that Java provides an excellent foundation for high performance and scalability. On a 2021 MacBook Pro, Membrane handles more than 20,000 requests per second, supports up to 10,000 concurrent clients, and can host over 100,000 APIs on a single instance.\n\nThe examples below demonstrate how to address a wide range of API Gateway requirements using simple configurations. Version **7.0.0 or newer** is required.\n\n**Forwarding Requests from Port 2000 to a Backend:** \n\n```yaml\napi:\n  port: 2000\n  target:\n    url: https://api.predic8.de\n```\n\n**Path Rewriting with an URI Template:**\n```yaml\napi:\n  port: 2000\n  path:\n    uri: /fruit/{id}\n  target:\n    url: https://api.predic8.de/shop/v2/products/${pathParam.id}\n```\n\n**Deploy OpenAPI and enable Request Validation:** \n```yaml\napi:\n  port: 2000\n  openapi:\n    - location: \"fruitshop-api.yml\"\n      validateRequests: yes\n```\n\n**Issue JSON Web Tokens:**\n\nTo issue a JWT for a user, create an API that acts as a simple token endpoint:\n\n```yaml\napi:\n  port: 2000\n  path:\n    uri: /token\n  flow:\n    - basicAuthentication:\n        htpasswdFileProvider:\n          location: .htpasswd\n    - request:\n        - template:\n            contentType: application/json\n            src: |\n              {\n                \"sub\": ${user()}\n              }\n        - jwtSign:\n            jwk:\n              location: jwk.json\n    - return:\n        status: 200\n```\n\nAuthenticated requests to '/token' return a signed JWT in which the username from Basic Authentication is used as the sub claim.\n\n```text\n{\n  \"typ\": \"JWT\",\n  \"alg\": \"RS256\"\n}\n.\n{\n  \"sub\": \"alice\",\n  \"iat\": 1765222877,\n  \"exp\": 1765223177\n}\n.hTL_0-AS8IZgiDUJ6Kg...\n```\n\nThis example is intentionally minimal, but it highlights the basic building blocks: authenticate the caller, shape the token payload, and sign the result. From there, you can extend it with additional claims, custom logic, or stricter policies to implement tailored API security flows.\n\n## API Gateway eBook\n\nLearn how API Gateways work with real-world examples and insights into Membrane.\n\n![API Gateway eBook Cover](docs/images/api-gateway-ebook-cover.jpg)\n\n[Download instantly](https://www.membrane-api.io/ebook/API-Gateway-Handbook-v1.0.0.pdf) — **no registration** required.\n\n## Features\n\n### **OpenAPI**\n\n- Deploy APIs from [OpenAPI specifications](https://www.membrane-api.io/openapi/configuration-and-validation).\n- Validate requests and responses against [OpenAPI](distribution/examples/openapi/validation-simple) and **JSON Schema**.\n\n### **API Security**\n- [JSON Web Tokens](#json-web-tokens), [OAuth2](https://www.membrane-soa.org/service-proxy/oauth2-provider-client.html), [API Keys](#api-keys), [NTLM](distribution/examples/security/ntlm), and [Basic Authentication](https://www.membrane-api.io/docs/current/basicAuthentication.html).\n- Built-in [OAuth2 Authorization Server](https://www.membrane-soa.org/service-proxy-doc/4.8/security/oauth2/flows/code/index.html).\n- [Rate limiting](#rate-limiting) and traffic control\n- Protection for **GraphQL**, **JSON**, and **XML** APIs against malicious inputs.\n\n### **Legacy Web Services**\n- Seamless support for [SOAP message routing](#soap-web-services).\n- Configure, validate, and rewrite WSDL-based services, including [message validation](#message-validation-against-wsdl-and-xsd).\n\n### **Additional Features**\n- **Admin Web Console** for monitoring and management.\n- Advanced [load balancing](#load-balancing) to ensure high availability.\n- Flexible [message transformation](#message-transformation) for seamless data processing.\n- Embeddable reverse proxy HTTP framework to build custom API gateways.\n- Traffic shadowing\n\n### **Speed \u0026 Size**\n\n- Streams HTTP traffic for low-latency, non-blocking processing.\n- Reuses TCP connections via HTTP Keep-Alive to reduce request overhead.\n- Lightweight distribution (~55MB) compared to other Java-based gateways.\n- Low memory footprint, ideal for containers and cloud-native environments.\n- Java-based, yet competitive with C/C++ gateways in performance.\n\n# Content\n\n1. [Getting Started](#getting-started)\n    - [Java](#java)\n    - [Docker](#docker)\n2. [Basics](#basics) Routing, rewriting\n    - [API Definition and Configuration](#api-definition-and-configuration)\n    - [Simple REST and HTTP Forwarding APIs](#simple-rest-and-http-forwarding-apis)\n3. [OpenAPI Support](#openapi-support)\n    - [Deploy APIs with OpenAPI](#deploy-apis-with-openapi)\n4. [Routing](#routing)\n    - [Short Circuit](#short-circuit)\n    - [URL Rewriting](#url-rewriting)\n5. [Scripting](#scripting)\n    - With [Groovy](#groovy-scripts) and [Javascript](#javascript-scripts)\n    - [Creating Responses with Groovy](#creating-responses-with-groovy)\n6. [Message Transformation](#message-transformation)\n    - [Manipulating](#manipulating-http-headers) and [removing](#removing-http-headers) HTTP Headers\n    - [Create JSON from Query Parameters](#create-json-from-query-parameters)\n    - [Transform JSON into TEXT, JSON or XML with Templates](#transform-json-into-text-json-or-xml-with-templates)\n    - [Transform XML into Text or JSON](#transform-xml-into-text-or-json)\n    - [Complex Transformations using Javascript or Groovy](#complex-transformations-using-javascript-or-groovy)\n    - [Transformation with Computations](#transformation-with-computations)\n    - [JSON and XML Beautifier](#json-and-xml-beautifier)\n7. [Conditionals with if](#conditionals-with-if)\n8. [Security](#security)\n    - [API Keys](#api-keys) and [Basic Authentication](#basic-authentication)\n    - [SSL/TLS](#ssltls)\n    - [JSON Web Tokens](#json-web-tokens) JWT\n    - [OAuth2](#oauth2)\n    - [Secure APIs with OAuth2](#secure-apis-with-oauth2)\n        - [Membrane as Authorization Server](#membrane-as-authorization-server)\n        - [XML and JSON Protection](#xml-and-json-protection)\n9. [Traffic Control](#traffic-control) Rate limiting, Load balancing\n    - [Rate Limiting](#rate-limiting)\n    - [Load Balancing](#load-balancing)\n10. [Legacy Web Services](#soap-web-services) SOAP and WSDL\n    - [API configuration from WSDL](#api-configuration-from-wsdl)\n    - [Message Validation against WSDL and XSD](#message-validation-against-wsdl-and-xsd)\n11. [Operation](#operation)\n    - [Logging](#log-http)\n    - [Monitoring with Prometheus and Grafana](#monitoring-with-prometheus-and-grafana)\n    - [OpenTelemetry](#opentelemetry-integration)\n12. [Community and professional Support](#support)\n\n# Installation\n\nYou can run Membrane as Docker container, standalone Java application or install it on Linux as RPM.\n\n## Java\n\n1. **Download and extract**\n    - [Download a release](https://github.com/membrane/api-gateway/releases) and unzip it.\n2. **Start the Gateway**\n    - Open a terminal in the extracted folder.\n    - Make sure Java 21 or newer is installed:\n    ```bash\n    java -version\n    ```\n    - Start:\n        - **Linux/Mac:** `./membrane.sh`\n        - **Windows:** `membrane.cmd`\n3. **Access the Gateway**\n    - Open [http://localhost:2000](http://localhost:2000)\n4. **Change the Configuration**\n\n   Modify the preconfigured APIs or add APIs by editing the `proxies.xml` file in the `conf` folder.\n\n## Docker\n\n1. **Start a Membrane container**\n   ```bash\n   docker run -p 2000:2000 predic8/membrane\n   ```\n2. **Access the Gateway**\n\n   Test an API by opening [http://localhost:2000](http://localhost:2000).\n\n3. **Change the Configuration**\n   - Download [proxies.xml](https://raw.githubusercontent.com/membrane/api-gateway/master/distribution/router/conf/proxies.xml) or:\n\n     ```bash\n     wget https://raw.githubusercontent.com/membrane/api-gateway/master/distribution/router/conf/proxies.xml\n     ```\n   \n   - Bind the configuration file to the container.\n\n     **Mac/Linux:**\n     ```bash\n     docker run -v \"$(pwd)/proxies.xml:/opt/membrane/conf/proxies.xml\" -p 2000:2000 predic8/membrane\n     ```  \n\n     **Windows:**\n     ```bash\n     docker run -v %cd%\\proxies.xml:/opt/membrane/conf/proxies.xml -p 2000:2000 predic8/membrane\n     ```\n\n     You can now edit `proxies.xml` and restart the container to apply the changes.\n\n\nFor detailed Docker setup instructions, see the [Membrane Deployment Guide](https://membrane-api.io/deployment/#docker).\n\n## Getting Started\n\n### Explore and Experiment\n- Try the code snippets on this page.\n- Run the samples in the [examples](distribution/examples#working-api-gateway-examples) folder of the distribution.\n\n### Dive into Tutorials\n- Follow the [REST API Tutorial](https://membrane-api.io/tutorials/rest/) to learn about deploying and securing APIs.\n- Check out the [SOAP API Tutorial](https://membrane-api.io/tutorials/soap/) for legacy web service integration.\n\n### Documentation\n\n- Read the [API Gateway eBook](https://www.membrane-api.io/api-gateway-ebook.html)\n- Look at the [documentation](https://www.membrane-api.io).\n- Browse the [reference](https://www.membrane-api.io/docs/)\n- Try the recipes from the [cookbook](https://www.membrane-api.io/api-gateway-cookbook.html)\n\n# Basics\n\n### API Definition and Configuration\n\nTo define new APIs or modify the existing configuration, edit the `proxies.xml` file located in the `conf` folder. This file serves as the central configuration point for managing API behavior and routing rules.\n\n### Using Samples\nExplore and copy the sample snippets below into the `proxies.xml` file and modify them to suit your needs. Then save or restart the gateway to apply the changes. Usually a save will trigger a reload automatically.\n\nFor even more samples have a look at the `examples` folder. \n\n\n## Simple REST and HTTP Forwarding APIs\n\n### Define an API Route\nTo forward requests from the API Gateway to a backend, use a simple `api` configuration. The example below routes requests received on port `2000` with a path starting with `/shop` to the backend at `https://api.predic8.de`:\n\n```yaml\napi:\n  port: 2000\n  path:\n    uri: /shop\n  target:\n    url: https://api.predic8.de\n```\n\n### Testing the Configuration\nAfter modifying and saving the `proxies.xml` file, open [http://localhost:2000/shop/v2/](http://localhost:2000/shop/v2/)\n\n\n## OpenAPI Support\n\nMembrane natively supports OpenAPI, allowing you to easily configure the gateway with OpenAPI documents and automatically validate both requests and responses.\n\n### Deploy APIs with OpenAPI\nMembrane allows you to configure APIs directly from OpenAPI documents in the `proxies.xml` file. Backend addresses and other details are automatically derived from the OpenAPI description.\n\n#### Example Configuration\nThe snippet below shows how to deploy an API using an OpenAPI (`openapi/fruitshop-v2-2-0.oas.yml`) with request validation enabled:\n\n```yaml\napi:\n  port: 2000\n  openapi:\n    - location: openapi/fruitshop-v2-2-0.oas.yml\n      validateRequests: true\n```  \n\n#### Viewing Deployed APIs\nOnce configured, a list of deployed APIs is available at: [http://localhost:2000/api-docs](http://localhost:2000/api-docs)\n\n![List of OpenAPI Deployments](distribution/examples/openapi/openapi-proxy/api-overview.jpg)\n\nClick on an API title in the list to open the Swagger UI for interactive exploration and testing:\n\n![Swagger UI](distribution/examples/openapi/openapi-proxy/swagger-ui.jpg)\n\n### Learn More\nFor additional details and a working example, check out the [OpenAPI Example](distribution/examples/openapi).\n\n## Routing\nMembrane provides versatile routing with a fallthrough mechanism that applies only the first matching API rule, ensuring precise and efficient routing based on path, HTTP method, or hostname or many other criterias.\n\n### Example: Advanced Routing\n\nThe configuration below demonstrates several routing rules:\n\n```yaml\n# POST requests\napi:\n  port: 2000\n  method: POST \n  flow:\n    - response:\n        - static:\n            src: POST is blocked!\n    - return:\n        status: 405\n---\n# Regex path matching\napi:\n  port: 2000\n  path:\n    uri: /shop/v2/products/.*\n    isRegExp: true\n  target:\n    url: https://api.predic8.de\n---\n# Requests whose HOST header is \"www.predic8.de\"\napi:\n  port: 2000\n  host: www.predic8.de\n  flow:\n    - response:\n        - static:\n            src: \"\u003chtml\u003eHomepage\u003c/html\u003e\"\n    - return:\n        status: 200\n---\n# Requests with a query parameter city and value Paris\napi:\n  port: 2000\n  test: params.city?.[0] == 'Paris'\n  flow:\n    - response:\n        - static:\n            src: Oui!\n    - return:\n        status: 200\n```\n\n### Configuration Options\n\n| Option   | Description                                                                  |\n|----------|------------------------------------------------------------------------------|\n| `port`   | port Membrane listens for incoming connections.                              |\n| `method` | - HTTP method (e.g., `GET`, `POST`, `DELETE`).\u003cbr\u003e- `*` matches any method.  |\n| `host`   | - Hostname e.g. `api.predic8.de`\u003cbr\u003e - Supports basic globbing with `*`      |\n| `test` | - Custom script e.g. `$pathParam.id == '42'`, `$header.contentType == '...'` |\n| `path`   | - Request path\u003cbr\u003e- Regular expressions can be used with `isRegExp=\"true\"`   |\n\nFor more routing options, see the [Membrane API documentation](https://www.membrane-api.io/docs/current/api.html).\n\n### Short Circuit\n\nMembrane lets you create endpoints that return immediately without forwarding requests to a backend.\n\n#### Example: Health Check\nThe following configuration creates a health check endpoint that responds to requests at [http://localhost:2000/health](http://localhost:2000/health):\n\n```yaml\napi:\n  port: 2000\n  path:\n    uri: /health\n  flow:\n    - response:\n        - static:\n            src: I'm good.\n    - return:\n        status: 200\n```\n\n#### Example: Blocking Specific Paths\nBlock paths (e.g., `/nothing`) while allowing other calls to pass through.\n\n**Routing Note:** APIs are matched from top to bottom. When multiple APIs share the same port, place the APIs with stricter routing conditions higher in the configuration.\n\n```yaml\napi:\n  port: 2000\n  path:\n    uri: /nothing\n  flow:\n    - response:\n        - static:\n            src: \"Nothing to see here!\"\n    - return:\n        status: 404\n---\napi:\n  port: 2000\n  flow:\n    - static:\n        src: Other calls\n    - return:\n        status: 200\n```\n\n### URL Rewriting\n\nThe URLs of request can be rewritten dynamically before forwarding them to the backend. This is useful for restructuring API paths or managing legacy endpoints.\n\n#### Example\nThe following configuration rewrites requests starting with `/fruitshop` to `/shop/v2`, preserving the remainder of the path:\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - rewriter:\n        - from: ^/fruitshop/(.*)\n          to: /shop/v2/$1\n  target:\n    url: https://api.predic8.de\n```\n\n#### Testing\nA request to:\n```\nhttp://localhost:2000/fruitshop/products/4\n```  \nwill be rewritten to and forwarded to the backend at:\n```\nhttps://api.predic8.de/shop/v2/products/4\n```\n\n# Scripting\n\nMembrane has powerful scripting features that allow to modify the desired of an API using Groovy or Javascript. \n\n#### Use Cases\n\n- **Custom Responses**: Tailor responses dynamically based on client requests or internal logic.\n- **Mocking APIs**: Simulate API behavior during testing or development phases.\n- **Dynamic Headers**: Add headers conditionally based on business rules.\n- **Debugging**: Inspect incoming requests during development.\n\n### Groovy Scripts\n\nThe following API executes a Groovy script during the request and the response. \n\n```yaml\napi:\n  port: 2000\n  flow:\n    - groovy:\n        src: |\n          println \"I'm executed in the ${flow} flow\"\n          println \"HTTP Headers:\\n${header}\"\n  target:\n    url: https://api.predic8.de\n```\n\nAfter invoking [http://localhost:2000](http://localhost:2000) you can see the following output in the console where you have started Membrane:\n\n```text\nI'm executed in the REQUEST flow\nHTTP Headers:\nHost: localhost:2000\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:133.0) Gecko/20100101 Firefox/133.0\n...\n\nI'm executed in the RESPONSE flow\nHTTP Headers:\nContent-Length: 390\nContent-Type: application/json\n```\n\n#### Dynamically Route to random Target \n\nYou can realize a load balancer by setting the destination randomly.  \n\n```yaml\napi:\n  port: 2013\n  flow:\n    - groovy:\n        src: |\n          sites = [\"https://api.predic8.de\",\"https://membrane-api.io\",\"https://predic8.de\"]\n          Collections.shuffle sites\n          exchange.destinations = sites\n  target: {} # No details needed target uses destinations from exchange\n```\n\n### Creating Responses with Groovy\n\nThe `groovy` plugin in Membrane allows you to dynamically generate custom responses. The result of the last line of the Groovy script is passed to the plugin. If the result is a `Response` object, it will be returned to the caller.\n\n#### Example\nThe following example creates a custom JSON response with a status code of `200`, a specific content type, and a custom header:\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - groovy:\n        src: |\n          Response.ok()\n            .contentType(\"application/json\")\n            .header(\"X-Foo\", \"bar\")\n            .body(\"\"\"\n              {\n                \"success\": true\n              }\"\"\")\n            .build()\n```  \n\n#### How It Works\n- The `Response.ok()` method initializes a new HTTP response with a status of `200 OK`.\n- The `contentType()` method sets the `Content-Type` header, ensuring the response is identified as JSON.\n- The `header()` method adds custom headers to the response.\n- The `body()` method specifies the response payload.\n- The `build()` method finalizes the response object, which is then returned by the `groovy` plugin.\n\n#### Resulting Response\nWhen accessing this API, the response will look like this:\n\n```\nHTTP/1.1 200 OK  \nContent-Type: application/json  \nX-Foo: bar  \n\n{\n  \"success\": true\n}\n```  \n\n#### Learn More about the Groovy Plugin\nFor more information about using Groovy with Membrane, refer to:\n\n- [Groovy Plugin Reference](https://www.membrane-api.io/docs/current/groovy.html).\n- [Sample Project](distribution/examples/scripting/groovy)\n\n### JavaScript Scripts\n\nIn addition to Groovy, Membrane supports JavaScript for implementing custom behavior. This allows you to inspect, modify, or log details about requests and responses.\n\n#### Example\nThe following example logs all HTTP headers from incoming requests and responses to the console:\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - javascript:\n        src: |\n          console.log(\"------------ Headers: -------------\");\n          var fields = header.getAllHeaderFields();\n          for (var i = 0; i \u003c fields.length; i++) {\n            console.log(fields[i]);\n          }\n  target:\n    url: https://api.predic8.de\n```  \n\nThe `CONTINUE` keyword ensures that the request continues processing and is forwarded to the target URL.\n\nWhen a JavaScript script returns a `Response` object as the last line of code, the request flow is interrupted, and the response is sent back to the client. This allows for creating custom responses dynamically.\n\nThe following example generates a JSON response and sends it directly to the client:\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - javascript:\n        src: |\n          var body = JSON.stringify({\n            foo: 7,\n            bar: 42\n          });\n          Response.ok(body).contentType(\"application/json\").build();\n```\n\n#### Learn More\nFor more details about using JavaScript with Membrane, check the [JavaScript Plugin documentation](https://www.membrane-api.io/docs/current/javascript.html).\n\n## Message Transformation\n\n### Manipulating HTTP Headers\n\nYou can modify HTTP headers in requests or responses using Membrane's `setHeader` and `headerFilter` feature. This is particularly useful for enabling CORS or adding custom headers.\n\n#### Example: Adding CORS Headers\nThe following configuration adds `CORS` headers to the responses received from the backend:\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - response:\n        - setHeader:\n            name: Access-Control-Allow-Origin\n            value: \"*\"\n        - setHeader:\n            name: Access-Control-Allow-Methods\n            value: GET\n  target:\n    url: https://api.predic8.de\n```\n\n### Example: Setting Headers from JSON Body Content\n\nMembrane allows dynamic extraction of values from the JSON body of a request or response and uses them to set HTTP headers. \n\n#### Example Configuration\nThe following example extracts the `id` and `name` fields from a JSON body and sets them as custom headers in the response:\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - response:\n      - setHeader:\n          name: X-Product-Id\n          value: ${jsonPath('$.id')}\n          language: spel\n      - setHeader:\n          name: X-Product-Name\n          value: ${$.name}\n          language: jsonpath\n  target:\n    url: https://api.predic8.de\n```\n\n### Removing HTTP Headers\n\nYou can easily remove specific HTTP headers from requests or responses (or both) using the `headerFilter` element. This is useful for cleaning up headers or meeting security requirements.\n\n#### Example: Header Filtering\nThe following configuration demonstrates how to manage headers:\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - response:\n        - headerFilter:\n            - include: \"X-XSS-Protection\"\n            - exclude: \"X-.*\"\n  target:\n    url: https://www.predic8.de\n```  \n\n- **`\u003cinclude\u003e`:** Specifies headers to retain.\n- **`\u003cexclude\u003e`:** Defines headers to remove. Wildcards can be used for patterns.\n\nThe first matching rule will be acted upon by the filter.\n\n### Create JSON from Query Parameters\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - request:\n        - template:\n            contentType: application/json\n            pretty: true\n            src: |\n              { \"answer\": ${params.answer?[0]} }\n    - return:\n        status: 200\n```\n\nCall this API with `http://localhost:2000?answer=42`.\n\n## Transform JSON into TEXT, JSON or XML with Templates\n\nCall the following APIs with this request:\n\n```\ncurl -d '{\"city\":\"Berlin\"}' -H \"Content-Type: application/json\" \"http://localhost:2000\"\n```\n\nThis template will transform the JSON input into plain text:\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - request:\n        - template:\n            contentType: text/plain\n            src: |\n              City: ${json.city}\n        - return:\n            status: 200\n```\n\n...into a different JSON:\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - request:\n        - template:\n            contentType: application/json\n            src: |\n              {\n                \"destination\": ${json.city}\n              }\n    - return:\n        status: 200\n```\n\n...or into XML:\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - request:\n        - template:\n            contentType: application/xml\n            src: |\n              \u003cplaces\u003e\n                  \u003cplace\u003e${json.city}\u003c/place\u003e\n              \u003c/places\u003e            \n    - return:\n        status: 200\n```\n\n### Transform XML into Text or JSON\n\nYou can use XPath to extract values from an XML message and insert them into a `template`.\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - request:\n        - template:\n            src: |\n              Buenas noches, ${xpath('/person/@firstname')}\n        - return:\n            status: 200\n```\n\nSee: [message-transformation examples](./distribution/examples/message-transformation)\n\n## Complex Transformations using Javascript or Groovy\n\nUse the Javascript or Groovy plugin for more powerful yet simple transformations.\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - request:\n        - javascript:\n            src: |\n              ({ id:7, place: json.city })\n    - return:\n        status: 200\n        contentType: application/json\n```\n\nCall the API with this curl command:\n\n```\ncurl -d '{\"city\":\"Berlin\"}' -H \"Content-Type: application/json\" \"http://localhost:2000\"\n```\n\n## Transformation with Computations\n\nThis script transforms the input and adds some calculations.\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - request:\n        - javascript:\n            src: |\n              function convertDate(d) {\n                return d.getFullYear() + \"-\" + (\"0\"+(d.getMonth()+1)).slice(-2) + \"-\" + (\"0\"+d.getDate()).slice(-2);\n              }\n\n              ({\n                id: json.id,\n                date: convertDate(new Date(json.date)),\n                client: json.customer,\n                total: json.items.map(i =\u003e i.quantity * i.price).reduce((a,b) =\u003e a+b),\n                positions: json.items.map(i =\u003e ({\n                pieces: i.quantity,\n                price: i.price,\n                article: i.description\n              }))\n              })\n    - return:\n        status: 200\n```\n\nSee [examples/javascript](distribution/examples/scripting/javascript) for a detailed explanation. The same transformation can also be realized with [Groovy](distribution/examples/scripting/groovy)\n\n## JSON and XML Beautifier\n\nUse the `beautifier` to pretty print JSON or XML.\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - response:\n        - beautifier: {}\n        - template:\n            contentType: application/json\n            src: |\n              { \"foo\": { \"bar\": { \"baz\": 99 }}}\n    - return:\n        status: 200\n```\n\nResult:\n\n```json\n{\n  \"foo\" : {\n    \"bar\" : {\n      \"baz\" : 99\n    }\n  }\n}\n```\n\n# Conditionals with if\n\nThis example shows how to intercept error responses from a backend and replace them with a custom response.\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - response:\n        - if:\n            test: statusCode \u003e= 500\n            language: spel\n            flow:\n              - static:\n                  src: Failure!\n  target:\n    url: https://httpbin.org/status/500\n```\n\n# Security\n\nMembrane offers all kinds of security features to protect APIs and backend servers.\n\n## API Keys\n\nAPI keys can be defined in the configuration, loaded from a file, or stored in a database. Requests are authenticated by validating the provided API key against these sources.\n\nYou can also define permissions using scopes in OpenAPI and enforce them with API keys, OAuth 2.0, or JWT-based authentication.\n\nThis configuration secures all APIs globally. Alternatively, API keys can be defined for individual APIs only.\n\n```yaml\nglobal:\n  - apiKey:\n      stores:\n        - simple:\n            - secret:\n                value: aed8bcc4-7c83-44d5-8789-21e4024ac873\n            - secret:\n                value: 08f121fa-3cda-49c6-90db-1f189ff80756\n      extractors:\n        - header: X-Api-Key\n```\n\n### Advanced Use Cases\n\nMore advanced scenarios are supported, including:\n\n- API keys in headers, query parameters or at any other location using expressions.\n- Role-based access control (RBAC) with fine-grained permissions.\n- OpenAPI-defined permissions.\n\nSee the [API Key Plugin Examples](./distribution/examples/security/api-key/rbac/README.md) for detailed configurations.\n\n## JSON Web Tokens\n\nThe API below only allows requests that present a valid JSON Web Token issued by Microsoft Azure Entra ID. The JWT validator can also be used with other identity providers.\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - jwtAuth:\n        expectedAud: api://2axxxx16-xxxx-xxxx-xxxx-faxxxxxxxxf0\n        jwks:\n          jwksUris: https://login.microsoftonline.com/common/discovery/keys\n  target:\n    url: https://your-backend\n```\n\n## OAuth2\n\n### Secure APIs with OAuth2\n\nUse OAuth2/OpenID to secure endpoints against Google, Azure Entra ID, GitHub, Keycloak or Membrane Authentication Servers.\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - oauth2Resource2:\n        membrane:\n          src: http://localhost:8000\n          clientId: abc\n          clientSecret: def\n          scope: openid profile\n          claims: username\n          claimsIdt: sub\n    - request:\n        # Forward the authenticated user’s email to the backend in an HTTP header.\n        - setHeader:\n            name: X-EMAIL\n            value: ${property['membrane.oauth2'].userinfo['email']}\n  target:\n    url: http://backend\n```\n\nTry the tutorial [OAuth2 with external OpenID Providers](https://membrane-soa.org/api-gateway-doc/current/oauth2-openid.html)\n\n### Membrane as Authorization Server\n\nMembrane includes a fully functional OAuth 2.0 Authorization Server and can also act as an OpenID Connect Provider.\n\nThe following example shows a minimal configuration for running Membrane as an OAuth 2.0 authorization server with a static client definition and basic claim and scope setup.\n\n```yaml\napi:\n  port: 8000\n  flow:\n    - oauth2authserver:\n        issuer: http://localhost:8000\n        location: logindialog\n        consentFile: consentFile.json\n        staticUserDataProvider:\n          users:\n            - username: john\n              password: secret\n              email: john@predic8.de\n        staticClientList:\n          clients:\n            - clientId: abc\n              clientSecret: def\n              callbackUrl: http://localhost:2000/oauth2callback\n        bearerToken: {}\n        claims:\n          value: aud email iss sub username\n          scopes:\n            - id: username\n              claims: username\n            - id: profile\n              claims: username email\n```\n\nUser accounts can be stored directly in the configuration, loaded from a file, or backed by a database.\n\nFor a full walkthrough of the authorization code flow, see the OAuth2 Authorization Server example [OAuth2 Authorization Server](https://www.membrane-soa.org/service-proxy-doc/4.8/oauth2-code-flow-example.html).\n\n## Basic Authentication\n\nSometimes the old basic authentication is enough to provide basic security.\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - basicAuthentication:\n        users:\n          - username: alice\n            password: secret\n          - username: bob\n            password: secret\n  target:\n    url: https://api.predic8.de\n```\n\n## SSL/TLS\n\nTLS is the base for secure API communication.\n\nThe first example shows TLS being used for connections from the API Gateway to the backend:\n\n```yaml\napi:\n  port: 2000\n  # Note the 's' in https!\n  target:\n    url: https://api.predic8.de\n```\n\nThe next example secures the public endpoint, enabling TLS for connections from clients to the API Gateway:\n\n```yaml\napi:\n  port: 443\n  ssl:\n    keystore:\n      location: keystore.p12\n      password: changeit\n    truststore:\n      location: keystore.p12\n      password: changeit\n  target:\n    url: http://backend\n```\n\nSee more [TLS/SSL configuration examples](/distribution/examples/security/ssl-tls)\n\n### XML and JSON Protection\n\nMembrane offers protection mechanisms to secure your APIs from common risks associated with XML and JSON payloads.\n\n#### XML Protection\n\n`xmlProtection` inspects incoming XML and reduces common attack vectors, including:\n\n- External entity references (XXE).\n- Overly long element names.\n- High numbers of attributes or deeply nested structures.\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - xmlProtection:\n        maxAttributeCount: 3\n        maxElementNameLength: 100\n        removeDTD: true\n    - return:\n        status: 200\n```  \n\nSee [XML Protection Reference](https://www.membrane-api.io/docs/current/xmlProtection.html).\n\n#### JSON Protection\n\nThe `jsonProtection` plugin safeguards APIs from JSON-based vulnerabilities by setting limits on:\n\n- **Depth**: Prevents overly nested JSON structures.\n- **Key Length**: Restricts excessively long keys.\n- **Object Size**: Maximum number of fields in a JSON object.\n- **String Length**: Controls maximum length of string values.\n- **...**\n\n**Example:**\n\n```yaml\nglobal:\n  - jsonProtection:\n      maxDepth: 3\n      maxObjectSize: 50\n      maxArraySize: 1000\n```  \n\nSee [JSON Protection](https://www.membrane-api.io/docs/current/jsonProtection.html).\n\n# Traffic Control\n\n## Rate Limiting\n\nLimit the number of incoming requests:\n\n```yaml\nglobal:\n  - rateLimiter:\n      requestLimit: 1000\n      requestLimitDuration: PT1H\n```\n\n## Load balancing\n\nDistribute workload to multiple backend nodes. [See the example](distribution/examples/loadbalancing)\n\n```yaml\napi:\n  port: 8080\n  flow:\n    - balancer:\n        clusters:\n          - name: Default\n            nodes:\n              - host: my.backend-1\n                port: 4000\n              - host: my.backend-2\n                port: 4000\n              - host: my.backend-3\n                port: 4000\n```\n\n# Websockets\n\nRoute and intercept WebSocket traffic:\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - webSocket:\n        url: http://my.websocket.server:1234\n        flow:\n          - wsLog: {}\n  target:\n    host: localhost\n    port: 8080\n```\n\nSee [documentation](https://www.membrane-soa.org/service-proxy-doc/4.8/websocket-routing-intercepting.html)\n\n# SOAP Web Services\n\nIntegrate legacy services.\n\n## API configuration from WSDL\n\nMembrane reads the WSDL and automatically generates a SOAP proxy.\n\n```yaml\nsoapProxy:\n  port: 2000\n  wsdl: https://www.predic8.de/city-service?wsdl\n```\n\nAfter startup, Membrane exposes:\n\n- A SOAP endpoint at http://localhost:2000/city-service\n- A WSDL at http://localhost:2000/city-service?wsdl\n\n## Message Validation against WSDL and XSD\n\nThe _validator_ checks SOAP messages against a WSDL document including referenced XSD schemas.\n\n```yaml\nsoapProxy:\n  port: 2000\n  wsdl: https://www.predic8.de/city-service?wsdl\n  flow:\n    # Validates SOAP messages against the WSDL and XSDs\n    - validator: {}\n```\n\n# Operation\n\n## Log HTTP\n\nLog data about requests and responses to a file or [database](distribution/examples/logging/jdbc-database) as [CSV](distribution/examples/logging/csv)\nor [JSON](distribution/examples/logging/json) file.\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - log: {} # Logs to the console\n    - statisticsCSV:\n        file: ./log.csv # Logs fine-grained CSV\n  target:\n    url: https://api.predic8.de\n```\n\n## Instrumentation\n\n### Monitoring with Prometheus and Grafana\n\nThis API will expose metrics for Prometheus at [http://localhost:2000/metrics](http://localhost:2000/metrics):\n\n```yaml\napi:\n  port: 2000\n  path:\n    uri: /metrics\n  flow:\n    - prometheus: {}\n```\n\n![Grafana Dashborad for Membrane API Gateway](/docs/images/membrane-grafana-dashboard.png)\nGrafana dashboard from Membrane metrics.\n \nSee [Prometheus and Grafana example](distribution/examples/monitoring-tracing/prometheus-grafana).\n\n### OpenTelemetry Integration\nMembrane supports integration with **OpenTelemetry** traces using the `openTelemetry` plugin and the `W3C` propagation standard. This enables detailed tracing of requests across Membrane and backend services.\n\n![OpenTelemetry Example](distribution/examples/monitoring-tracing/opentelemetry/resources/otel_example.png)  \nThis diagram illustrates Membrane in a tracing setup with a backend service and a database connection.\n\n#### Example Setup\nThe configuration below shows Membrane forwarding requests to a backend, while exporting OpenTelemetry data to a collector:\n\n```yaml\napi:\n  port: 2000\n  flow:\n    - openTelemetry:\n        sampleRate: 1.0\n        otlpExporter:\n          host: localhost\n          port: 4317\n  target:\n    host: localhost\n    port: 3000\n```  \n\nFor a working example and detailed setup, see the [OpenTelemetry Example](./distribution/examples/monitoring-tracing/opentelemetry).\n\n# Support\n\n## Community Support\n\nTo get support from our community, please post your questions to our [Discussions](https://github.com/membrane/api-gateway/discussions) page @GitHub.\n\nIf you find a bug, please report it using [GitHub Issues](https://github.com/membrane/api-gateway/issues). Please provide a minimal example that reproduces the issue and the version of Membrane you are using.\n\n## Enterprise-grade Support\n\nSee [commercial support options and pricing](https://www.membrane-api.io/api-gateway-pricing.html).\n","funding_links":[],"categories":["Projects","API网关"],"sub_categories":["Miscellaneous"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmembrane%2Fapi-gateway","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmembrane%2Fapi-gateway","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmembrane%2Fapi-gateway/lists"}