[Edgemicro] Handle error when calling a non-existent API Proxy

Hello All,

If i call an inexistent API proxy in Apigee Cloud, NO PLUG-INS are called, therefore NO HOOKS are called inside a custom-plug-in as well . EMG responds immediately with a 404:

{
  "message":"no match found for /plonk",
  "status":404
}


In this case I see no way to trigger some hook in a custom plug-in to handle it (By "handle it" I mean change the JSON response payload according to my business needs).

Is there any way to handle this response or simply I cannot?

Thanks!

Ciro

Solved Solved
1 6 1,293
1 ACCEPTED SOLUTION

Hello @Ciro Santos

That is correct, the Microgateway returns the 404 before any plugins are called. It will only handle requests for the base paths specified in Edge micro-aware proxies. An Edge micro-aware proxy is defined in Edge and prefixed with "edgemicro_".

You can see the allowed base paths in the org-env-cache-config.yaml file under the proxies section.

proxies:
  - max_connections: 1000
    name: edgemicro_lab_hello
    revision: '1'
    proxy_name: default
    base_path: /edgemicro_lab
    target_name: default
    url: 'http://localhost:8090'
  - max_connections: 1000
    name: edgemicro_lab_twoway_tls
    revision: '6'
    proxy_name: default
    base_path: /edgemicro_lab_ssl
    target_name: default
    url: 'https://localhost:9443'
  - max_connections: 1000
    name: edgemicro_weather
    revision: '1'
    proxy_name: default
    base_path: /edgemicro_weather
    target_name: default
    url: 'http://weather.yahooapis.com'

However, there is a way to configure the Microgateway to handle unknown requests. Setup a new Edge micro-aware proxy that has a base path of "/", then the Microgateway will handle the request and you can create a custom plugin to return a 404 with an alternate payload. You can see from the trace below that the proxy plugins execute when I send a request with /2articles, which does not exist in my proxies section.

gateway:main selected proxy https://weather.yahoo.com with base path / for request path /2articles/articlesearch.json +12s

gateway:main sourceRequest +5ms c-11e7-9eac-7f575730dec6 GET /2articles/articlesearch.json?q=tesat&api-key=key
  
plugin:oauth api key cache miss 123 +12s
plugin:oauth verify apikey access_denied +229ms
plugin:oauth auth failure 403 access_denied Unauthorized { host: 'localhost:8000',
  'user-agent': 'curl/7.43.0',
  accept: '*/*',
  'x-api-key2': '123' } GET /2articles/articlesearch.json?q=test&api-key=key +1ms

gateway:errors access_denied +245ms
analytics flushing 1 records. 0 records remaining. +28ms

However, when I send a request for /edgemicro_lab the correct target is located.

gateway:main selected proxy http://localhost:8090 with base path /edgemicro_lab for request path /edgemicro_lab/hello +2s

gateway:main sourceRequest +2ms 35cbb680-04ee-11e7-bb92-e3b1164c4585 GET /edgemicro_lab/hello
plugin:plugin1 plugin-1: onrequest +2s
plugin:plugin2 plugin-2: onrequest +0ms
gateway:main targetRequest +7ms 35cbb680-04ee-11e7-bb92-e3b1164c4585 GET localhost 8090 /hello

I would suggest that if you try this approach you should perform a significant amount of testing to ensure that all requests to the Microgateway are handled correctly.

View solution in original post

6 REPLIES 6

Hello @Ciro Santos

That is correct, the Microgateway returns the 404 before any plugins are called. It will only handle requests for the base paths specified in Edge micro-aware proxies. An Edge micro-aware proxy is defined in Edge and prefixed with "edgemicro_".

You can see the allowed base paths in the org-env-cache-config.yaml file under the proxies section.

proxies:
  - max_connections: 1000
    name: edgemicro_lab_hello
    revision: '1'
    proxy_name: default
    base_path: /edgemicro_lab
    target_name: default
    url: 'http://localhost:8090'
  - max_connections: 1000
    name: edgemicro_lab_twoway_tls
    revision: '6'
    proxy_name: default
    base_path: /edgemicro_lab_ssl
    target_name: default
    url: 'https://localhost:9443'
  - max_connections: 1000
    name: edgemicro_weather
    revision: '1'
    proxy_name: default
    base_path: /edgemicro_weather
    target_name: default
    url: 'http://weather.yahooapis.com'

However, there is a way to configure the Microgateway to handle unknown requests. Setup a new Edge micro-aware proxy that has a base path of "/", then the Microgateway will handle the request and you can create a custom plugin to return a 404 with an alternate payload. You can see from the trace below that the proxy plugins execute when I send a request with /2articles, which does not exist in my proxies section.

gateway:main selected proxy https://weather.yahoo.com with base path / for request path /2articles/articlesearch.json +12s

gateway:main sourceRequest +5ms c-11e7-9eac-7f575730dec6 GET /2articles/articlesearch.json?q=tesat&api-key=key
  
plugin:oauth api key cache miss 123 +12s
plugin:oauth verify apikey access_denied +229ms
plugin:oauth auth failure 403 access_denied Unauthorized { host: 'localhost:8000',
  'user-agent': 'curl/7.43.0',
  accept: '*/*',
  'x-api-key2': '123' } GET /2articles/articlesearch.json?q=test&api-key=key +1ms

gateway:errors access_denied +245ms
analytics flushing 1 records. 0 records remaining. +28ms

However, when I send a request for /edgemicro_lab the correct target is located.

gateway:main selected proxy http://localhost:8090 with base path /edgemicro_lab for request path /edgemicro_lab/hello +2s

gateway:main sourceRequest +2ms 35cbb680-04ee-11e7-bb92-e3b1164c4585 GET /edgemicro_lab/hello
plugin:plugin1 plugin-1: onrequest +2s
plugin:plugin2 plugin-2: onrequest +0ms
gateway:main targetRequest +7ms 35cbb680-04ee-11e7-bb92-e3b1164c4585 GET localhost 8090 /hello

I would suggest that if you try this approach you should perform a significant amount of testing to ensure that all requests to the Microgateway are handled correctly.

Thanks @swilliams I will implement this!


Hey @swilliams this was very helpful! I implemented and is working real nice! Thanks

anarjinary
Participant II

hi @Ciro @swilliams

Could you please share the custom plugin code to capture the error and write alternate payload back to client as discussed here.

I am trying to look for error handing patterns for edgemicro but unable to get any, so the code on this context would also be really helpful.

Thanks.

Hello @anarjinary@wiley.com,

Regarding this specific topic, here is what I did:

1) Create an API proxy in Apigee Cloud called edgemicro_error with the values:

Base path:
<BasePath>/</BasePath>

and target:
<HTTPTargetConnection>
    <Properties/>
    <URL>http://emgerror</URL>
</HTTPTargetConnection>

Then created a custom plugin (In my case I already had a error plugin, so I only added the following lines):

//function that executes on request...
function _onRequest (req, res, next) {
  debug('Error mapping plugin invoked on request.')

  if (req.targetHostname && req.targetHostname === 'emgerror') {
    var notFound = 404
    res.statusCode = notFound
    res.setHeader('content-type', 'application/json')
    _createErrorPayload(notFound, 'No such API proxy was found in Apigee Cloud', _errorMessageCodeUrn)
  }

  next()
}

//function that handles the error part (in my case generate a proper json payload)
function _createErrorPayload (statusCode, message, messageCode) {
  message = message || _jsonStdErrorMsgs[statusCode]

  var customField = {
    statusCode: statusCode
  }

  if (messageCode) {
    messageCode += ':' + statusCode
    customField['messageCode'] = messageCode
  }
  throw new StandardError(message, customField)
}

//init function that enables onrequest hook calling my _onRequest function
module.exports.init = function (config, logger) { 
  return {
    onrequest: function (req, res, next) {          
        try {
          _onRequest(req, res, next)
        } catch (error) {
          _processError(error, next)
        }      
    }   
  }
}

Hope this helps!

Ciro

hi @Ciro Santos ,
Thanks, it helped.