Table of contents

How can I use HTTParty to interact with REST APIs that require specific content types?

When working with REST APIs, different endpoints often require specific content types in both request headers and response handling. HTTParty provides flexible options for configuring content types, making it an excellent choice for API integration. This guide covers how to properly set and handle various content types when using HTTParty for API interactions.

Understanding Content Types in REST APIs

Content types tell the server what format your data is in and what format you expect in return. The most common content types for REST APIs include:

  • application/json - JSON data
  • application/xml - XML data
  • application/x-www-form-urlencoded - Form data
  • multipart/form-data - File uploads
  • text/plain - Plain text

Setting Request Content Types

JSON Content Type

For most modern REST APIs, JSON is the preferred format. Here's how to configure HTTParty for JSON requests:

require 'httparty'

class ApiClient
  include HTTParty

  base_uri 'https://api.example.com'
  headers 'Content-Type' => 'application/json'

  def create_user(user_data)
    options = {
      body: user_data.to_json,
      headers: { 'Content-Type' => 'application/json' }
    }

    self.class.post('/users', options)
  end
end

# Usage
client = ApiClient.new
response = client.create_user({
  name: 'John Doe',
  email: 'john@example.com'
})

XML Content Type

For APIs that require XML format:

require 'httparty'

class XmlApiClient
  include HTTParty

  base_uri 'https://api.example.com'

  def send_xml_data(xml_content)
    options = {
      body: xml_content,
      headers: { 
        'Content-Type' => 'application/xml',
        'Accept' => 'application/xml'
      }
    }

    self.class.post('/data', options)
  end
end

# Usage with XML string
xml_data = <<~XML
  <?xml version="1.0" encoding="UTF-8"?>
  <user>
    <name>John Doe</name>
    <email>john@example.com</email>
  </user>
XML

client = XmlApiClient.new
response = client.send_xml_data(xml_data)

Form Data Content Type

For traditional form submissions:

require 'httparty'

class FormApiClient
  include HTTParty

  base_uri 'https://api.example.com'

  def submit_form_data(form_params)
    options = {
      body: form_params,
      headers: { 'Content-Type' => 'application/x-www-form-urlencoded' }
    }

    self.class.post('/form-submit', options)
  end
end

# Usage
client = FormApiClient.new
response = client.submit_form_data({
  username: 'johndoe',
  password: 'secretpassword'
})

Handling Response Content Types

Automatic JSON Parsing

HTTParty automatically parses JSON responses when the server returns the appropriate content type:

class JsonApiClient
  include HTTParty

  base_uri 'https://jsonplaceholder.typicode.com'
  format :json

  def get_user(id)
    response = self.class.get("/users/#{id}")

    if response.success?
      # HTTParty automatically parses JSON response
      puts response['name']
      puts response['email']
      return response.parsed_response
    else
      puts "Error: #{response.code} - #{response.message}"
    end
  end
end

Custom Response Parsing

For APIs with custom content types or specific parsing needs:

class CustomApiClient
  include HTTParty

  base_uri 'https://api.example.com'

  def get_custom_data
    options = {
      headers: { 
        'Accept' => 'application/vnd.api+json',
        'Content-Type' => 'application/vnd.api+json'
      }
    }

    response = self.class.get('/custom-endpoint', options)

    # Handle different content types
    case response.headers['content-type']
    when /application\/json/
      JSON.parse(response.body)
    when /application\/xml/
      # Use a gem like Nokogiri for XML parsing
      require 'nokogiri'
      Nokogiri::XML(response.body)
    when /text\/csv/
      require 'csv'
      CSV.parse(response.body, headers: true)
    else
      response.body
    end
  end
end

Working with File Uploads

When uploading files, you'll typically use multipart/form-data:

require 'httparty'

class FileUploadClient
  include HTTParty

  base_uri 'https://api.example.com'

  def upload_file(file_path, additional_params = {})
    options = {
      body: {
        file: File.new(file_path, 'rb'),
        **additional_params
      },
      # HTTParty automatically sets multipart/form-data when files are present
    }

    self.class.post('/upload', options)
  end

  def upload_with_explicit_content_type(file_path)
    file_content = File.read(file_path)

    options = {
      body: file_content,
      headers: { 
        'Content-Type' => 'application/octet-stream',
        'Content-Disposition' => 'attachment; filename="document.pdf"'
      }
    }

    self.class.post('/binary-upload', options)
  end
end

# Usage
client = FileUploadClient.new
response = client.upload_file('/path/to/document.pdf', { description: 'Important document' })

Advanced Content Type Configuration

Global Headers Configuration

Set default content types for all requests in a class:

class ApiClient
  include HTTParty

  base_uri 'https://api.example.com'
  headers 'Content-Type' => 'application/json',
          'Accept' => 'application/json',
          'User-Agent' => 'MyApp/1.0'
  format :json

  def initialize(api_key)
    self.class.headers 'Authorization' => "Bearer #{api_key}"
  end

  def make_request(endpoint, data = nil)
    if data
      self.class.post(endpoint, body: data.to_json)
    else
      self.class.get(endpoint)
    end
  end
end

Dynamic Content Type Selection

Choose content types based on the data being sent:

class FlexibleApiClient
  include HTTParty

  base_uri 'https://api.example.com'

  def send_data(endpoint, data, format: :json)
    options = case format
              when :json
                {
                  body: data.to_json,
                  headers: { 'Content-Type' => 'application/json' }
                }
              when :xml
                {
                  body: data.to_xml,
                  headers: { 'Content-Type' => 'application/xml' }
                }
              when :form
                {
                  body: data,
                  headers: { 'Content-Type' => 'application/x-www-form-urlencoded' }
                }
              else
                raise ArgumentError, "Unsupported format: #{format}"
              end

    self.class.post(endpoint, options)
  end
end

# Usage
client = FlexibleApiClient.new
client.send_data('/users', user_data, format: :json)
client.send_data('/legacy-endpoint', form_data, format: :form)

Error Handling and Content Type Validation

Always validate content types and handle errors appropriately:

class RobustApiClient
  include HTTParty

  base_uri 'https://api.example.com'

  def safe_api_call(endpoint, data, expected_content_type = 'application/json')
    options = {
      body: data.to_json,
      headers: { 
        'Content-Type' => 'application/json',
        'Accept' => expected_content_type
      },
      timeout: 30
    }

    begin
      response = self.class.post(endpoint, options)

      # Validate response content type
      response_content_type = response.headers['content-type']
      unless response_content_type&.include?(expected_content_type)
        puts "Warning: Expected #{expected_content_type}, got #{response_content_type}"
      end

      if response.success?
        response.parsed_response
      else
        handle_error_response(response)
      end

    rescue HTTParty::Error, Net::TimeoutError => e
      puts "Network error: #{e.message}"
      nil
    end
  end

  private

  def handle_error_response(response)
    error_message = case response.headers['content-type']
                   when /application\/json/
                     response.parsed_response['error'] || response.parsed_response['message']
                   when /text\/html/
                     "HTML error response (likely 404 or 500)"
                   else
                     response.body
                   end

    puts "API Error #{response.code}: #{error_message}"
    nil
  end
end

Best Practices

  1. Always specify both Content-Type and Accept headers when working with APIs that support multiple formats
  2. Use the format class method to set default parsing behavior
  3. Handle different response content types gracefully with proper error checking
  4. Set appropriate timeouts when making API requests
  5. Validate content types in responses to catch API changes early

Integration with Web Scraping

When building comprehensive data collection systems, you might need to combine HTTParty's API capabilities with web scraping tools. For instance, after collecting data through APIs, you might need to handle browser sessions in Puppeteer for additional data that's only available through web interfaces.

For complex workflows involving both API calls and browser automation, consider monitoring network requests in Puppeteer to understand how web applications communicate with their backends.

Conclusion

HTTParty provides excellent flexibility for working with REST APIs that require specific content types. By properly configuring request headers, handling response formats, and implementing robust error handling, you can build reliable API integrations. Remember to always validate content types, handle errors gracefully, and choose the appropriate format for your specific use case.

The key to successful API integration is understanding both the expected request format and how to properly parse the response, regardless of the content type returned by the server.

Try WebScraping.AI for Your Web Scraping Needs

Looking for a powerful web scraping solution? WebScraping.AI provides an LLM-powered API that combines Chromium JavaScript rendering with rotating proxies for reliable data extraction.

Key Features:

  • AI-powered extraction: Ask questions about web pages or extract structured data fields
  • JavaScript rendering: Full Chromium browser support for dynamic content
  • Rotating proxies: Datacenter and residential proxies from multiple countries
  • Easy integration: Simple REST API with SDKs for Python, Ruby, PHP, and more
  • Reliable & scalable: Built for developers who need consistent results

Getting Started:

Get page content with AI analysis:

curl "https://api.webscraping.ai/ai/question?url=https://example.com&question=What is the main topic?&api_key=YOUR_API_KEY"

Extract structured data:

curl "https://api.webscraping.ai/ai/fields?url=https://example.com&fields[title]=Page title&fields[price]=Product price&api_key=YOUR_API_KEY"

Try in request builder

Related Questions

Get Started Now

WebScraping.AI provides rotating proxies, Chromium rendering and built-in HTML parser for web scraping
Icon