Querying a search service


#1

I’m prototyping a simple frontend that needs to send search queries to a backend API that ultimately ends up querying a search engine. The returned payload are not records per se but the results of the search query.

What’s the right way to handle this in ember? It seems that the expected approach is to define models that map to ‘records’ that are already known in some kind of RDBMS, and URLs are automatically generated to map to these records by id. However, in the search example, the paradigm is much different in that there are no predefined records - we only know what will be returned after the user has submitted a search query.

Can someone explain the best way to handle this problem in ember? Do I need models that map to the different elements of each returned search query? Do I need to write a custom adapter to handle this type of query to the backend?

Thanks.


#2

That’s a great question, @em.b.

How many endpoints to this API are you going to deal with? How much will the hostnames/URIs vary?

  • You could have a QueryService with a method that returns an ajax promise, inject that service in your route/controller/component
  • You could still make use of Ember Data with adapters/serializers which bring advantages even when you don’t have a fixed schema. A model could be Query with a payload property as a JSON blob.
  • Or use an add-on such as https://github.com/poteto/ember-hypersearch

#3

Thanks for that info. I’ll spend some time looking into the options you listed.

In the meantime, do you know of any tutorials/examples that address this particular issue? Trying to get up to speed on ember as fast as I can, and learning by example is super helpful.


#4

I can’t think of any resource that answers this issue specifically, but I wrote about non-standard REST actions, that might give you some ideas? https://emberigniter.com/non-standard-rest-actions-ember-data/ Again, the strategy really depends on your endpoint structure


#5

What I’ve done for clients in the past is just use the raw JSON objects passed back (which Ember is fine with). Although we normally use Ember Data models in the model hook in the guides, Ember templates are data layer agnostic and don’t care what you give it to render.

Then, if you want to view a specific search item in a route, you can pass the ID and have the item’s Ember Data model load at that point. That’s the quick approach.

For a more elegant approach (where your search results contain all the model attributes) you could use a serializer approach as Frank mentioned, but it is more work …


#6

Thanks for all of the great suggestions.

I’ve been able to query the search service using ember-ajax and it seems pretty straightfoward.

However, being new to ember I’m struggling with figuring out how to wire up the incoming data from the search engine to the template. I feel like I’m missing something obvious.

Here’s what I have in my routes/search.js:

export default Ember.Route.extend({
  ajax: Ember.inject.service(),
  model() {
  },

  searchResults: null,

  submit(searchTerm) {
      return this.get('ajax').request('api/q/srch', {
        method: 'POST',
        dataType: 'json',
        data: JSON.stringify({
            text: searchTerm,
            similarity:"TFIDF",
            highlights:false,
            maxResults:500,
            weighted:true
        })
      }).then(function(data) {
        console.log('searched');
        return data;
      })
      .catch(function(error) {
        debugger;
      });
  },

  actions: {
    hitEngine: function(searchTerm) {
      let newResults = this.submit(searchTerm).then(function(data) {
        this.set('searchResults', data);
      }.bind(this));
    }
  }
});

Then, in my template, I have the following:

<div id="main_content">
  <div class="search_area">
    <form>
      Search: {{input value=searchTerm type="text" name="search_input" class="search"}}
      <button {{action "hitEngine" searchTerm}}>Submit</button>
    </form>
  </div>
  <div class="search_results_area">
    {{#each searchResults.data.items as |item|}}
      {{item.digest.text}}
    {{/each}}
  </div>
</div>

One thing that I know is wrong is my use of bind() in the hitEngine action. There must be a more Ember-like way of doing that. But I can’t figure out how to access the data returned by the ajax promise otherwise.

When I use set() to update the value of searchResults, the template does not update even thought the value of searchResults appears to be successfully set.

Sorry for the elementary questions. Having to use ember-ajax threw me for a bit of a loop after expecting to be able to use Ember Data and models right out of the box!

Thanks for the help.