Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fetch information from an API before sending the request upstream

Tags:

nginx

Is it possible to send a http subrequest in a location block and use the response in the proxy_pass directive?

use case

My upstream application needs some additional information from an API. I've written a location block that proxies request with the proxy_pass directive. Before nginx sends the request to my application. I'd like to send an HTTP request to my API and use several response headers as request headers to my application.

This is the outline of what I want to achieve:

server {
  server_name ...;
  location {
    # perform subrequest to fetch additional information from an api

    proxy_pass myapplication;

    proxy_set_header X-Additional-Info "some information from the subrequest";
  }

}

The behaviour is similar to the auth_request module. However, I can't find documentation of sending an additional blocking HTTP request before inside a location block using standard nginx configuration.

like image 256
Thomas Avatar asked Jan 19 '18 19:01

Thomas


1 Answers

You can't do it using regular nginx directives but it's quite easy using lua-nginx-module.

This module embeds Lua, via the standard Lua 5.1 interpreter or LuaJIT 2.0/2.1, into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model.

Here's how to accomplish what you need:

  1. create a directory conf.d/
  2. put 2 files test.conf and header.lua into it (see the contents below)
  3. docker run -p8080:8080 -v your_path/conf.d:/etc/nginx/conf.d openresty/openresty:alpine
  4. curl http://localhost:8080/

test.conf

  server {
    listen 8080;

    location /fetch_api {
        # this is a service echoing your IP address   
        proxy_pass http://api.ipify.org/;
    }

    location / {
        set $api_result "";
        access_by_lua_file /etc/nginx/conf.d/header.lua;
        proxy_set_header X-Additional-Info $api_result;
        # this service just prints out your request headers
        proxy_pass http://scooterlabs.com/echo;
    }
}

header.lua

local res = ngx.location.capture('/fetch_api', { method = ngx.HTTP_GET, args = {} });

ngx.log(ngx.ERR, res.status);
if res.status == ngx.HTTP_OK then
  ngx.var.api_result = res.body;
else
  ngx.exit(403);
end

results

curl http://localhost:8080/
Simple webservice echo test: make a request to this endpoint to return the HTTP request parameters and headers. Results available in plain text, JSON, or XML formats. See http://www.cantoni.org/2012/01/08/simple-webservice-echo-test for more details, or https://github.com/bcantoni/echotest for source code.

Array
(
    [method] => GET
    [headers] => Array
        (
            [X-Additional-Info] => my-ip-address
            [Host] => scooterlabs.com
            [Connection] => close
            [User-Agent] => curl/7.43.0
            [Accept] => */*
        )

    [request] => Array
        (
        )

    [client_ip] => my-ip-address
    [time_utc] => 2018-01-23T19:25:56+0000
    [info] => Echo service from Scooterlabs (http://www.scooterlabs.com)
)

Notice the X-Additional-Info header populated with the data obtained in /fetch_api handler

like image 192
ffeast Avatar answered Oct 02 '22 03:10

ffeast