Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Post document to SOLR 4 from AngularJS


I'm deep in the rabbit hole with this. I'm creating a simple app that uses SOLR 4 as a NoSQL datastore and AngularJS v1.2.2 for the interface. I've loaded a bunch of documents from the command line and AngularJS makes it very easy to search/view these. I want to permit document editing but can't get the POST working. Chrome console shows 400 errors and the Network tab shows it's failing on OPTIONS method.

Network Headers:
Request URL:http://localhost:8983/solr/mrm_assay/update Request Method:OPTIONS Status Code:400 Bad Request Request Headers Accept:*/* Accept-Encoding:gzip,deflate,sdch Accept-Language:en-US,en;q=0.8,es;q=0.6 Access-Control-Request-Headers:accept, content-type Access-Control-Request-Method:POST Cache-Control:no-cache Connection:keep-alive Host:localhost:8983 Origin:http://localhost:63342 Pragma:no-cache Referer:http://localhost:63342/angular-solr2/app/index.html User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36 Response Headers Access-Control-Allow-Credentials:true Access-Control-Allow-Headers:origin, content-type, cache-control, accept, options Access-Control-Allow-Methods:GET,POST,DELETE,PUT,HEAD,OPTIONS Access-Control-Allow-Origin:http://localhost:63342 Access-Control-Max-Age:1800 Content-Type:application/xml; charset=UTF-8 Transfer-Encoding:chunked

Quick overview of architecture:
Both SOLR and AngularJS apps are running on my Mac. SOLR is using the default Jetty instance and the Angular app runs within the server from WebStorm's IDE. CORS is enabled and includes GET,POST,DELETE,PUT,HEAD,OPTIONS.

Updates work when:

  • Using SOLR's dashboard
  • Using command line (example)
    $ curl http://localhost:8983/solr/mrm_assay/update -H 'Content-type:application/json' -d '[ { "keep_in_assay" {"set" : "N", "detected_endog": "N", "problems_w_is": "removed b/c requires addition post-Oasis", "onc_std_set": "set1", "fraction_id": "7", "onclistgene": "UBL3", "geneid": "UBL3_IS6", "taxonid": "9606", "peptide": "SSNVPADMINLR", "degen_human": "1", "gene_degeneracy": "1", "percnt_id": "66.7", "uuid": "6d20eb03-d3ee-4eb2-bc16-27cfaabab989" } ]'

My Angular controller code looks like this:
assayControllers.controller('AssayUpdateController', ['$scope', '$http', function($scope, $http){ $scope.processForm = function(){ console.log($scope.assay); $http({ method:'POST', url:'http://localhost:8983/solr/mrm_assay/update', data : $scope.assay, headers : {'Content-Type': 'application/json' } }) .success(function(data, status, headers){ console.log(data.message); }) .error(function(data, status, headers, config){ console.log(status); }); }; } ]);

Data is successfully sent from the form as I can see it on the console (although the JSON object isn't packaged in an array, which SOLR seems to expect...I also tried to push JSON-formatted data to an array and POST that but no luck)

I appreciate your help - even if it's just to direct my troubleshooting!

like image 747
jbdamask Avatar asked Mar 22 '14 15:03

jbdamask


1 Answers

The answer on how to update an individual document to SOLR v4.7 using AngularJS v1.2.2 is multi-part. This has only been tested on my localhost!

I. Configure CORS on Jetty server that ships with SOLR
solr-4.7.0/example/solr-webapp/webapp/WEB-INF/web.xml

Notes: CrossOriginFilter has a parameter, chainPreflight, that is set to true by default. This needs to be set to false. This was the key to CORS forwarding POST instead of OPTIONS to SOLR.. Also, order matters!

<filter>
    <filter-name>cross-origin</filter-name>
    <filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
    <init-param>
         <param-name>allowedOrigins</param-name>
         <param-value>http://localhost*</param-value>
    </init-param>
     <init-param>
         <param-name>allowedMethods</param-name>
         <param-value>GET,POST,DELETE,PUT,HEAD,OPTIONS</param-value>
     </init-param>
     <init-param>
         <param-name>allowedHeaders</param-name>
         <param-value>origin, content-type, cache-control, accept, options, authorization, x-requested-with</param-value>
     </init-param>
    <init-param>
        <param-name>supportsCredentials</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
      <param-name>chainPreflight</param-name>
      <param-value>false</param-value>
    </init-param>
</filter>

<filter-mapping>
  <filter-name>cross-origin</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

II. SOLR expects payload in array format, so you need to push Angular object into one. Basically, $scope.data becomes [$scope.data]

assayControllers.controller('AssayUpdateController', ['$scope', '$http', '$location',
    function($scope,  $http, $location){
        $scope.processForm = function(){
            $http.post("http://localhost:8983/solr/mrm_assay/update?commit=true", [$scope.assay])
                .success(function(data, status, headers){
                    console.log(data.message);
                    $location.path("/assays")
                })
                .error(function(data, status, headers, config){
                    console.log(status);
                });
        };
    }
]);

III. SOLR documents contain version field that can cause "conflict" errors on POST. This is due to a cache issue I wasn't able to track down (curl showed current value but browsers had old one; even on force refresh). Anyway, this is of more use to SOLR than me so the best bet is to not return it to the client in the first place. I don't think field exclusion is an option so I whitelisted all the fields I wanted to return in solrconfig.xml

 <!-- A request handler that returns indented JSON by default -->
  <requestHandler name="/query" class="solr.SearchHandler">
     <lst name="defaults">
       <str name="echoParams">explicit</str>
       <str name="wt">json</str>
       <str name="indent">true</str>
       <str name="df">text</str>
      <str name="fl">uuid,keep_in_assay,detected_endog,problems_w_is,onc_std_set,fraction_id,detected_by_orbi_experiments,onclistgene,geneid,taxonid,peptide,\
degen_human,degen_mouse,gene_degeneracy,department,protein_ac,pepid,protid,percnt_id,peptide_ordered</str>

Now the app works like a charm!

like image 150
jbdamask Avatar answered Oct 22 '22 04:10

jbdamask