Self-hosted service
membrane/api-gateway avatar
membrane/api-gateway

Membrane API Gateway bridges REST and SOAP from one YAML file

API Gateway bridging modern and legacy APIs with WSDL-to-OpenAPI, SOAP-to-REST, XML, OAuth2, and GraphQL.

656 stars184 forksJavaApache-2.0

At a glance

What is it?
Membrane is an Apache-2.0 licensed Java API gateway that deploys APIs from OpenAPI descriptions, converts WSDL and SOAP services into JSON APIs, validates messages against OpenAPI, JSON Schema, XSD and WSDL, and secures them with API keys, OAuth2, JWT and WS-Security, all configured in YAML and shipped as a container image of roughly 55 MB with no database. The last push was on 2026-10-20 and release v7.7.1 came on 2026-10-11.
Who is it for?
Adopt Membrane when you have legacy SOAP or WSDL services that partners need to reach over JSON, or when you want validation and OAuth2 enforcement added to existing APIs without writing a service of your own. Do not adopt it when your gateway needs persistent state, a UI-driven configuration, or throughput measured on your own hardware rather than on the published 16-vCPU Azure benchmark.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One gateway that speaks both REST and SOAP

Membrane API Gateway is written in Java and its whole premise is that a gateway should be able to sit between a modern JSON client and an old XML service without either side changing. The README frames it as an open-source API gateway that speaks both REST and SOAP, deployed from a few lines of YAML, and the project description lists the range: WSDL-to-OpenAPI conversion, SOAP-to-REST, XML, OAuth2 and GraphQL.

The scope is broader than a reverse proxy. It deploys APIs from OpenAPI descriptions, validates incoming messages against a schema before they reach your backend, secures them with API keys, OAuth2 or JWT, and can act as an outgoing gateway that controls access to partner APIs. It also describes an AI Gateway role for LLM providers and MCP servers, and an observability story built on logging, metrics, Prometheus, Grafana and OpenTelemetry tracing.

Two architectural choices shape everything else. There is no database, so the gateway holds no state of its own, and the plugins run in the same process as the HTTP engine rather than across a network hop. The repository layout follows from that: core/ holds the runtime, distribution/ holds the packaged artifacts including the tutorials, annot/ holds an annotation module, war/ holds the web deployment variant, and a top level pom.xml ties them together with Maven.

The Apache-2.0 licence covers the project, and the container image is published under the predic8/membrane name.

Start with one docker run and one apis.yaml file

The quickest way to see it work is a single container:

bash
docker run --rm -it -p 2000:2000 predic8/membrane

The image starts with sample APIs mounted at the same port, including a current time endpoint, an API deployed from an OpenAPI description at /api-docs, and a shop endpoint at /shop/v2/products. If you would rather run it as a Java application, the README points to a Java quickstart instead of a container.

The next step is to write a configuration file. The README asks for an apis.yaml with this content:

yaml
api:
  port: 2000
  target:
    url: https://apibin.io

Three keys and the gateway is proxying. The port is where Membrane listens, and the target URL is the upstream every request is forwarded to, so requests to http://localhost:2000 now reach the upstream service.

To use your own configuration, mount the file into the container at the path Membrane reads it from:

bash
docker run --rm -p 2000:2000 -v "$(pwd)/apis.yaml:/opt/membrane/conf/apis.yaml" predic8/membrane

On Windows PowerShell the same mount uses the PowerShell variable syntax instead, with "${PWD}/apis.yaml" as the host side of the volume mapping. The difference in that one line is the entire platform-specific part of the quick start, which is a good sign about how little ceremony the gateway asks for.

For a longer path, the README suggests downloading the release distribution, unzipping it, and working through tutorials/getting-started/10-First-API.yaml, then continuing with the other tutorials on OpenAPI, security, SOAP and AI.

OpenAPI 3.2 in, WSDL out

The OpenAPI side is the native one. Membrane deploys APIs from OpenAPI descriptions, serves a Swagger UI from them, and uses OpenAPI for message validation. The README states support for OpenAPI 3.0, 3.1 and 3.2, which puts it among the gateways that accept the current specification version.

The legacy direction is the one that generates more interest. Membrane ships wsdl2openapi, which generates OpenAPI descriptions from a WSDL document and then uses that generated description to convert between JSON and XML. The point of the workflow is that you can expose an existing SOAP service as a JSON API without changing the backend, and the OpenAPI description is the artifact that makes both directions work.

Data access across both worlds uses the same tools. XPath and JSONPath give you access to message data for routing, filtering and transformation, while templates and XSLT handle custom formats and more involved conversions. The README makes a point of symmetry here: the same routing, transformation and orchestration capabilities apply to legacy SOAP services and to modern JSON APIs.

For anyone whose integration problem is a partner that insists on SOAP while the internal service is JSON, this is the part of Membrane that carries the value. The cost is that you now maintain a conversion layer defined in YAML, and XSLT is not a language people enjoy maintaining.

Validation and security are the same kind of plugin

Membrane's plugin model means security and validation are configured the same way as routing. Messages can be validated against OpenAPI, JSON Schema, XSD and WSDL, and the README says invalid requests are rejected before they reach the backend. It also describes XML, JSON and GraphQL protection aimed at malicious payloads, which is a separate concern from schema conformance.

The security options listed are API keys, OAuth2 and JWT for APIs, and WS-Security with XML signatures and encryption for SOAP services. That last pairing is the one that shows the project is aimed at enterprises rather than at hobby projects, because WS-Security is what a partner integrating over SOAP will actually ask about.

The design intent is that a deployment is a stack of plugins in one document, so validation, authentication and transformation can be ordered deliberately rather than bolted on by a reverse proxy in front of a reverse proxy. The trade is that you are expressing a security policy in a configuration language rather than in code, so the review path for a change to that policy is a diff of YAML rather than a code review.

The README also positions Membrane as a possible replacement for Backend for Frontend services where declarative configuration suffices, and as something you can embed inside your own Java applications and products, which is a different integration path from running it as a standalone deployment.

Routing, transformation and orchestration in the same file

Beyond proxying, the gateway is a flow engine. The README lists combining calls to multiple APIs in a single flow, processing collections with loops, and controlling execution with conditions, plus routing rules, rate limiting, load balancing and conditional processing for traffic control.

The transformation side is where the format list gets long: JSON, XML, SOAP, HTTP headers, query parameters and other formats can be converted into one another. Since the same routing and transformation capabilities apply to SOAP and JSON upstreams, a legacy integration and a modern one can share a policy file rather than living in two separate proxies.

For custom logic there are three levels of extension, and the README lists them in increasing order of effort. Expressions with SpEL, JSONPath and XPath handle inline conditions and mappings. Groovy scripts handle anything an expression cannot. A Java plugin handles deeper integration, which is where you write your own code against the gateway API.

The README makes a small point that is worth repeating: there is no need to learn Lua. It is a minor thing, but it tells you the configuration and scripting surface is entirely JVM-side, which matters for teams who already run Java and would rather not add a second language to the stack.

The throughput figures come from one documented benchmark

The README publishes throughput numbers from benchmarks on a 16-vCPU Azure VM, and it is worth reading them with their configuration attached. Plain proxying measured 216,000 requests per second. Adding Basic Auth, rate limiting and TLS brought that figure down to 196,000. Validating every request against an OpenAPI description gave 167,000.

Read as a shape rather than a promise, the numbers say that adding authentication, rate limiting and TLS costs roughly a tenth of the throughput, and that validating every request against an OpenAPI description costs somewhat more. The important part for an evaluation is that the last row is the interesting one: a gateway whose selling point is validation is still within reach of a sixth of the plain proxy figure on that machine.

The architecture claim behind those numbers is that the HTTP engine was built specifically for API gateway workloads, and that Java plugins run in the same process, which keeps overhead low compared with gateways built on general-purpose HTTP servers.

The distribution is described as approximately 55 MB, runnable as a container or a Java application, with no database required. The README links both the benchmark setup and results and the performance test directory, so the numbers can be traced and rerun rather than taken on trust. They are still a measurement on one cloud machine, and the README says the same thing about the shared environment when it discusses the alternative benchmarks.

Where the configuration-driven approach stops working

A gateway with no database and no UI has limits that follow from that choice.

First, there is no place to keep state. Rate limit counters, session data or anything else that must survive a restart or be shared across gateway instances is not something the described architecture covers, so those workloads need something in front of it. Second, because configuration lives in YAML files mounted into a container, environment promotion means managing files rather than clicking through a console, and the audit trail is whatever your version control gives you.

Third, the extension path bottoms out in writing Java. The plugin approach is powerful for a team that is comfortable in the JVM, and unhelpful for a team that is not, because there is no scripting language outside the JVM.

The comparison worth making is not against other gateways but against the two alternatives to a gateway at all. Writing a small service in your own language gives you full control of behaviour and a familiar language, at the cost of owning the protocol details, retries, security, and the schema validation that would otherwise be configuration. Writing nothing and letting the partner call the legacy service directly avoids the extra hop, at the cost of the protocol mismatch that started the conversation.

Membrane sits between those options, and its appeal is that the WSDL conversion, the validation and the OAuth2 handling are the parts that would otherwise be hand written. Its weakness is equally clear: when the requirement goes past configuration into custom behaviour, you are writing Java plugins against a framework, which is a real cost even though the alternative was not cheap either.

Editorial conclusion

Adopt Membrane when you have legacy SOAP or WSDL services that partners need to reach over JSON, or when you want validation and OAuth2 enforcement added to existing APIs without writing a service of your own. Do not adopt it when your gateway needs persistent state, a UI-driven configuration, or throughput measured on your own hardware rather than on the published 16-vCPU Azure benchmark. Verify first by starting the container, mounting an apis.yaml that points at one real upstream, and checking the behaviour of the XSLT and Groovy transformations on your actual payloads before migrating the rest of the traffic.

Frequently asked questions

How do I run Membrane API Gateway?

The quickest route is the container image: docker run --rm -it -p 2000:2000 predic8/membrane, which starts with sample APIs on port 2000. To use your own configuration, create an apis.yaml with an api block containing the port and a target URL, then mount it at /opt/membrane/conf/apis.yaml. A Java quickstart is also available for running it as an application.

Can Membrane expose a SOAP service as a JSON API?

Yes. The README describes wsdl2openapi generating an OpenAPI description from a WSDL document and using it to convert between JSON and XML, so an existing SOAP service can be published as a JSON API without changing the backend. Routing, transformation and orchestration work the same way for SOAP and JSON services.

Which OpenAPI versions and security mechanisms does Membrane support?

The README states support for OpenAPI 3.0, 3.1 and 3.2, with OpenAPI used both to deploy APIs and to validate messages. Security options are API keys, OAuth2 and JWT for APIs, and WS-Security with XML signatures and encryption for SOAP services.

Official sources

  1. License: Apache-2.0
  2. membrane/api-gateway on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/membrane-api-gateway.svg)](https://hysenlabs.com/projects/membrane-api-gateway)

Was this useful?