0.0
No release in over 3 years
Decodes 17-character VINs to provide vehicle specifications like make, model, and engine type.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

>= 0
~> 3.0
~> 6.0
~> 3.0

Runtime

~> 2.0
>= 0
~> 2.6
 Project Readme

VinDecoder

vin_decoder is a lightweight Ruby client for the NHTSA vPIC API. It decodes 17-character VINs and exposes a tidy domain object so you can access make, model, year, powertrain data, and more without sifting through raw JSON.

Installation

Add the gem to your project (when published):

gem 'vin_decoder'

Or install directly from source:

git clone https://github.com/Wenmar-Pro/vin_decoder.git
cd vin_decoder
bundle install

Configuration

Use the top-level VinDecoder.configure block to customize the base URL (handy for mocking) or request timeout. Defaults target the official NHTSA API with a 10-second timeout.

VinDecoder.configure do |config|
  config.base_url = 'https://vpic.nhtsa.dot.gov/api/vehicles'
  config.timeout = 5
end

Usage

client = VinDecoder::Client.new
vehicle = client.decode('1HGCM82633A004352')

if vehicle.valid?
  puts [vehicle.year, vehicle.make, vehicle.model].compact.join(' ')
  puts "Engine: #{vehicle.engine} (#{vehicle.engine_cylinders} cylinders)"
  puts "Fuel: #{vehicle.fuel_type}"
  puts "Fuel type (raw accessor): #{vehicle['FuelTypePrimary']}"
  puts "Lot size (dynamic): #{vehicle.lot_size}"
else
  warn 'VIN could not be decoded'
end

The client raises:

  • VinDecoder::NotFoundError when the API responds with HTTP 404.
  • VinDecoder::ApiError for any other non-200 HTTP status code.

Each VinDecoder::Vehicle exposes the entire response payload:

  • Common helper methods (make, model, trim, engine, etc.).
  • Hash-style access with string or symbol keys (vehicle['ModelYear'] / vehicle[:ModelYear]).
  • Dynamic snake_case readers derived from the raw keys (vehicle.vehicle_descriptor, vehicle.fuel_type_secondary). Missing fields raise NoMethodError so mistakes are caught quickly.

Rails Integration

Add the gem to your Rails app (from RubyGems or a local path while developing).

# Gemfile
gem 'vin_decoder', path: '../path/to/vin_decoder'

Create an initializer to configure timeouts and base URL:

# config/initializers/vin_decoder.rb
VinDecoder.configure do |config|
  config.timeout = ENV.fetch('VIN_DECODER_TIMEOUT', 5).to_i
  config.base_url = ENV.fetch('VIN_DECODER_BASE_URL', 'https://vpic.nhtsa.dot.gov/api/vehicles')
end

Wrap the client in a PORO/service for controllers or jobs:

# app/services/vin_lookup.rb
class VinLookup
  def initialize(client: VinDecoder::Client.new)
    @client = client
  end

  def call(vin)
    vehicle = @client.decode(vin)
    raise VinDecoder::NotFoundError unless vehicle.valid?

    vehicle
  end
end

Example controller usage:

class VehiclesController < ApplicationController
  def show
    @vehicle = VinLookup.new.call(params[:vin])
  rescue VinDecoder::NotFoundError
    redirect_to root_path, alert: 'VIN not found'
  end
end

You can also enqueue lookups via ActiveJob/Sidekiq and cache results to avoid repeated external calls.

Testing & VCR Cassettes

Tests run via RSpec and rely on VCR/WebMock for deterministic HTTP interactions.

bundle exec rspec

To refresh the live cassette, delete spec/fixtures/vcr_cassettes/decode_success.yml and rerun the specs. VCR will connect to the real API once, capture the response, and reuse it on subsequent runs.

Publishing Checklist

  1. Ensure version in lib/vin_decoder/version.rb reflects the release.

  2. Update CHANGELOG or release notes as needed (add one if not yet created).

  3. Build the gem and inspect the package contents:

    gem build vin_decoder.gemspec
    gem install vin_decoder-<version>.gem
  4. Push the artifact to RubyGems:

    gem push vin_decoder-<version>.gem
  5. Tag the release in git and push tags to GitHub for reference.

That’s it—you now have a fully tested VIN decoder client ready for reuse or publication.