Skip to content

Using the Web Services: Ruby

Darren Oakley edited this page Jul 4, 2011 · 5 revisions

Helpers

  #! /usr/bin/env ruby -wKU

  # Author::    Sébastien Briois (mailto:sebriois@gmail.com)

  require "rubygems"
  require "rest_client"
  require "json"

  DOMAIN = RestClient::Resource.new( "http://user:password@localhost:3000" )

  # Generic helper method for handling the web calls to the repository.
  def request( method, url, data = nil )
    response =
      case method.upcase
      when "GET"    then DOMAIN[url].get
      when "POST"   then DOMAIN[url].post data, :content_type => "application/json"
      when "PUT"    then DOMAIN[url].put  data, :content_type => "application/json"
      when "DELETE" then DOMAIN[url].delete
      else
        raise "Method #{method} unknown when requesting url #{url}"
      end

    puts "#{method} #{url} - #{response.code} #{RestClient::STATUSES[response.code]}"
    return response.body
  end

  #
  # Allele specific methods
  #
  def find_allele( allele )
    params = ""
    params << "mgi_accession_id="    + allele[:mgi_accession_id]
    params << "&assembly="           + allele[:assembly]
    params << "&chromosome="         + allele[:chromosome]
    params << "&strand="             + allele[:strand]
    params << "&cassette="           + allele[:cassette]
    params << "&backbone="           + allele[:backbone]
    params << "&homology_arm_start=" + allele[:homology_arm_start]
    params << "&homology_arm_end="   + allele[:homology_arm_end]
    params << "&cassette_start="     + allele[:cassette_start]
    params << "&cassette_end="       + allele[:cassette_end]

    # Will find a conditional allele or a non-conditional allele
    if ( allele.include? :loxp_start and allele[:loxp_start] ) and ( allele.include? :loxp_end and allele[:loxp_end] )
      params += "&loxp_start=#{allele[:loxp_start]}&loxp_end=#{allele[:loxp_end]}"
    else
      params += "&loxp_start='null'&loxp_end='null'"
    end

    # Request for all the alleles that match the params.
    # The '.json' indicates that we want a JSON string as a response.
    response = request( 'GET', "alleles.json?#{params}" )

    # This will be a list whether the request returned one allele or more.
    allele_list = JSON.parse( response )

    # If the search is not specific enough and returns more than 1 allele
    if allele_list.length > 1 
      raise "Your search returned more than one allele, please refine it."
    end

    if allele_list == 1
      return allele_list[0]
    end

    return nil
  end

  def create_allele( data )
    json     = JSON.generate({ :allele => data })
    response = request( 'POST', 'alleles.json', json )
    allele   = JSON.parse( response )
    return allele
  end

  def update_allele( id, data )
    json     = JSON.generate({ :allele => data })
    response = request( 'PUT', "alleles/#{id}.json", json )
    allele   = JSON.parse( response )
    return allele
  end

  def delete_allele( id )
    request( 'DELETE', "alleles/#{id}" )
  end


  #
  # Targeting Vector specific methods
  #
  def find_targeting_vector( vector )
    response = request( 'GET', "targeting_vectors.json?name=#{vector['name']}" )
    targeting_vector_list = JSON.parse( response )

    if targeting_vector_list == 1
      return targeting_vector_list[0]
    end

    return nil
  end

  def create_targeting_vector( data )
    json     = JSON.generate({ :targeting_vector => data })
    response = request( 'POST', 'targeting_vectors.json', json )
    vector   = JSON.parse( response )
    return vector
  end

  def update_targeting_vector( id, data )
    json     = JSON.generate({ :targeting_vector => data })
    response = request( 'PUT', "targeting_vectors/#{id}.json", json )
    vector   = JSON.parse( response )
    return vector
  end

  def delete_targeting_vector( id )
    request( 'DELETE', "targeting_vectors/#{id}" )
  end

  #
  # ES Cell specific methods
  #
  def find_es_cell( cell )
    response = request( 'GET', "es_cells.json?name=#{cell['name']}" )
    es_cell_list = JSON.parse( response )

    if es_cell_list == 1
      return es_cell_list[0]
    end

    return nil
  end

  def create_es_cell( cell )
    json     = JSON.generate({ :es_cell => cell })
    response = request( 'POST', 'es_cells.json', json )
    cell     = JSON.parse( response )
    return cell
  end

  def update_es_cell( id, data )
    json     = JSON.generate({ :es_cell => data })
    response = request( 'PUT', "es_cells/#{id}.json", json )
    cell     = JSON.parse( response )
    return cell
  end

  def delete_es_cell( id )
    request( 'DELETE', "es_cells/#{id}" )
  end

An Example Loading Script

  ##
  ##  Main script scenario:
  ##    - We create a data structure containing all the objects we want to create or update in the database
  ##    - We loop over this data structure and follow this procedure:
  ##      1- Search the object
  ##      2- Object found ? Yes: Update; No: Create
  ##

  # We will work with the data linked to the pipeline named "EUCOMM", let's find its ID
  response = request( method = 'GET', url = 'pipelines.json' )
  pipeline_list = JSON.parse( response )
  pipeline = pipeline_list.find { |pipeline| pipeline['name'] == 'EUCOMM' }

  # Create our data structure
  alleles = [
  
    # First allele
    {
      :mgi_accession_id   => "MGI:123",
      :project_design_id  => 23640,
      :cassette           => "L1L2_gt2",
      :backbone           => "L3L4_pZero_kan",
      :assembly           => "NCBIM37",
      :chromosome         => "1",
      :strand             => "+",
      :design_type        => "Knock Out",
      :design_subtype     => "Frameshift",
      :homology_arm_start => 10,
      :homology_arm_end   => 10000,
      :cassette_start     => 50,
      :cassette_end       => 500,
      :loxp_start         => 1000,
      :loxp_end           => 1500,
    
      # Targeting vectors for the first allele
      :targeting_vectors  => [
        {
          :pipeline_id         => pipeline['id'],
          :name                => 'PRPGD001',
          :intermediate_vector => 'PGS001',
          :ikmc_project_id     => 9801
        },
        {
          :pipeline_id         => pipeline['id'],
          :name                => 'PRPGD002',
          :intermediate_vector => 'PGS001',
          :ikmc_project_id     => 9801
        }
      ],
    
      # ES Cells for the first allele
      :es_cells => [
        { :pipeline_id => pipeline['id'], :name => 'EPD001', :allele_symbol_superscript => 'tm1a', :targeting_vector => 'PRPGD001' },
        { :pipeline_id => pipeline['id'], :name => 'EPD002', :allele_symbol_superscript => 'tm1a', :targeting_vector => 'PRPGD001' },
        { :pipeline_id => pipeline['id'], :name => 'EPD003', :allele_symbol_superscript => 'tm1a', :targeting_vector => 'PRPGD001' },
        { :pipeline_id => pipeline['id'], :name => 'EPD004', :allele_symbol_superscript => 'tm1a', :targeting_vector => 'PRPGD002' },
        { :pipeline_id => pipeline['id'], :name => 'EPD005', :allele_symbol_superscript => 'tm1a', :targeting_vector => 'PRPGD002' },
        { :pipeline_id => pipeline['id'], :name => 'EPD006', :allele_symbol_superscript => 'tm1a', :targeting_vector => 'PRPGD002' }
      ]
    
      # Genbank File for the first allele
      :genbank_file => { 
        :escell_clone     => "A GENBANK FILE IN PLAIN TEXT",
        :targeting_vector => "A GENBANK FILE IN PLAIN TEXT"
      }
    },
  
    # Second allele
    {
      :mgi_accession_id   => "MGI:456",
      :project_design_id  => 29871,
      :cassette           => "L1L2_gt2",
      :backbone           => "L3L4_pZero_kan",
      :assembly           => "NCBIM37",
      :chromosome         => "1",
      :strand             => "+",
      :design_type        => "Knock Out",
      :design_subtype     => "Frameshift",
      :homology_arm_start => 10,
      :homology_arm_end   => 10000,
      :cassette_start     => 50,
      :cassette_end       => 500,
      :loxp_start         => 1000,
      :loxp_end           => 1500,
    
      # Targeting vectors for the second allele
      :targeting_vectors  => [
        {
          :pipeline_id         => pipeline['id'],
          :name                => 'PRPGD003',
          :intermediate_vector => 'PGS002',
          :ikmc_project_id     => 6809480
        },
        {
          :pipeline_id         => pipeline['id'],
          :name                => 'PRPGD004',
          :intermediate_vector => 'PGS002',
          :ikmc_project_id     => 6809480
        }
      ],
    
      # ES Cells for the second allele
      :es_cells => [
        { :pipeline_id => pipeline['id'], :name => 'EPD007', :allele_symbol_superscript => 'tm1a', :targeting_vector => 'PRPGD003' },
        { :pipeline_id => pipeline['id'], :name => 'EPD008', :allele_symbol_superscript => 'tm1a', :targeting_vector => 'PRPGD003' },
        { :pipeline_id => pipeline['id'], :name => 'EPD009', :allele_symbol_superscript => 'tm1a', :targeting_vector => 'PRPGD003' },
        { :pipeline_id => pipeline['id'], :name => 'EPD010', :allele_symbol_superscript => 'tm1a', :targeting_vector => 'PRPGD004' },
        { :pipeline_id => pipeline['id'], :name => 'EPD011', :allele_symbol_superscript => 'tm1a', :targeting_vector => 'PRPGD004' },
        { :pipeline_id => pipeline['id'], :name => 'EPD012', :allele_symbol_superscript => 'tm1a', :targeting_vector => 'PRPGD004' }
      ]
    }
  ]

  alleles.each do |allele_hash|
    # allele_hash should not contain unknown fields
    targeting_vectors = allele_hash.delete( :targeting_vectors )
    es_cells          = allele_hash.delete( :es_cells )
  
    # Find, Create or Update allele
    allele_found = find_allele( allele_hash )
    if allele_found.nil?
      allele = create_allele( allele_hash )
    else
      # If allele has been found, it has an "id"
      allele = update_allele( allele_found['id'], allele_hash )
    end
    # Our allele now has an ID
    allele_hash[:id] = allele['id']
  
    # Find, Create or Update Targeting Vector
    targeting_vectors.each do |vector_hash|
      vector_hash[:allele_id] = allele_hash[:id]
    
      vector_found = find_targeting_vector( vector_hash )
      if vector_found.nil?
        vector = create_targeting_vector( vector_hash )
      else
        vector = update_targeting_vector( vector_found['id'], vector_hash )
      end
      vector_hash[:id] = vector['id']
    end
  
    # Find, Create or Update ES Cell
    es_cells.each do |es_cell_hash|
      # ES Cell must be linked to a Molecular Structure
      es_cell_hash[:allele_id] = allele_hash[:id]
    
      # If ES Cell is linked to a targeting vector, retrieve its ID
      if es_cell_hash.include? :targeting_vector
        es_cell_hash[:targeting_vector_id] =
          targeting_vectors.find { |v| v[:name] == es_cell_hash[:targeting_vector] }['id']
      else
        es_cell_hash[:targeting_vector_id] = nil
      end
    
      # Find, Create or Update ES Cell
      es_cell_found = find_es_cell( es_cell_hash )
      if es_cell_found.nil?
        es_cell = create_es_cell( es_cell_hash )
      else
        es_cell = update_es_cell( es_cell_found['id'], es_cell_hash )
      end
      es_cell_hash[:id] = es_cell['id']
    end
  end

  # DELETE All ES Cells
  es_cells.each { |es_cell| delete_es_cell( es_cell[:id] ) }
  targeting_vectors.each { |vector| delete_targeting_vector( vector[:id] ) }
  alleles.each { |allele| delete_allele( allele[:id] ) }