RequestRocket Documentation
Guides

Client Application Integration

Step-by-step guide for integrating RequestRocket into your client application

Client Application Integration

This guide will walk you through integrating RequestRocket into your client application with practical code examples in multiple languages.

Building a SaaS? Check out our SaaS Integration Guide to learn how to use RequestRocket as your integration platform for customers.

Prerequisites

Before integrating, ensure you have:

  1. A RequestRocket account
  2. An organisation (client) created
  3. A proxy configured with:
    • Proxy credential
    • Target credential
    • Target API endpoint

Don't have a proxy yet? Follow the getting started guide →

Integration Steps

Get Your Proxy Details

From the RequestRocket dashboard:

  1. Navigate to your proxy
  2. Copy the Base URL
  3. Note your proxy credential type and value

Example Base URL:

https://us-east-1.requestrocket.com/api/prx_abc123

Install HTTP Client

Choose an HTTP client for your programming language:

# Node.js - use built-in fetch or install axios
npm install axios
# Python - install requests
pip install requests
// Go - use net/http (built-in)
import "net/http"
<!-- Java - add to pom.xml -->
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.12.0</version>
</dependency>

Configure Your Application

Store your credentials securely:

// .env file
REQUESTROCKET_BASE_URL=https://us-east-1.requestrocket.com/api/prx_abc123
REQUESTROCKET_API_KEY=your-proxy-credential-here

// config.js
export const config = {
  baseURL: process.env.REQUESTROCKET_BASE_URL,
  apiKey: process.env.REQUESTROCKET_API_KEY
};
# .env file
REQUESTROCKET_BASE_URL=https://us-east-1.requestrocket.com/api/prx_abc123
REQUESTROCKET_API_KEY=your-proxy-credential-here

# config.py
import os
from dotenv import load_dotenv

load_dotenv()

BASE_URL = os.getenv('REQUESTROCKET_BASE_URL')
API_KEY = os.getenv('REQUESTROCKET_API_KEY')
// config.go
package main

import "os"

type Config struct {
    BaseURL string
    APIKey  string
}

func LoadConfig() *Config {
    return &Config{
        BaseURL: os.Getenv("REQUESTROCKET_BASE_URL"),
        APIKey:  os.Getenv("REQUESTROCKET_API_KEY"),
    }
}
// Config.java
public class Config {
    public static final String BASE_URL = 
        System.getenv("REQUESTROCKET_BASE_URL");
    public static final String API_KEY = 
        System.getenv("REQUESTROCKET_API_KEY");
}

Create Client Class

Build a reusable client:

// requestrocket.js
import { config } from './config.js';

class RequestRocketClient {
  constructor() {
    this.baseURL = config.baseURL;
    this.apiKey = config.apiKey;
  }

  async request(method, path, data = null) {
    const url = `${this.baseURL}${path}`;
    
    const options = {
      method,
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${this.apiKey}`
      }
    };

    if (data) {
      options.body = JSON.stringify(data);
    }

    const response = await fetch(url, options);
    
    // Check RequestRocket headers
    const proxyCode = response.headers.get('requestrocket-proxy-code');
    
    if (proxyCode === 'proxy-access-denied') {
      throw new Error('Proxy authentication failed');
    }

    if (!response.ok) {
      const error = await response.text();
      throw new Error(`Request failed: ${response.status} - ${error}`);
    }

    return await response.json();
  }

  async get(path) {
    return this.request('GET', path);
  }

  async post(path, data) {
    return this.request('POST', path, data);
  }

  async put(path, data) {
    return this.request('PUT', path, data);
  }

  async delete(path) {
    return this.request('DELETE', path);
  }
}

export default new RequestRocketClient();
# requestrocket.py
import requests
from config import BASE_URL, API_KEY

class RequestRocketClient:
    def __init__(self):
        self.base_url = BASE_URL
        self.api_key = API_KEY
        self.session = requests.Session()
        self.session.headers.update({
            'Content-Type': 'application/json',
            'Authorization': f'Bearer {self.api_key}'
        })

    def _request(self, method, path, **kwargs):
        url = f"{self.base_url}{path}"
        response = self.session.request(method, url, **kwargs)
        
        # Check RequestRocket headers
        proxy_code = response.headers.get('requestrocket-proxy-code')
        
        if proxy_code == 'proxy-access-denied':
            raise Exception('Proxy authentication failed')
        
        response.raise_for_status()
        return response.json()

    def get(self, path, params=None):
        return self._request('GET', path, params=params)

    def post(self, path, data=None):
        return self._request('POST', path, json=data)

    def put(self, path, data=None):
        return self._request('PUT', path, json=data)

    def delete(self, path):
        return self._request('DELETE', path)

client = RequestRocketClient()
// client.go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

type Client struct {
    baseURL string
    apiKey  string
    client  *http.Client
}

func NewClient(cfg *Config) *Client {
    return &Client{
        baseURL: cfg.BaseURL,
        apiKey:  cfg.APIKey,
        client:  &http.Client{},
    }
}

func (c *Client) Request(method, path string, body interface{}) (*http.Response, error) {
    var bodyReader io.Reader
    if body != nil {
        jsonData, err := json.Marshal(body)
        if err != nil {
            return nil, err
        }
        bodyReader = bytes.NewBuffer(jsonData)
    }

    url := c.baseURL + path
    req, err := http.NewRequest(method, url, bodyReader)
    if err != nil {
        return nil, err
    }

    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Authorization", "Bearer "+c.apiKey)

    resp, err := c.client.Do(req)
    if err != nil {
        return nil, err
    }

    // Check RequestRocket headers
    if proxyCode := resp.Header.Get("requestrocket-proxy-code"); proxyCode == "proxy-access-denied" {
        return nil, fmt.Errorf("proxy authentication failed")
    }

    return resp, nil
}

func (c *Client) Get(path string, result interface{}) error {
    resp, err := c.Request("GET", path, nil)
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    return json.NewDecoder(resp.Body).Decode(result)
}

func (c *Client) Post(path string, body, result interface{}) error {
    resp, err := c.Request("POST", path, body)
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    return json.NewDecoder(resp.Body).Decode(result)
}
// RequestRocketClient.java
import okhttp3.*;
import com.google.gson.Gson;
import java.io.IOException;

public class RequestRocketClient {
    private final String baseURL;
    private final String apiKey;
    private final OkHttpClient client;
    private final Gson gson;

    public RequestRocketClient() {
        this.baseURL = Config.BASE_URL;
        this.apiKey = Config.API_KEY;
        this.client = new OkHttpClient();
        this.gson = new Gson();
    }

    private Response request(String method, String path, Object body) throws IOException {
        String url = baseURL + path;
        
        Request.Builder builder = new Request.Builder()
            .url(url)
            .header("Content-Type", "application/json")
            .header("Authorization", "Bearer " + apiKey);

        if (body != null) {
            String json = gson.toJson(body);
            RequestBody requestBody = RequestBody.create(
                json, 
                MediaType.parse("application/json")
            );
            builder.method(method, requestBody);
        } else {
            builder.method(method, null);
        }

        Response response = client.newCall(builder.build()).execute();
        
        String proxyCode = response.header("requestrocket-proxy-code");
        if ("proxy-access-denied".equals(proxyCode)) {
            throw new IOException("Proxy authentication failed");
        }

        if (!response.isSuccessful()) {
            throw new IOException("Request failed: " + response.code());
        }

        return response;
    }

    public <T> T get(String path, Class<T> responseType) throws IOException {
        Response response = request("GET", path, null);
        String json = response.body().string();
        return gson.fromJson(json, responseType);
    }

    public <T> T post(String path, Object body, Class<T> responseType) throws IOException {
        Response response = request("POST", path, body);
        String json = response.body().string();
        return gson.fromJson(json, responseType);
    }
}

Make Your First Request

Test your integration:

# Example: Fetch user data
curl -X GET "https://us-east-1.requestrocket.com/api/prx_abc123/users/123" \
  -H "Authorization: Bearer your-proxy-credential-here" \
  -H "Content-Type: application/json"

# Example: Create new user
curl -X POST "https://us-east-1.requestrocket.com/api/prx_abc123/users" \
  -H "Authorization: Bearer your-proxy-credential-here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "John Doe",
    "email": "john@example.com"
  }'

# Example: Update user
curl -X PUT "https://us-east-1.requestrocket.com/api/prx_abc123/users/123" \
  -H "Authorization: Bearer your-proxy-credential-here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Jane Doe"
  }'

# Example: Delete user
curl -X DELETE "https://us-east-1.requestrocket.com/api/prx_abc123/users/123" \
  -H "Authorization: Bearer your-proxy-credential-here"
// Example: Fetch user data
import client from './requestrocket.js';

async function getUser(userId) {
  try {
    const user = await client.get(`/users/${userId}`);
    console.log('User:', user);
    return user;
  } catch (error) {
    console.error('Error:', error.message);
    throw error;
  }
}

// Example: Create new user
async function createUser(userData) {
  try {
    const user = await client.post('/users', userData);
    console.log('Created user:', user);
    return user;
  } catch (error) {
    console.error('Error:', error.message);
    throw error;
  }
}

// Usage
await getUser('123');
await createUser({ name: 'John Doe', email: 'john@example.com' });
# Example: Fetch user data
from requestrocket import client

def get_user(user_id):
    try:
        user = client.get(f'/users/{user_id}')
        print(f'User: {user}')
        return user
    except Exception as e:
        print(f'Error: {e}')
        raise

# Example: Create new user
def create_user(user_data):
    try:
        user = client.post('/users', user_data)
        print(f'Created user: {user}')
        return user
    except Exception as e:
        print(f'Error: {e}')
        raise

# Usage
user = get_user('123')
new_user = create_user({
    'name': 'John Doe',
    'email': 'john@example.com'
})
// main.go
package main

import (
    "fmt"
    "log"
)

type User struct {
    ID    string `json:"id"`
    Name  string `json:"name"`
    Email string `json:"email"`
}

func main() {
    cfg := LoadConfig()
    client := NewClient(cfg)

    // Get user
    var user User
    err := client.Get("/users/123", &user)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("User: %+v\n", user)

    // Create user
    newUser := User{
        Name:  "John Doe",
        Email: "john@example.com",
    }
    var created User
    err = client.Post("/users", newUser, &created)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created: %+v\n", created)
}
// Main.java
public class Main {
    public static void main(String[] args) {
        RequestRocketClient client = new RequestRocketClient();

        try {
            // Get user
            User user = client.get("/users/123", User.class);
            System.out.println("User: " + user);

            // Create user
            User newUser = new User("John Doe", "john@example.com");
            User created = client.post("/users", newUser, User.class);
            System.out.println("Created: " + created);

        } catch (IOException e) {
            System.err.println("Error: " + e.getMessage());
        }
    }
}

Error Handling

Implement robust error handling:

Check Response Headers

# Check response headers with verbose output
curl -v -X GET "https://us-east-1.requestrocket.com/api/prx_abc123/users/123" \
  -H "Authorization: Bearer your-proxy-credential-here" \
  -H "Content-Type: application/json"

# Look for these headers in the response:
# < requestrocket-proxy-code: proxy-access-granted
# < requestrocket-proxy-message: Access granted

# Check only headers (no body)
curl -I "https://us-east-1.requestrocket.com/api/prx_abc123/users/123" \
  -H "Authorization: Bearer your-proxy-credential-here"
async function makeRequest(path) {
  const response = await fetch(proxyUrl + path, options);
  
  const proxyCode = response.headers.get('requestrocket-proxy-code');
  const proxyMessage = response.headers.get('requestrocket-proxy-message');
  
  if (proxyCode === 'proxy-access-denied') {
    throw new Error(`Authentication failed: ${proxyMessage}`);
  }
  
  if (proxyCode === 'proxy-access-granted' && !response.ok) {
    throw new Error(`Target API error: ${response.status}`);
  }
  
  return await response.json();
}
def make_request(path):
    response = requests.get(proxy_url + path, headers=headers)
    
    proxy_code = response.headers.get('requestrocket-proxy-code')
    proxy_message = response.headers.get('requestrocket-proxy-message')
    
    if proxy_code == 'proxy-access-denied':
        raise Exception(f'Authentication failed: {proxy_message}')
    
    if proxy_code == 'proxy-access-granted' and not response.ok:
        raise Exception(f'Target API error: {response.status_code}')
    
    return response.json()
func makeRequest(path string) (interface{}, error) {
    resp, err := client.Request("GET", path, nil)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()
    
    proxyCode := resp.Header.Get("requestrocket-proxy-code")
    proxyMessage := resp.Header.Get("requestrocket-proxy-message")
    
    if proxyCode == "proxy-access-denied" {
        return nil, fmt.Errorf("authentication failed: %s", proxyMessage)
    }
    
    if proxyCode == "proxy-access-granted" && resp.StatusCode >= 400 {
        return nil, fmt.Errorf("target API error: %d", resp.StatusCode)
    }
    
    var result interface{}
    json.NewDecoder(resp.Body).Decode(&result)
    return result, nil
}
public Object makeRequest(String path) throws IOException {
    Response response = client.request("GET", path, null);
    
    String proxyCode = response.header("requestrocket-proxy-code");
    String proxyMessage = response.header("requestrocket-proxy-message");
    
    if ("proxy-access-denied".equals(proxyCode)) {
        throw new IOException("Authentication failed: " + proxyMessage);
    }
    
    if ("proxy-access-granted".equals(proxyCode) && !response.isSuccessful()) {
        throw new IOException("Target API error: " + response.code());
    }
    
    return gson.fromJson(response.body().string(), Object.class);
}

Implement Retry Logic

async function fetchWithRetry(url, options, maxRetries = 3) {
  const retryableCodes = [408, 429, 500, 502, 503, 504];
  
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      
      if (response.ok || !retryableCodes.includes(response.status)) {
        return response;
      }
      
      // Calculate backoff delay
      const delay = Math.min(1000 * Math.pow(2, attempt), 10000);
      await new Promise(resolve => setTimeout(resolve, delay));
      
    } catch (error) {
      if (attempt === maxRetries - 1) throw error;
    }
  }
}

Common Integration Patterns

API Gateway Pattern

Use RequestRocket as your application's API gateway:

// Express.js example
app.use('/api/*', async (req, res) => {
  const path = req.path.replace('/api', '');
  
  try {
    const result = await client.request(
      req.method,
      path,
      req.body
    );
    res.json(result);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

Microservices Communication

Route between microservices:

class ServiceClient {
  constructor(serviceName) {
    this.client = new RequestRocketClient();
    this.serviceName = serviceName;
  }

  async call(endpoint, method = 'GET', data = null) {
    const path = `/${this.serviceName}${endpoint}`;
    return await this.client.request(method, path, data);
  }
}

const userService = new ServiceClient('users');
const paymentService = new ServiceClient('payments');

// Usage
const user = await userService.call('/profile/123');
const payment = await paymentService.call('/charge', 'POST', chargeData);

Webhook Forwarding

Use Async API for reliable webhook delivery:

async function forwardWebhook(webhookData) {
  const asyncURL = proxyBaseURL.replace('/api/', '/async/');
  
  const response = await fetch(asyncURL + '/webhooks', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${apiKey}`
    },
    body: JSON.stringify(webhookData)
  });
  
  const { requestId } = await response.json();
  console.log('Webhook queued:', requestId);
  
  return requestId;
}

Testing Your Integration

Unit Tests

// Jest example
import client from './requestrocket';

jest.mock('./requestrocket');

test('fetches user successfully', async () => {
  const mockUser = { id: '123', name: 'John' };
  client.get.mockResolvedValue(mockUser);
  
  const user = await getUser('123');
  
  expect(user).toEqual(mockUser);
  expect(client.get).toHaveBeenCalledWith('/users/123');
});

Integration Tests

test('proxy handles authentication correctly', async () => {
  const response = await fetch(proxyURL + '/test', {
    headers: { 'Authorization': `Bearer ${apiKey}` }
  });
  
  expect(response.headers.get('requestrocket-proxy-code'))
    .toBe('proxy-access-granted');
});

Production Considerations

1. Rate Limiting

Monitor and handle rate limits:

class RateLimitedClient extends RequestRocketClient {
  constructor() {
    super();
    this.requestCount = 0;
    this.resetTime = Date.now() + 60000;
  }

  async request(method, path, data) {
    if (Date.now() > this.resetTime) {
      this.requestCount = 0;
      this.resetTime = Date.now() + 60000;
    }

    if (this.requestCount >= 100) {
      const waitTime = this.resetTime - Date.now();
      await new Promise(r => setTimeout(r, waitTime));
    }

    this.requestCount++;
    return await super.request(method, path, data);
  }
}

2. Monitoring

Log requests for monitoring:

async function monitoredRequest(method, path, data) {
  const start = Date.now();
  
  try {
    const result = await client.request(method, path, data);
    
    logger.info('Request succeeded', {
      method,
      path,
      duration: Date.now() - start,
      status: 'success'
    });
    
    return result;
  } catch (error) {
    logger.error('Request failed', {
      method,
      path,
      duration: Date.now() - start,
      error: error.message
    });
    throw error;
  }
}

3. Caching

Implement response caching:

class CachedClient extends RequestRocketClient {
  constructor() {
    super();
    this.cache = new Map();
  }

  async get(path, ttl = 300000) {
    const cached = this.cache.get(path);
    
    if (cached && Date.now() < cached.expiry) {
      return cached.data;
    }

    const data = await super.get(path);
    
    this.cache.set(path, {
      data,
      expiry: Date.now() + ttl
    });

    return data;
  }
}

Need help? Contact support or check our community forums for assistance.

Next Steps

On this page