Unable to get js middleware to load

Hi all!

I’m working on an API POC at work and I’m currently testing out Tyk for this purpose. I have installed and gotten the Tyk Pro Windows Docker Demo running and functional and am able to proxy requests from our application.

I am currently running into issues trying to get the JS middleware functional so I can test some functionality out with it.

JSVM setting is enabled. I have created the ./middleware/{api-id}/post and pre folders and I have copied the example NewProcess request called test and named the file test.js. It has the simple console.log in it to verify that it is initialized but it is never logged to the terminal.

I have looked around through the documentation and here on the forums and most issues were with people not having the JSVM setting set to true. I don’t get any errors so I don’t have much to go on.

Any help is much appreciated! Thanks!

Hi Chris,

I spent some time with custom middlewares last week, and I’d be happy to help you with this. Could you attach a copy of the relevant configurations? (tyk.conf, the exported API config, and the relevant .js files?) In addition, could you send the folder structure you’ve created?

Nathan

Thank you!

tyk.conf

{
  "listen_address": "",
  "listen_port": 8080,
  "secret": "352d20ee67be67f6340b4c0605b044b7",
  "node_secret": "352d20ee67be67f6340b4c0605b044b7",
  "template_path": "./templates",
  "tyk_js_path": "./js/tyk.js",
  "middleware_path": "./middleware",
  "policies": {
    "policy_source": "service",
    "policy_connection_string": "http ://tyk-dashboard:3000",
    "policy_record_name": "tyk_policies",
    "allow_explicit_policy_id": true
  },
  "use_db_app_configs": true,
  "db_app_conf_options": {
    "connection_string": "http ://tyk-dashboard:3000",
    "node_is_segmented": false,
    "tags": [
      "test"
    ]
  },
  "disable_dashboard_zeroconf": false,
  "app_path": "./test_apps/",
  "storage": {
    "type": "redis",
    "host": "tyk-redis",
    "port": 6379,
    "hosts": null,
    "username": "",
    "password": "",
    "database": 0,
    "optimisation_max_idle": 3000,
    "optimisation_max_active": 5000,
    "enable_cluster": false
  },
  "enable_separate_cache_store": false,
  "enable_analytics": true,
  "analytics_config": {
    "type": "mongo",
    "ignored_ips": [],
    "enable_detailed_recording": false,
    "enable_geo_ip": false,
    "geo_ip_db_path": "./GeoLite2-City.mmdb",
    "normalise_urls": {
      "enabled": true,
      "normalise_uuids": true,
      "normalise_numbers": true,
      "custom_patterns": []
    }
  },
  "health_check": {
    "enable_health_checks": false,
    "health_check_value_timeouts": 0
  },
  "optimisations_use_async_session_write": true,
  "allow_master_keys": false,
  "hash_keys": true,
  "suppress_redis_signal_reload": false,
  "suppress_default_org_store": false,
  "use_redis_log": true,
  "sentry_code": "",
  "use_sentry": false,
  "use_syslog": false,
  "use_graylog": false,
  "use_logstash": false,
  "graylog_network_addr": "",
  "logstash_network_addr": "",
  "syslog_transport": "",
  "logstash_transport": "",
  "syslog_network_addr": "",
  "enforce_org_data_age": true,
  "enforce_org_data_detail_logging": false,
  "enforce_org_quotas": true,
  "experimental_process_org_off_thread": false,
  "enable_non_transactional_rate_limiter": true,
  "enable_sentinel_rate_limiter": false,
  "Monitor": {
    "enable_trigger_monitors": false,
    "configuration": {
      "method": "",
      "target_path": "",
      "template_path": "",
      "header_map": null,
      "event_timeout": 0
    },
    "global_trigger_limit": 0,
    "monitor_user_keys": false,
    "monitor_org_keys": false
  },
  "oauth_refresh_token_expire": 0,
  "oauth_token_expire": 0,
  "oauth_redirect_uri_separator": ";",
  "slave_options": {
    "use_rpc": false,
    "connection_string": "",
    "rpc_key": "",
    "api_key": "",
    "enable_rpc_cache": false,
    "bind_to_slugs": false,
    "disable_keyspace_sync": false,
    "group_id": ""
  },
  "disable_virtual_path_blobs": false,
  "local_session_cache": {
    "disable_cached_session_state": true,
    "cached_session_timeout": 0,
    "cached_session_eviction": 0
  },
  "http_server_options": {
    "override_defaults": false,
    "read_timeout": 0,
    "write_timeout": 0,
    "use_ssl": false,
    "use_ssl_le": false,
    "enable_websockets": true,
    "certificates": [],
    "server_name": "",
    "min_version": 0,
    "flush_interval": 0
  },
  "service_discovery": {
    "default_cache_timeout": 0
  },
  "close_connections": false,
  "auth_override": {
    "force_auth_provider": false,
    "auth_provider": {
      "name": "",
      "storage_engine": "",
      "meta": null
    },
    "force_session_provider": false,
    "session_provider": {
      "name": "",
      "storage_engine": "",
      "meta": null
    }
  },
  "uptime_tests": {
    "disable": true,
    "config": {
      "failure_trigger_sample_size": 1,
      "time_wait": 2,
      "checker_pool_size": 50,
      "enable_uptime_analytics": true
    }
  },
  "hostname": "",
  "enable_api_segregation": false,
  "control_api_hostname": "",
  "enable_custom_domains": true,
  "enable_jsvm": true,
  "enable_coprocess": false,
  "hide_generator_header": false,
  "event_handlers": {
    "events": {}
  },
  "event_trigers_defunct": {},
  "pid_file_location": "./tyk-gateway.pid",
  "allow_insecure_configs": true,
  "public_key_path": "",
  "close_idle_connections": false,
  "allow_remote_config": true,
  "enable_bundle_downloader": false,
  "max_idle_connections_per_host": 500
}

API Definition

{
  "api_model": {},
  "api_definition": {
    "api_id": "24a942a26df34d6c7a5de62a44bd3c84",
    "jwt_issued_at_validation_skew": 0,
    "upstream_certificates": {},
    "use_keyless": true,
    "enable_coprocess_auth": false,
    "base_identity_provided_by": "",
    "custom_middleware": {
      "pre": [],
      "post": [],
      "post_key_auth": [],
      "auth_check": {
        "name": "",
        "path": "",
        "require_session": false
      },
      "response": [],
      "driver": "",
      "id_extractor": {
        "extract_from": "",
        "extract_with": "",
        "extractor_config": {}
      }
    },
    "disable_quota": false,
    "custom_middleware_bundle": "",
    "cache_options": {
      "cache_timeout": 0,
      "enable_cache": false,
      "cache_all_safe_requests": false,
      "cache_response_codes": [],
      "enable_upstream_cache_control": false,
      "cache_control_ttl_header": ""
    },
    "enable_ip_blacklisting": false,
    "tag_headers": [],
    "pinned_public_keys": {},
    "expire_analytics_after": 0,
    "domain": "",
    "openid_options": {
      "providers": [],
      "segregate_by_client": false
    },
    "jwt_policy_field_name": "",
    "jwt_default_policies": [],
    "active": true,
    "jwt_expires_at_validation_skew": 0,
    "config_data": {},
    "notifications": {
      "shared_secret": "",
      "oauth_on_keychange_url": ""
    },
    "jwt_client_base_field": "",
    "auth": {
      "use_param": false,
      "param_name": "",
      "use_cookie": false,
      "cookie_name": "",
      "auth_header_name": "",
      "use_certificate": false,
      "validate_signature": false,
      "signature": {
        "algorithm": "",
        "header": "",
        "secret": "",
        "allowed_clock_skew": 0,
        "error_code": 0,
        "error_message": ""
      }
    },
    "check_host_against_uptime_tests": false,
    "auth_provider": {
      "name": "",
      "storage_engine": "",
      "meta": {}
    },
    "blacklisted_ips": [],
    "hmac_allowed_clock_skew": -1,
    "dont_set_quota_on_create": false,
    "uptime_tests": {
      "check_list": [],
      "config": {
        "expire_utime_after": 0,
        "service_discovery": {
          "use_discovery_service": false,
          "query_endpoint": "",
          "use_nested_query": false,
          "parent_data_path": "",
          "data_path": "",
          "cache_timeout": 60
        },
        "recheck_wait": 0
      }
    },
    "enable_jwt": false,
    "do_not_track": false,
    "name": "frapipoc",
    "slug": "first-rate-poc",
    "oauth_meta": {
      "allowed_access_types": [],
      "allowed_authorize_types": [],
      "auth_login_redirect": ""
    },
    "CORS": {
      "enable": false,
      "max_age": 0,
      "allow_credentials": false,
      "exposed_headers": [],
      "allowed_headers": [],
      "options_passthrough": false,
      "debug": false,
      "allowed_origins": [],
      "allowed_methods": []
    },
    "event_handlers": {
      "events": {}
    },
    "proxy": {
      "target_url": "https ://wf82.firstrate.com/ibi_apps/WFServlet.ibfs",
      "service_discovery": {
        "endpoint_returns_list": false,
        "cache_timeout": 0,
        "parent_data_path": "",
        "query_endpoint": "",
        "use_discovery_service": false,
        "_sd_show_port_path": false,
        "target_path": "",
        "use_target_list": false,
        "use_nested_query": false,
        "data_path": "",
        "port_data_path": ""
      },
      "check_host_against_uptime_tests": false,
      "transport": {
        "ssl_insecure_skip_verify": false,
        "ssl_ciphers": [],
        "ssl_min_version": 0,
        "proxy_url": ""
      },
      "target_list": [],
      "preserve_host_header": false,
      "strip_listen_path": true,
      "enable_load_balancing": false,
      "listen_path": "/api/",
      "disable_strip_slash": false
    },
    "client_certificates": [],
    "use_basic_auth": false,
    "version_data": {
      "not_versioned": true,
      "default_version": "",
      "versions": {
        "Default": {
          "name": "Default",
          "expires": "",
          "paths": {
            "ignored": [],
            "white_list": [],
            "black_list": []
          },
          "use_extended_paths": true,
          "global_headers": {},
          "global_headers_remove": [],
          "global_size_limit": 0,
          "override_target": "",
          "extended_paths": {
            "transform_headers": [],
            "transform_response_headers": [
              {
                "delete_headers": [],
                "add_headers": {
                  "Content-Type": "application/json"
                },
                "path": "/reports/pml",
                "method": "GET",
                "act_on": false
              }
            ],
            "url_rewrites": [
              {
                "path": "/reports/pml",
                "method": "GET",
                "match_pattern": "/reports/pml?(.*)",
                "rewrite_to": "?IBIF_ex=FRPNADA&USE_RC=Y&PROGRAM=FRAPIGetAccountPML&FRPAPI=Y&CLIENT=DV2764&FRP_ROOT=FRP&FRP_VERSION=64&FRP_SUITE=ADV$1",
                "triggers": [],
                "MatchRegexp": null
              }
            ],
            "track_endpoints": [
              {
                "path": "/reports/pml",
                "method": "GET"
              }
            ]
          }
        }
      }
    },
    "use_standard_auth": false,
    "session_lifetime": 0,
    "hmac_allowed_algorithms": [],
    "disable_rate_limit": false,
    "definition": {
      "location": "header",
      "key": "version",
      "strip_path": false
    },
    "use_oauth2": false,
    "jwt_source": "",
    "jwt_signing_method": "",
    "jwt_not_before_validation_skew": 0,
    "jwt_identity_base_field": "",
    "allowed_ips": [],
    "org_id": "5d30917606f0d80001b85035",
    "enable_ip_whitelisting": false,
    "global_rate_limit": {
      "rate": 0,
      "per": 0
    },
    "enable_context_vars": true,
    "tags": [],
    "basic_auth": {
      "disable_caching": false,
      "cache_ttl": 0,
      "extract_from_body": false,
      "body_user_regexp": "",
      "body_password_regexp": ""
    },
    "session_provider": {
      "name": "",
      "storage_engine": "",
      "meta": {}
    },
    "strip_auth_data": false,
    "id": "5d35a71a06f0d80001b8503c",
    "certificates": [],
    "enable_signature_checking": false,
    "use_openid": false,
    "internal": false,
    "jwt_skip_kid": false,
    "enable_batch_request_support": false,
    "response_processors": [
      {
        "name": "header_injector",
        "options": {}
      }
    ],
    "use_mutual_tls_auth": false
  },
  "hook_references": [],
  "is_site": false,
  "sort_by": 0,
  "user_group_owners": [],
  "user_owners": []
}

test.js
/* — test.js — */

// Create your middleware object
var test = new TykJS.TykMiddleware.NewMiddleware({});

// Initialise it with your functionality by passing a closure that accepts two objects
// into the NewProcessRequest() function:
test.NewProcessRequest(function(request, session, spec) {

  console.log("This middleware does nothing, but will print this to your terminal.")

  // You MUST return both the request and session metadata    
  return test.ReturnData(request, session.meta_data);
});

image

Hey! Sorry for the late reply, Chris. I’m going to try this out tonight or tomorrow and see what I can find, then I’ll report back here!

Thanks so much! I feel like it might be related to the folder structure, since this is with the Docker demo (which I’m not experienced with at the moment). I have no idea where else I might place the middleware folder if not for here though.

Hi Chris,

What you’ve done looks good, but it seems like you haven’t set up the jsvm middleware in your API definition. Take a look at this section of your API definition:

"custom_middleware": {
  "pre": [],
  "post": [],
  "post_key_auth": [],
  "auth_check": {
    "name": "",
    "path": "",
    "require_session": false
  },
  "response": [],
  "driver": "",
  "id_extractor": {
    "extract_from": "",
    "extract_with": "",
    "extractor_config": {}
  }
}

And compare it to the ‘Enable the JSVM’ section here:

https://tyk.io/docs/customise-tyk/plugins/javascript-middleware/install-middleware/tyk-ce/

Let me know if that helps you!

Another question – is there a reason you’ve decided to go with the JSVM to extend the product rather than, for example, using one of our coprocess interpreters or gRPC?

From what I understood from the documentation here, setting up the “custom_middleware” here is only relevant to the CE. The pro/on-premise version needs to be defined in the file structure.

My theory is that since I am running through Docker that I have my “middleware” folder in the wrong location and it is not being detected, but I don’t know where else I would put it as this is the only Tyk folder I have setup and running on my machine.

(I just tried adding the file to my middleware definition and I repeatedly receieve an error “Failed to open JS middleware file”. I’ve tried several different paths and locations. This is leading me even more to believe the Docker file location theory above)

I don’t think I’m familiar with the coprocess interpreter or gRPC, but I see it in the documentation now that you have mentioned it. Would it be preferable to use these instead of the JSVM?

Essentially what I’m trying to accomplish is a couple things:

  1. Route traffic to different servers/URLs with different params based on requesting client.
  2. Catch invalid responses from our back end (essentially an HTML error page) and instead return a proper JSON error response.

As I get deeper in the project there may be more use cases, but these are the 2 currently I am investigating usage of the middleware to address.

Thank you for your help!