Block undefined routes/paths in apigee - apigee

I have a proxy defined in Apigee with an end point which has quite a few different controllers and paths. I only want to expose 2 of these via apigee (a get and post). I can't work out how to stop anyone else being able to access the other endpoints through the apigee proxy.
Anyone able to help?

Just to confirm I understand your requirement right, the target API exposes multiple paths. Of all those paths, you would want to expose 2(GET and POST) paths via Apigee to your consumers.
This can be done using conditional flows. Create three conditional flows in your proxy endpoint. Two conditional flows for two paths you would want to expose. You may use combination of paths and HTTP verbs in the Condition tag.
Use the third conditional flow without any conditions as a catch all block. You can use the raise fault policy in the third conditional flow to return appropriate error to the consumer.
Your proxy endpoint should look something like this -
<Flows>
<Flow name="get-resource">
<Description>Get resource</Description>
<Request/>
<Response/>
<Condition>(proxy.pathsuffix MatchesPath "/resource") and (request.verb = "GET")</Condition>
</Flow>
<Flow name="post-resource">
<Description>Create resource</Description>
<Request/>
<Response/>
<Condition>(proxy.pathsuffix MatchesPath "/resource") and (request.verb = "POST")</Condition>
</Flow>
<Flow name="Unknown Resource">
<Description>Unknown resource</Description>
<Request>
<Step>
<Name>RaiseFault-UnknownResource</Name>
</Step>
</Request>
<Response/>
</Flow>
</Flows>
And the raise fault policy would look something like this -
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<RaiseFault async="false" continueOnError="false" enabled="true" name="RaiseFault-UnknownResource">
<DisplayName>RaiseFault-UnknownResource</DisplayName>
<Properties/>
<FaultResponse>
<Set>
<Headers/>
<Payload contentType="text/plain">Resource not found</Payload>
<StatusCode>404</StatusCode>
<ReasonPhrase>Not Found</ReasonPhrase>
</Set>
</FaultResponse>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</RaiseFault>
If this is not the requirement please clarify it and I'll try and update the answer accordingly.

Related

How to set full url dynamically in http request connector in Mule

As shown in this question, it is possible to have parts of the url in variables, when requesting an http endpoint with mule.
But I have a full url, returned from an endpoint supporting hateoas. Is it possible to use this full url for requests without splitting it up into several parts (host, port, path)?
With full url I mean sth. like "http://example.com/a/specific/path" instead of host="example.com", port="80", path="/a/specific/path"
One simple way to do is to split the url into multiple parts and set it into a flow variables. Then you can use this flow variables anywhere you want.
An simple example to do it is as follows:-
<http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="8081" doc:name="HTTP Listener Configuration"/>
<flow name="csv-to-smtpFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/aa" doc:name="HTTP"/>
<logger message="#[payload]" level="INFO" doc:name="Logger"/>
<set-payload value="http://example.com:80/a/specific/path" doc:name="Set Payload"/>
<set-variable variableName="url" value="#[new URL(payload);]" doc:name="Variable"/>
<set-variable variableName="protocol" value="#[url.getProtocol();]" doc:name="Variable"/>
<set-variable variableName="host" value="#[url.getHost();]" doc:name="Variable"/>
<set-variable variableName="port" value="#[url.getPort();]" doc:name="Variable"/>
<set-variable variableName="path" value="#[url.getPath();]" doc:name="Variable"/>
<logger message="Done" level="INFO"/>
</flow>
Here you can see I am setting the url http://example.com:80/a/specific/path in a payload and then splitting it into host, port, path etc and storing it in variables.
Pls note if your url is in the form http://example.com:80/a/specific/path, you will get the port using expression #[url.getProtocol();]
But if your url is in the form http://example.com/a/specific/path, you will not get the port number.
Ref:- https://docs.oracle.com/javase/tutorial/networking/urls/urlInfo.html

how can we call a http servlet from mule?

I have a requirement in which i need to call a servlet from mule flow.I got one answer from the below site
http://mule.1045714.n5.nabble.com/Creating-query-string-for-calling-a-servlet-td2665836.html
But when i copy that code in my flow it is showing some errors in flow. Is there any other method or solution to call servlet from mule. I have servlet URL and username and password. I am using mule 3.5 anypoint studio. Please help me in completing this task
EDIT: (Pasted from a comment from the OP)
<flow name="CallServletServiceFlow1" doc:name="CallServletServiceFlow1">
<http:inbound-endpoint exchange-pattern="request-response" doc:name="HTTP" address="localhost:8080/servlet"/>
<object-to-string-transformer doc:name="Object to String"/>
<http:outbound-endpoint exchange-pattern="request-response" user="javauser" password="javauser1" method="GET" doc:name="HTTP" address="servlet/customTaskServlet?" connector-ref="HTTP_HTTPS"/>
</flow>
You seem to be copying old Mule 2 syntax in Mule 3, so this can not work.
Just use a simple HTTP outbound endpoint in your flow.
Reference: http://www.mulesoft.org/documentation/display/current/HTTP+Transport+Reference
EDIT: If you use the address attribute in HTTP endpoints (instead of the host port and path), you need to specify the scheme. So for example, you should replace address="localhost:8080/servlet" with address="http://localhost:8080/servlet".

Apigee RouteRule evaluates correctly but then returns a 503

I have two Resources set up for my API proxy and have a route rule named talkback that should take POST requests to my /matches API resource and route them to my talkback subdomain rather than www.
I have this working correctly for GET requests that redirect to my open subdomain. However the talkback rule correctly evaluates but then returns a 503 without reaching my target endpoint:
error The Service is temporarily unavailable
error.cause Connection refused
error.class com.apigee.messaging.adaptors.http.HttpAdaptorException
state TARGET_REQ_FLOW
type ErrorPoint
Are you able to advise on what may be the issue?
This is the route rule I'm using:
<RouteRule name="talkback">
<Condition>(proxy.pathsuffix MatchesPath "/matches/**") and (request.verb equals "POST")</Condition>
<TargetEndpoint>talkback</TargetEndpoint>
</RouteRule>
This is the talkback target endpoint:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<TargetEndpoint name="talkback">
<Description/>
<FaultRules/>
<Flows/>
<HTTPTargetConnection>
<Properties/>
<URL>http://talkback.test.xxxx.co.uk/gapi</URL>
</HTTPTargetConnection>
<PreFlow name="PreFlow">
<Request/>
<Response/>
</PreFlow>
<PostFlow name="PostFlow">
<Request/>
<Response/>
</PostFlow>
</TargetEndpoint>
This pretty much looks like an issue where Apigee is not able to connect to your target backend - http://talkback.test.xxxx.co.uk. Apigee throws a 503 back to the client when its unable to connect to the backend. Is the backend publicly accessible?

Calling a GET on the Apigee HTTPTargetConnection when the request was POST

I need to call a legacy API which uses GET.
My API proxy uses POST.
I tried using in AssignMessage:
<AssignTo type="request" createNew="false"/>
and
<Set> ... <Verb>GET</Verb>
But it still does a POST on the target API.
What is the proper way of converting?
Will the gateway automatically convert the POST form parameters into GET query parameters?
Is message.queryparam the same for both GET and POST?
When converting the Verb from POST to GET, the policy will NOT automatically convert the form parameters to query parameters. You will need to use the <Add> and/or <Remove> functionality of the AssignMessage policy to manipulate the message further. Example use in the AssignMessage policy to add the queryparams, referencing the formparams:
<Add>
<QueryParams>
<QueryParam name="q1">{request.formparam.q1}</QueryParam>
</QueryParams>
</Add>
Also, in your question you mentioned that the API Proxy accepts the request using method as POST. Then, you have a policy to set GET:
<Set> ... <Verb>GET</Verb>
But it still does a GET on the target API.
What's the problem? Isn't that what you are expecting? The request goes into the Apigee API Proxy as POST, the proxy converts the method (verb) to GET, and sends the request to the backend legacy API using GET.
Note: <AssignTo> is optional in the AssignMessage. Try leaving this out if the method is not being set properly. In its absence, the message at the current point in the flow will be modified.
Change this predefined variable to post
request.verb = "GET"
Note: If you do this and you have a flow condition based on request.verb="POST" that will not work well in the response. So you need to use another variable to use in the flow condition.
Here is the policy code that worked for me.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="changeverbassignmessage">
<DisplayName>ChangeVerbAssignMessage</DisplayName>
<FaultRules/>
<Properties/>
<AssignVariable>
<Name>request.verb</Name>
<Value>GET</Value>
<Ref/>
</AssignVariable>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>

Is there a way to poll several addresses using Mule's HttpPollingConnector?

I am trying to poll several addresses (URL links) from a list that contains all these addresses using the http polling connector in Mule. Currently, I am only able to poll from one address but I would like to find a way to use this list to iterate the polling for each site. Is there anything built within Mule that provides such function?
Is composite source what you're looking for? It allows you to have more than one endpoint in the inbound.
e.g. from http://www.mulesoft.org/documentation-3.2/display/32X/Bookstore+Example
<flow name="CatalogService">
<composite-source>
<!-- Public interface -->
<inbound-endpoint address="http://0.0.0.0:8777/services/catalog" exchange-pattern="request-response">
<cxf:jaxws-service serviceClass="org.mule.example.bookstore.CatalogService" />
</inbound-endpoint>
<!-- Administration interface -->
<inbound-endpoint address="servlet://catalog" exchange-pattern="request-response">
<!-- Convert request parameters to Book object -->
<custom-transformer class="org.mule.example.bookstore.transformers.HttpRequestToBook" />
<response>
<!-- Format response to be a nice HTML page -->
<custom-transformer class="org.mule.example.bookstore.transformers.AddBookResponse" />
<!-- Force text/html, otherwise it falls back to request
props, which have form-encoded one -->
<transformer ref="setHtmlContentType" />
</response>
</inbound-endpoint>
</composite-source>
....
Edit:
The following is a simple foreach example:
<flow name="foreachFlow1" doc:name="foreachFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" doc:name="HTTP"/>
<foreach collection="#[groovy:['localhost:8082', 'localhost:8083']]" doc:name="For Each">
<http:outbound-endpoint exchange-pattern="request-response" address="http://#[payload]" method="GET" doc:name="HTTP"/>
</foreach>
</flow>
<flow name="foreachFlow2" doc:name="foreachFlow2">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8082" doc:name="HTTP"/>
<logger message="in flow2" level="INFO"/>
</flow>
<flow name="foreachFlow3" doc:name="foreachFlow3">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8083" doc:name="HTTP"/>
<logger message="in flow3" level="INFO"/>
</flow>
Basically, the 'tricky' part is to figure out that the payload becomes the current item in the collection you're iterating over (the docs do a wonderful job at pointing that out... well at least if you're into fishing :P).

Resources