Git Product home page Git Product logo

membrane / service-proxy Goto Github PK

View Code? Open in Web Editor NEW
442.0 43.0 139.0 46.79 MB

API gateway for REST, OpenAPI, GraphQL and SOAP written in Java.

Home Page: https://membrane-api.io

License: Apache License 2.0

Java 93.85% CSS 1.37% JavaScript 1.38% XSLT 0.77% Shell 1.23% HTML 0.33% Batchfile 1.01% PowerShell 0.04% Dockerfile 0.02% Python 0.01%
reverse-proxy java proxy oauth2 ssl api-gateway api rest authentication http-proxy

service-proxy's Introduction

Membrane Logo

API Gateway

GitHub release Hex.pm

API Gateway for REST, WebSockets and legacy Web Services written in Java. Featuring:

OpenAPI:

API Security:

Legacy Web Services:

Other:

Getting Started

Java

  1. Make sure Java 17 or newer is installed.

  2. Download the binary and unzip it.

  3. Run service-proxy.sh or service-proxy.bat in a terminal

  4. Open http://localhost:2000 to access https://api.predic8.de over the gateway.

  5. Change the configuration in conf/proxies.xml

Docker

$ docker run -p 2000:2000 predic8/membrane

Browse to http://localhost:2000 or use curl:

curl http://localhost:2000

This should yield the same response as calling https://api.predic8.de does.

More about setting up Membrane for Docker.

Next Steps

See the snippets below, run the samples, follow the REST or SOAP tutorial or have a look at the documentation.

Configuration

Try the following snippets by copying them into the conf/proxies.xml file.

Using OpenAPI for Configuration & Validation

Configures APIs from OpenAPI and validates messages against the definitions. Needed data like backend addresses are taken from the OpenAPI description. See the example

This configuration is all you need to deploy from OpenAPI:

<api port="2000">
    <openapi location="fruitshop-api.yml" validateRequests="yes"/>
</api>

A list of deployed APIs is available at http://localhost:2000/api-docs

List of OpenAPI Deployments

Click on the API title to get the Swagger UI.

Swagger UI

REST and HTTP APIs

Routing requests from port 2000 to api.predic8.de when the path starts with /shop/v2/.

<api port="2000">
    <path>/shop/v2/</path>
    <target url="https://api.predic8.de"/>
</api>

Call the API by opening http://localhost:2000/shop/v2/ in the browser.

Instrumentation

Open Telemetry

Using the openTelemetry plugin and the W3C propagation standard, we can integrate Membrane into OpenTelemetry traces. otel_example

Membrane together with a backend with database connection.

    <api port="2000">
        <openTelemetry sampleRate="1.0">
            <otlpExporter host="localhost" port="4317"/>
        </openTelemetry>
        <target host="localhost" port="3000"/>
    </api>

See the opentelemetry example

Message Transformation

Create JSON from Query Parameters

<api port="2000" method="GET">
    <request>
        <template contentType="application/json" pretty="yes">
            { "answer": ${params.answer} }
        </template>
    </request>
    <return statusCode="200"/>
</api>

Call this API with http://localhost:2000?answer=42 . Replace <return.../> with your <target url="backend-server"/>.

Transform JSON into TEXT, JSON or XML with Templates

Call the following APIs with this request:

curl -d '{"city":"Berlin"}' -H "Content-Type: application/json" "http://localhost:2000"

This template will transform the JSON input into plain text:

<api port="2000" method="POST">
    <request>
        <template contentType="text/plain">
            City: ${json.city}
        </template>
    </request>
    <return statusCode="200"/>
</api>

...into JSON:

<template contentType="application/json" pretty="true">
    {
    "destination": "${json.city}"
    }
</template>

...and into XML:

<template contentType="application/xml">
    <![CDATA[
    <places>
        <place>${json.city}</place>
    </places>
    ]]>
</template>

Transform XML into Text or JSON

Using the xpathExtractor you can extract values from XML request or response bodies and store it in properties. The properties are then available as variables in the template plugin.

<api port="2000">
    <request>
        <xpathExtractor>
            <property name="fn" xpath="person/@firstname"/>
        </xpathExtractor>
        <template>Buenas Noches, ${fn}sito!</template>
    </request>
    <return statusCode="200" contentType="text/plain"/>
</api>

See: message-transformation examples

Complex Transformations using Javascript or Groovy

Use the Javascript or Groovy plugin for more powerful yet simple transformations.

<api port="2000">
    <request>
        <javascript>
            ({ id:7, place: json.city })
        </javascript>
    </request>
    <return contentType="application/json"/>
</api>

Call the API with this curl command:

curl -d '{"city":"Berlin"}' -H "Content-Type: application/json" "http://localhost:2000"

Transformation with Computations

This script transforms the input and adds some calculations.

<api port="2000">
    <request>
        <javascript>

            function convertDate(d) {
            return d.getFullYear() + "-" + ("0"+(d.getMonth()+1)).slice(-2) + "-" + ("0"+d.getDate()).slice(-2);
            }

            ({
            id: json.id,
            date: convertDate(new Date(json.date)),
            client: json.customer,
            total: json.items.map(i => i.quantity * i.price).reduce((a,b) => a+b),
            positions: json.items.map(i => ({
            pieces: i.quantity,
            price: i.price,
            article: i.description
            }))
            })
        </javascript>
    </request>
    <return/>
</api>

See examples/javascript for a detailed explanation. The same transformation can also be realized with Groovy

Beautifier

You can beautify a JSON or XML using the <beautifier/> plugin.

<api port="2000">
    <template contentType="application/xml"><![CDATA[
        <foo><bar>baz</bar></foo>
    ]]></template>

    <beautifier/>

    <return statusCode="200"/>
</api>

Returns:

<foo>
    <bar>baz</bar>
</foo>

Branching and Conditionals

Conditionally modify response:

<api port="2000">
  <if test="header.contains('X-Demo')">
    <response>
      <groovy>
        exc.getResponse().setBodyContent("Example".getBytes())
      </groovy>
    </response>
  </if>
  <return/>
</api>

Check if certain scopes/roles are provided:

<api port="2000">
    <if test="hasScopes({'admin', 'webmaster'})" language="SpEL">
      <target url="https://localhost:2000/admin" />
    </if>
    <target host="localhost" port="1001" />
</api>

Writing Extensions with Groovy or Javascript

Dynamically manipulate and monitor messages with Groovy:

<api port="2000">
    <response>
        <groovy>
            header.add("X-Groovy", "Hello from Groovy!")
            println("Status: ${message.statusCode}")
            CONTINUE
        </groovy>
    </response>
    <target url="https://api.predic8.de"/>
</api>

Create a response with Javascript:

<api port="2000">
    <response>
        <javascript>
            var body = JSON.stringify({
            foo: 7,
            bar: 42
            });

            Response.ok(body).contentType("application/json").build();
        </javascript>
    </response>
    <return/> <!-- Do not forward, return immediately -->
</api>

Also try the Groovy and Javascript example.

Security

Membrane offers lots of security features to protect backend servers.

JSON Web Tokens

The API below only allows requests with valid tokens from Microsoft's Azure AD. You can also use the JWT validator for other identity providers.

<api port="8080">
    <jwtAuth expectedAud="api://2axxxx16-xxxx-xxxx-xxxx-faxxxxxxxxf0">
        <jwks jwksUris="https://login.microsoftonline.com/common/discovery/keys"/>
    </jwtAuth>
    <target url="https://your-backend"/>
</api>

OAuth2

Secure an API with OAuth2

Use OAuth2/OpenID to secure endpoints against Google, Azure AD, GitHub, Keycloak or Membrane authentication servers.

<api port="2001">
    <oauth2Resource>
        <membrane src="https://accounts.google.com"
                  clientId="INSERT_CLIENT_ID"
                  clientSecret="INSERT_CLIENT_SECRET"
                  scope="email profile"
                  subject="sub"/>
    </oauth2Resource>
    <groovy>
        // Get email from OAuth2 and forward it to the backend
        def oauth2 = exc.properties.oauth2
        header.setValue('X-EMAIL',oauth2.userinfo.email)
        CONTINUE
    </groovy>
    <target url="https://backend"/>
</api>

Try the tutorial OAuth2 with external OpenID Providers

Membrane as Authorization Server

Operate your own identity provider:

<api port="2000">
    <oauth2authserver location="logindialog" issuer="http://localhost:2000" consentFile="consentFile.json">
        <staticUserDataProvider>
            <user username="john" password="password" email="[email protected]"/>
        </staticUserDataProvider>
        <staticClientList>
            <client clientId="abc" clientSecret="def" callbackUrl="http://localhost:2001/oauth2callback"/>
        </staticClientList>
        <bearerToken/>
        <claims value="aud email iss sub username">
            <scope id="username" claims="username"/>
            <scope id="profile" claims="username email password"/>
        </claims>
    </oauth2authserver>
</api>

See the OAuth2 Authorization Server example.

Basic Authentication

<api port="2000">
    <basicAuthentication>
        <user name="bob" password="secret"/>
    </basicAuthentication>
    <target host="localhost" port="8080"/>
</api>

SSL/TLS

Route to SSL/TLS secured endpoints:

<api port="8080">
    <target url="https://api.predic8.de"/>
</api>

Secure endpoints with SSL/TLS:

<api port="443">
  <ssl>
    <keystore location="membrane.p12" password="secret" keyPassword="secret" />
    <truststore location="membrane.p12" password="secret" />
  </ssl>
  <target host="localhost" port="8080"  />
</api>

Rate Limiting

Limit the number of incoming requests:

<api port="2000">
    <rateLimiter requestLimit="3" requestLimitDuration="PT30S"/>
    <target host="localhost" port="8080"/>
</api>

Load balancing

Distribute workload to multiple backend nodes. See the example

<api port="8080">
    <balancer name="balancer">
        <clusters>
            <cluster name="Default">
                <node host="my.backend-1" port="4000"/>
                <node host="my.backend-2" port="4000"/>
                <node host="my.backend-3" port="4000"/>
            </cluster>
        </clusters>
    </balancer>
</api>

Rewrite URLs

<api port="2000">
    <rewriter>
        <map from="^/good-looking-path/(.*)" to="/backend-path/$1"/>
    </rewriter>
    <target host="my.backend.server"/>
</api>

Log HTTP

Log data about requests and responses to a file or database as CSV or JSON file.

<api port="2000">
    <log/> <!-- Logs to the console -->
    <statisticsCSV file="./log.csv"/> <!-- Logs fine-grained CSV -->
    <target url="https://api.predic8.de"/>
</api>

Websockets

Route and intercept WebSocket traffic:

<api port="2000">
    <webSocket url="http://my.websocket.server:1234">
        <wsLog/>
    </webSocket>
    <target port="8080" host="localhost"/>
</api>

See documentation

SOAP Web Services

Integrate legacy services.

API configuration from WSDL

SOAP proxies configure themselves by analysing WSDL:

<soapProxy wsdl="http://thomas-bayer.com/axis2/services/BLZService?wsdl"/>

Message Validation against WSDL and XSD

The validator checks SOAP messages against a WSDL document including referenced XSD schemas.

<soapProxy wsdl="http://thomas-bayer.com/axis2/services/BLZService?wsdl">
    <validator/>
</soapProxy>

See configuration reference for much more.

service-proxy's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

service-proxy's Issues

web app missing one more context-path

(as a web app)

  • if a load balancing is defined on a ServiceProxy, you clic on it to display the graphical view. On target you have a link to display the load balancing group : this link is not correct (missing relative path)

tomcat & exchange store

I don't know if it's linked with Tomcat install but, I use file exchange store and response messages are writen but not request.

ConfigurationException

As of now membrane throws Exception for illegal user configuration (proxies.xml). I suggest adding a ConfigurationException (I'm fine with extending checked Exception).

An example is AbstractProxy.java line 284:
throw new Exception("Unknown interceptor found: " + name);

This ex makes it up the tree to the user's face, without any wrapping. Configuration exceptions must include:

  1. the file name
  2. the line number

Somewhere up the stack someone must know from where the offending configuration is coming from, and can wrap this low level ex in a more verbose one.

Admin Console: Error Message for creating new Proxy

If you create a new proxy at localhost:9000 using the small form below the list of proxys and you use a port < 1024 without the priviledges you get an IncokationTargetException.

There should be a better message indicating that the port is already bound or that the user has no rights to open it.

Config Parsing: Better Error Message for Unknown Interceptor

You get a stacktrace plus:

09:08:36,897 ERROR HotDeploymentThread:58 - Could not redeploy proxies.xml
java.lang.Exception: Unknown interceptor found: admin

if you misspell an interceptor name. Maybe we can omit the stacktrace and add:

"Please check the spelling of your configuration. You will find a configuration reference at: http://"

The URL should point to the new location for the Membrane Service Proxy

Wrong Exception in HttpUtil

The following method is also used for reading HTTP header => The Exception should be changed or the name of the exception should be changed.

public static String readLine(InputStream in) throws IOException, EndOfStreamException {

    StringBuilder line = new StringBuilder(128);

    int b;
    while ((b = in.read()) != -1) {
        if (b == 13) {
            in.read();
            return line.toString();
        }

        line.append((char) b);
    }

    throw new ErrorReadingStartLineException(line.toString());
}

Web App: Add log4j.properties

A log4j.properties file is missing in the Web App. One should be in WEB-INF/classes to enable logging into e.g. Tomcat

JBoss AS 7 .sar deployment

add a jboss-deployment-structure.xml containing

    <dependencies>
        <module name="org.apache.commons.logging" />
    </dependencies>

and more

Take out NS-Prefixes from REST2SOAP JSON Response

Instead of:

{"ns1:getBankResponse":{"ns1:details":{"ns1:bezeichnung":"Raiffeisenbank Kraichgau","ns1:bic":"GENODE61KIR","ns1:ort":"Kirchardt","ns1:plz":74912}}}

return

{getBankResponse":{"details":{"bezeichnung":"Raiffeisenbank Kraichgau","bic":"GENODE61KIR","ort":"Kirchardt","plz":74912}}}

Documentation: interceptors.htm is outdated

This is about http://membrane-soa.org/esb-doc/3.5/interceptors.htm

There is probably more, but I find these 2 things urgent:

  • The listed Interceptor Interface is outdated. It certainly needs to list the very important handleAbort().
    One can always look at the code to see all the methods. On this page I would omit all the noise, and just list the three handle* methods.
  • Replace the text in the Lifecycle paragraph with a short text mentioning exc.setProperty() and exc.getProperty().

Automatically decode message bodies

gzip, compress, XOP should be realized as implicit decoders (instead of the current "MessageUtil.getContent(exc)") that are activated when calling getBodyAsStream, but not if the message is simply forwarded.

Service Proxy to predic8.com

A service proxy defined in the Web console using the add-Button is not working if the targethost is predic8.com but predic8.de works fine.

Exchange has two forms of getUri()

exc.getRequest().getUri() vs. exc.getRequestURI()
in my test request i get the exact same String value for both method calls.
but the code in those methods is different, they get the string in different ways. so i assume that under certain circumstances they don't return the same String?

both methods have no javadoc.

task: document why exc.getRequestURI() is needed, and in what way it differs.
alternatively, set it to deprecated and refer to exc.getRequest().getUri().

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.