Gradually move REST API

Use Apache mod_rewrite to move an API call by call to another implementation.

Loading the proxy_http module

If you tried to proxy rewrite and got the following error in the log file, chances are that the proxy_http_module was not loaded:

AH01144: No protocol handler was valid for the URL /api/tomove. If you are using a DSO version of mod_proxy, make sure the proxy submodules are included in the configuration using LoadModule.  

In order to use proxy rewrites (flag P), the proxy_http_module needs to be loaded. Find this line in the httpd.conf file:

#LoadModule proxy_http_module modules/mod_proxy_http.so

Remove the leading pound sign (#).
Restart the Apache server.

Redirect a certain API call

I have decided to move some of my REST API to be serviced by a Servlet, so I need to proxy the request to the same server, but on port 8080 and to the path:

examples/servlets/servlet/HelloWorldExample  

Tomcat conveniently comes with some example servlets, so rather than writing a servlet, I am just using an existing one, since I want to focus this article on the Apache mod_rewrite configuration.

I already have a .htaccess file in the /api folder in order to redirect all requests to the index.php file, like this:

RewriteEngine On  
Options FollowSymLinks  
RewriteBase /api/  
RewriteCond %{REQUEST_FILENAME} !index\.php$  
RewriteRule ^(.*)$ index.php?url=$1&%{QUERY_STRING} [L]  

This file says that if the requested filename does not end with index.php, the RewriteRule will step in and change the request such that it goes to the index.php file and passes the originally requested URL as the url query parameter.
The [L] flag says that this is the last rewrite rule.

Now let's proxy all GET requests to /api/administration/settings with this addition to the file:

RewriteCond %{REQUEST_URI} ^/api/administration/settings  
RewriteCond %{REQUEST_METHOD} GET  
RewriteRule ^(.*) "http://localhost:8080/examples/servlets/servlet/HelloWorldExample" [P,L]  

These additional lines have to be added in the beginning of the file.

We can verify that this works by making a GET request to http://localhost/api/administration/settings.

Setting host, scheme and port correctly

This is still not perfect, though. This only works if the host name of the server is indeed localhost. Let's fix this by using the Apache server variable HTTP_HOST:

RewriteRule ^(.*) "http://%{HTTP_HOST}:8080/examples/servlets/servlet/HelloWorldExample" [P,L]  

This is better, but still not perfect. The scheme of the request is http, but what if the original request was https, then we would also like the proxy request to use this scheme. Also we would want the port to follow, so that a secure connection would use port 8443 for instance.
Add the following in the beginning of the file to set some environment variables:

RewriteCond %{HTTPS} ^on$  
RewriteRule . - [E=SCHEME:https,E=PORT:8443]  
RewriteCond %{HTTPS} ^off$  
RewriteRule . - [E=SCHEME:http,E=PORT:8080]  

Now we can use those environment variable values later on:

RewriteRule ^(.*) "%{ENV:SCHEME}://%{HTTP_HOST}:%{ENV:PORT}/examples/servlets/servlet/HelloWorldExample" [P,L]