3

I’m building an app that uses Stackoverflow’s API to get the last question of a certain tag & ouput it on my app. I have been able to get the last question on the specific tag, but now I want that automatically detect changes in the API Endpoint & fetch the last question posted without refreshing the browser or calling the function. I have tried with Computed Properties & Watchers, but I haven’t got it to work. I might be doing it wrong or my solution is not the right approach.

This is my code snippet:

<template>
  <div class="question container-fluid">
    <h1 class="my-3"
    >
    Last "<span class="question_tag">{{ tag }}</span>" Question Details
    </h1>
    <b-form
      class="my-4" 
      @submit.prevent="updateTag"
    >
      <b-form-input
        class="w-auto"
        placeholder="Enter a stackoverflow tag"
        type="text"
        v-model="newTag"
      >
      </b-form-input>
    </b-form>
    <div class="question_title my-2">
      <strong>Title: </strong> <span>{{ details.title }}</span>
    </div>
    <div class="question_status my-2">
      <strong>Question answered: </strong><span>{{ details.is_answered }}</span>
    </div>
    <div class="question_views my-2">
      <strong>Views: </strong><span>{{ details.view_count }}</span>
    </div>
    <div class="question_answers my-2">
      <strong>Answers Count: </strong><span>{{ details.answer_count }}</span>
    </div>
    <div class="question_link my-2">
      <strong>Check question: </strong>
      <a :href="details.link"
      :title="details.link"
      rel="noopener"
      target="_blank"
      >
        Here
      </a>
    </div>
  </div>
</template>

<script>
import axios from 'axios'

export default {
  name: 'QuestionInfo',
  data(){
    return {
      details: '',
      tag: `phaser-framework`,
      newTag: ''
    }
  },
  mounted() {
    this.getTag()
  },
  methods: {
    getTag(){
      axios.get(`https://api.stackexchange.com//2.2/questions?order=desc&sort=creation&tagged=${this.tag}&site=stackoverflow`).then(response => {
        this.details = response.data.items[0]
        // console.log an error if get() method is unsuccessful
      }).catch(err => {
        console.log(err)
      })
    },
    updateTag() {
      this.tag = this.newTag
      this.getTag();
    },
  },
}
</script>

EDIT:

I would like to find a Client Side solution... preferably a Vue Solution if there is any. I would like to avoid as much as possible a Server Side Solution for this feature.

tony19
  • 125,647
  • 18
  • 229
  • 307
Manuel Abascal
  • 5,616
  • 5
  • 35
  • 68
  • 1
    Consider creating a websocket instead of using the API, that way they can send to *you* – CertainPerformance Oct 16 '19 at 04:21
  • @CertainPerformance I have updated my answer so other respondant can understand my needs better. – Manuel Abascal Oct 16 '19 at 04:31
  • 1
    There's nothing preventing you from initializing a websocket on the client-side. I know how to do it in vanilla JS, but I don't have experience with Vue, so I can't provide a full answer, sorry – CertainPerformance Oct 16 '19 at 04:32
  • @CertainPerformance thanks for trying to help me. However, I don't know anything about WebSocket & I think there must be an easier solution with Vue to accomplish this or maybe a Vue Plugin. – Manuel Abascal Oct 16 '19 at 04:34
  • If you use the API, you *will* have to use polling, which is really inelegant. That's not something Vue or any plugin can solve. The only other option is a websocket, AFAIK – CertainPerformance Oct 16 '19 at 04:36

2 Answers2

2

I have found a solution. It's not the most elegant, but I finally decided to use setInterval() & make an new API call every 10 seconds. Getting fresh data every 10 seconds won't reach the Stack Exchange API's daily limit & solves my problem.

Code Snippet:

<script>
import axios from 'axios'

export default {
  name: 'QuestionInfo',
  data(){
    return {
      details: [],
      tag: `jquery`,
      newTag: ''
    }
  },
  // makes an API call on page load
  mounted() {
    this.getTag()
  },
  methods: {
    getTag(){
      setInterval(() => {
        axios.get(`https://api.stackexchange.com//2.2/questions?order=desc&sort=creation&tagged=${this.tag}&site=stackoverflow`).then(response => {
          this.details = response.data.items[0]
        // console.log an error if get() method is unsuccessful
        }).catch(err => {
          console.log(err)
        })
      }, 10000);
    },
    updateTag() {
      this.tag = this.newTag
      this.getTag();
    },
  },
}
</script>
Manuel Abascal
  • 5,616
  • 5
  • 35
  • 68
2

It looks like what you're trying to do is to allow for the server to send events to the client without the client having to ask for it. There are four ways to do this.

  1. Hit the API on a regular interval.
  2. Long Polling
  3. Server Sent Events
  4. Websockets

The first is the least efficient and a waste of resources. Each new incoming connection must be established, the HTTP headers must be parsed, a query for new data must be performed, and a response (usually with no new data to offer) must be generated and delivered. The connection must then be closed and any resources cleaned up.

The second way is to set up long polling., wherein you're still connecting via an HTTP connection, but the connection is lengthened until a response comes in or it times out. This way you aren't sending as many requests.

Server-sent events will solve the problem for you and is an efficient solution for you to use, but is mono-directional (communication from the server to the client) so if you need to communicate back and forth with the API, then you might want to try something else. It depends on your needs.

Typically I would recommend websockets, but this depends on whether or not the Stackoverflow API supports the use of websockets, which is seems like is not currently the case.

For your use case, I would first look at support for websockets. If this doesn't work, look into whether server sent events will do the job for you. If this is not enough, I would recommend implementing long-polling, which should help reduce some of the resource waste.

SamOh
  • 199
  • 6