From e4edf55c4753aaac807316c029354532c112fce9 Mon Sep 17 00:00:00 2001
From: Eliot Berriot <contact@eliotberriot.com>
Date: Thu, 11 Jan 2018 21:35:51 +0100
Subject: [PATCH] Replaced vue-resource by axios

---
 api/funkwhale_api/favorites/views.py          |  2 +-
 api/funkwhale_api/music/fake_data.py          |  4 +--
 api/tests/test_favorites.py                   |  7 ++--
 front/package.json                            |  4 ++-
 front/src/components/audio/Search.vue         | 17 ++-------
 front/src/components/auth/Settings.vue        |  6 ++--
 front/src/components/favorites/List.vue       |  6 ++--
 front/src/components/library/Album.vue        |  7 ++--
 front/src/components/library/Artist.vue       |  7 ++--
 front/src/components/library/Artists.vue      |  6 ++--
 front/src/components/library/Home.vue         |  6 ++--
 front/src/components/library/Radios.vue       |  6 ++--
 front/src/components/library/Track.vue        |  9 +++--
 .../library/import/ArtistImport.vue           |  7 ++--
 .../components/library/import/BatchDetail.vue |  7 ++--
 .../components/library/import/BatchList.vue   |  6 ++--
 .../components/library/import/FileUpload.vue  |  9 ++---
 .../components/library/import/ImportMixin.vue |  8 ++---
 .../components/library/import/TrackImport.vue |  8 ++---
 .../src/components/library/radios/Builder.vue | 22 ++++++------
 .../src/components/library/radios/Filter.vue  |  5 +--
 front/src/components/metadata/CardMixin.vue   |  9 ++---
 front/src/config.js                           |  2 +-
 front/src/main.js                             | 35 ++++++++++++-------
 front/src/store/auth.js                       | 16 +++------
 front/src/store/favorites.js                  | 17 +++------
 front/src/store/player.js                     |  7 ++--
 front/src/store/radios.js                     | 13 ++-----
 28 files changed, 111 insertions(+), 147 deletions(-)

diff --git a/api/funkwhale_api/favorites/views.py b/api/funkwhale_api/favorites/views.py
index 98c0cfc0..08ae00b6 100644
--- a/api/funkwhale_api/favorites/views.py
+++ b/api/funkwhale_api/favorites/views.py
@@ -43,7 +43,7 @@ class TrackFavoriteViewSet(mixins.CreateModelMixin,
         favorite = models.TrackFavorite.add(track=track, user=self.request.user)
         return favorite
 
-    @list_route(methods=['delete'])
+    @list_route(methods=['delete', 'post'])
     def remove(self, request, *args, **kwargs):
         try:
             pk = int(request.data['track'])
diff --git a/api/funkwhale_api/music/fake_data.py b/api/funkwhale_api/music/fake_data.py
index ef5eaf4b..892b784c 100644
--- a/api/funkwhale_api/music/fake_data.py
+++ b/api/funkwhale_api/music/fake_data.py
@@ -4,7 +4,7 @@ Populates the database with fake data
 import random
 
 from funkwhale_api.music import models
-from funkwhale_api.music.tests import factories
+from funkwhale_api.music import factories
 
 
 def create_data(count=25):
@@ -19,4 +19,4 @@ def create_data(count=25):
 
 
 if __name__ == '__main__':
-    main()
+    create_data()
diff --git a/api/tests/test_favorites.py b/api/tests/test_favorites.py
index 418166d8..8165722e 100644
--- a/api/tests/test_favorites.py
+++ b/api/tests/test_favorites.py
@@ -58,11 +58,14 @@ def test_user_can_remove_favorite_via_api(logged_in_client, factories, client):
     assert response.status_code == 204
     assert TrackFavorite.objects.count() == 0
 
-def test_user_can_remove_favorite_via_api_using_track_id(factories, logged_in_client):
+
+@pytest.mark.parametrize('method', ['delete', 'post'])
+def test_user_can_remove_favorite_via_api_using_track_id(
+        method, factories, logged_in_client):
     favorite = factories['favorites.TrackFavorite'](user=logged_in_client.user)
 
     url = reverse('api:v1:favorites:tracks-remove')
-    response = logged_in_client.delete(
+    response = getattr(logged_in_client, method)(
         url, json.dumps({'track': favorite.track.pk}),
         content_type='application/json'
     )
diff --git a/front/package.json b/front/package.json
index 2818757a..aa5024d2 100644
--- a/front/package.json
+++ b/front/package.json
@@ -15,6 +15,7 @@
     "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs"
   },
   "dependencies": {
+    "axios": "^0.17.1",
     "dateformat": "^2.0.0",
     "js-logger": "^1.3.0",
     "jwt-decode": "^2.2.0",
@@ -22,7 +23,6 @@
     "semantic-ui-css": "^2.2.10",
     "vue": "^2.3.3",
     "vue-lazyload": "^1.1.4",
-    "vue-resource": "^1.3.4",
     "vue-router": "^2.3.1",
     "vue-upload-component": "^2.7.4",
     "vuedraggable": "^2.14.1",
@@ -69,6 +69,7 @@
     "karma-phantomjs-launcher": "^1.0.2",
     "karma-phantomjs-shim": "^1.4.0",
     "karma-sinon-chai": "^1.3.1",
+    "karma-sinon-stub-promise": "^1.0.0",
     "karma-sourcemap-loader": "^0.3.7",
     "karma-spec-reporter": "0.0.30",
     "karma-webpack": "^2.0.2",
@@ -87,6 +88,7 @@
     "shelljs": "^0.7.6",
     "sinon": "^2.1.0",
     "sinon-chai": "^2.8.0",
+    "sinon-stub-promise": "^4.0.0",
     "url-loader": "^0.5.8",
     "vue-loader": "^12.1.0",
     "vue-style-loader": "^3.0.1",
diff --git a/front/src/components/audio/Search.vue b/front/src/components/audio/Search.vue
index 2811c2b5..bb088186 100644
--- a/front/src/components/audio/Search.vue
+++ b/front/src/components/audio/Search.vue
@@ -29,13 +29,11 @@
 </template>
 
 <script>
+import axios from 'axios'
 import logger from '@/logging'
 import backend from '@/audio/backend'
 import AlbumCard from '@/components/audio/album/Card'
 import ArtistCard from '@/components/audio/artist/Card'
-import config from '@/config'
-
-const SEARCH_URL = config.API_URL + 'search'
 
 export default {
   components: {
@@ -73,17 +71,8 @@ export default {
       let params = {
         query: this.query
       }
-      this.$http.get(SEARCH_URL, {
-        params: params,
-        before (request) {
-          // abort previous request, if exists
-          if (this.previousRequest) {
-            this.previousRequest.abort()
-          }
-
-          // set previous request on Vue instance
-          this.previousRequest = request
-        }
+      axios.get('search', {
+        params: params
       }).then((response) => {
         self.results = self.castResults(response.data)
         self.isLoading = false
diff --git a/front/src/components/auth/Settings.vue b/front/src/components/auth/Settings.vue
index d93373a1..f090581e 100644
--- a/front/src/components/auth/Settings.vue
+++ b/front/src/components/auth/Settings.vue
@@ -36,7 +36,7 @@
 </template>
 
 <script>
-import Vue from 'vue'
+import axios from 'axios'
 import config from '@/config'
 import logger from '@/logging'
 
@@ -61,8 +61,8 @@ export default {
         new_password1: this.new_password,
         new_password2: this.new_password
       }
-      let resource = Vue.resource(config.BACKEND_URL + 'api/auth/registration/change-password/')
-      return resource.save({}, credentials).then(response => {
+      let url = config.BACKEND_URL + 'api/auth/registration/change-password/'
+      return axios.post(url, credentials).then(response => {
         logger.default.info('Password successfully changed')
         self.$router.push('/profile/me')
       }, response => {
diff --git a/front/src/components/favorites/List.vue b/front/src/components/favorites/List.vue
index 8577e84c..c65144a9 100644
--- a/front/src/components/favorites/List.vue
+++ b/front/src/components/favorites/List.vue
@@ -54,15 +54,15 @@
 </template>
 
 <script>
+import axios from 'axios'
 import $ from 'jquery'
 import logger from '@/logging'
-import config from '@/config'
 import TrackTable from '@/components/audio/track/Table'
 import RadioButton from '@/components/radios/Button'
 import Pagination from '@/components/Pagination'
 import OrderingMixin from '@/components/mixins/Ordering'
 import PaginationMixin from '@/components/mixins/Pagination'
-const FAVORITES_URL = config.API_URL + 'tracks/'
+const FAVORITES_URL = 'tracks/'
 
 export default {
   mixins: [OrderingMixin, PaginationMixin],
@@ -115,7 +115,7 @@ export default {
         ordering: this.getOrderingAsString()
       }
       logger.default.time('Loading user favorites')
-      this.$http.get(url, {params: params}).then((response) => {
+      axios.get(url, {params: params}).then((response) => {
         self.results = response.data
         self.nextLink = response.data.next
         self.previousLink = response.data.previous
diff --git a/front/src/components/library/Album.vue b/front/src/components/library/Album.vue
index dcfea560..65768aaf 100644
--- a/front/src/components/library/Album.vue
+++ b/front/src/components/library/Album.vue
@@ -41,14 +41,13 @@
 </template>
 
 <script>
-
+import axios from 'axios'
 import logger from '@/logging'
 import backend from '@/audio/backend'
 import PlayButton from '@/components/audio/PlayButton'
 import TrackTable from '@/components/audio/track/Table'
-import config from '@/config'
 
-const FETCH_URL = config.API_URL + 'albums/'
+const FETCH_URL = 'albums/'
 
 export default {
   props: ['id'],
@@ -71,7 +70,7 @@ export default {
       this.isLoading = true
       let url = FETCH_URL + this.id + '/'
       logger.default.debug('Fetching album "' + this.id + '"')
-      this.$http.get(url).then((response) => {
+      axios.get(url).then((response) => {
         self.album = backend.Album.clean(response.data)
         self.isLoading = false
       })
diff --git a/front/src/components/library/Artist.vue b/front/src/components/library/Artist.vue
index 5eab08dd..c2834e1d 100644
--- a/front/src/components/library/Artist.vue
+++ b/front/src/components/library/Artist.vue
@@ -41,15 +41,14 @@
 </template>
 
 <script>
-
+import axios from 'axios'
 import logger from '@/logging'
 import backend from '@/audio/backend'
 import AlbumCard from '@/components/audio/album/Card'
 import RadioButton from '@/components/radios/Button'
 import PlayButton from '@/components/audio/PlayButton'
-import config from '@/config'
 
-const FETCH_URL = config.API_URL + 'artists/'
+const FETCH_URL = 'artists/'
 
 export default {
   props: ['id'],
@@ -74,7 +73,7 @@ export default {
       this.isLoading = true
       let url = FETCH_URL + this.id + '/'
       logger.default.debug('Fetching artist "' + this.id + '"')
-      this.$http.get(url).then((response) => {
+      axios.get(url).then((response) => {
         self.artist = response.data
         self.albums = JSON.parse(JSON.stringify(self.artist.albums)).map((album) => {
           return backend.Album.clean(album)
diff --git a/front/src/components/library/Artists.vue b/front/src/components/library/Artists.vue
index 23a30e77..c9bea5ef 100644
--- a/front/src/components/library/Artists.vue
+++ b/front/src/components/library/Artists.vue
@@ -57,10 +57,10 @@
 </template>
 
 <script>
+import axios from 'axios'
 import _ from 'lodash'
 import $ from 'jquery'
 
-import config from '@/config'
 import backend from '@/audio/backend'
 import logger from '@/logging'
 
@@ -69,7 +69,7 @@ import PaginationMixin from '@/components/mixins/Pagination'
 import ArtistCard from '@/components/audio/artist/Card'
 import Pagination from '@/components/Pagination'
 
-const FETCH_URL = config.API_URL + 'artists/'
+const FETCH_URL = 'artists/'
 
 export default {
   mixins: [OrderingMixin, PaginationMixin],
@@ -124,7 +124,7 @@ export default {
         ordering: this.getOrderingAsString()
       }
       logger.default.debug('Fetching artists')
-      this.$http.get(url, {params: params}).then((response) => {
+      axios.get(url, {params: params}).then((response) => {
         self.result = response.data
         self.result.results.map((artist) => {
           var albums = JSON.parse(JSON.stringify(artist.albums)).map((album) => {
diff --git a/front/src/components/library/Home.vue b/front/src/components/library/Home.vue
index 624da62c..cdcbe4b7 100644
--- a/front/src/components/library/Home.vue
+++ b/front/src/components/library/Home.vue
@@ -24,14 +24,14 @@
 </template>
 
 <script>
+import axios from 'axios'
 import Search from '@/components/audio/Search'
 import backend from '@/audio/backend'
 import logger from '@/logging'
 import ArtistCard from '@/components/audio/artist/Card'
-import config from '@/config'
 import RadioCard from '@/components/radios/Card'
 
-const ARTISTS_URL = config.API_URL + 'artists/'
+const ARTISTS_URL = 'artists/'
 
 export default {
   name: 'library',
@@ -58,7 +58,7 @@ export default {
       }
       let url = ARTISTS_URL
       logger.default.time('Loading latest artists')
-      this.$http.get(url, {params: params}).then((response) => {
+      axios.get(url, {params: params}).then((response) => {
         self.artists = response.data.results
         self.artists.map((artist) => {
           var albums = JSON.parse(JSON.stringify(artist.albums)).map((album) => {
diff --git a/front/src/components/library/Radios.vue b/front/src/components/library/Radios.vue
index 409b6b67..1952908f 100644
--- a/front/src/components/library/Radios.vue
+++ b/front/src/components/library/Radios.vue
@@ -59,10 +59,10 @@
 </template>
 
 <script>
+import axios from 'axios'
 import _ from 'lodash'
 import $ from 'jquery'
 
-import config from '@/config'
 import logger from '@/logging'
 
 import OrderingMixin from '@/components/mixins/Ordering'
@@ -70,7 +70,7 @@ import PaginationMixin from '@/components/mixins/Pagination'
 import RadioCard from '@/components/radios/Card'
 import Pagination from '@/components/Pagination'
 
-const FETCH_URL = config.API_URL + 'radios/radios/'
+const FETCH_URL = 'radios/radios/'
 
 export default {
   mixins: [OrderingMixin, PaginationMixin],
@@ -125,7 +125,7 @@ export default {
         ordering: this.getOrderingAsString()
       }
       logger.default.debug('Fetching radios')
-      this.$http.get(url, {params: params}).then((response) => {
+      axios.get(url, {params: params}).then((response) => {
         self.result = response.data
         self.isLoading = false
       })
diff --git a/front/src/components/library/Track.vue b/front/src/components/library/Track.vue
index 48cd801c..a4040961 100644
--- a/front/src/components/library/Track.vue
+++ b/front/src/components/library/Track.vue
@@ -60,15 +60,14 @@
 </template>
 
 <script>
-
+import axios from 'axios'
 import url from '@/utils/url'
 import logger from '@/logging'
 import backend from '@/audio/backend'
 import PlayButton from '@/components/audio/PlayButton'
 import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon'
-import config from '@/config'
 
-const FETCH_URL = config.API_URL + 'tracks/'
+const FETCH_URL = 'tracks/'
 
 export default {
   props: ['id'],
@@ -94,7 +93,7 @@ export default {
       this.isLoadingTrack = true
       let url = FETCH_URL + this.id + '/'
       logger.default.debug('Fetching track "' + this.id + '"')
-      this.$http.get(url).then((response) => {
+      axios.get(url).then((response) => {
         self.track = response.data
         self.isLoadingTrack = false
       })
@@ -104,7 +103,7 @@ export default {
       this.isLoadingLyrics = true
       let url = FETCH_URL + this.id + '/lyrics/'
       logger.default.debug('Fetching lyrics for track "' + this.id + '"')
-      this.$http.get(url).then((response) => {
+      axios.get(url).then((response) => {
         self.lyrics = response.data
         self.isLoadingLyrics = false
       }, (response) => {
diff --git a/front/src/components/library/import/ArtistImport.vue b/front/src/components/library/import/ArtistImport.vue
index 870a886e..fb531439 100644
--- a/front/src/components/library/import/ArtistImport.vue
+++ b/front/src/components/library/import/ArtistImport.vue
@@ -37,8 +37,8 @@
 
 <script>
 import Vue from 'vue'
+import axios from 'axios'
 import logger from '@/logging'
-import config from '@/config'
 
 import ImportMixin from './ImportMixin'
 import ReleaseImport from './ReleaseImport'
@@ -92,9 +92,8 @@ export default Vue.extend({
     fetchReleaseGroupsData () {
       let self = this
       this.releaseGroups.forEach(group => {
-        let url = config.API_URL + 'providers/musicbrainz/releases/browse/' + group.id + '/'
-        let resource = Vue.resource(url)
-        resource.get({}).then((response) => {
+        let url = 'providers/musicbrainz/releases/browse/' + group.id + '/'
+        return axios.get(url).then((response) => {
           logger.default.info('successfully fetched release group', group.id)
           let release = response.data['release-list'].filter(r => {
             return r.status === 'Official'
diff --git a/front/src/components/library/import/BatchDetail.vue b/front/src/components/library/import/BatchDetail.vue
index 762074c1..621078b1 100644
--- a/front/src/components/library/import/BatchDetail.vue
+++ b/front/src/components/library/import/BatchDetail.vue
@@ -52,11 +52,10 @@
 </template>
 
 <script>
-
+import axios from 'axios'
 import logger from '@/logging'
-import config from '@/config'
 
-const FETCH_URL = config.API_URL + 'import-batches/'
+const FETCH_URL = 'import-batches/'
 
 export default {
   props: ['id'],
@@ -75,7 +74,7 @@ export default {
       this.isLoading = true
       let url = FETCH_URL + this.id + '/'
       logger.default.debug('Fetching batch "' + this.id + '"')
-      this.$http.get(url).then((response) => {
+      axios.get(url).then((response) => {
         self.batch = response.data
         self.isLoading = false
         if (self.batch.status === 'pending') {
diff --git a/front/src/components/library/import/BatchList.vue b/front/src/components/library/import/BatchList.vue
index f6e7b03e..8133d8e2 100644
--- a/front/src/components/library/import/BatchList.vue
+++ b/front/src/components/library/import/BatchList.vue
@@ -42,10 +42,10 @@
 </template>
 
 <script>
+import axios from 'axios'
 import logger from '@/logging'
-import config from '@/config'
 
-const BATCHES_URL = config.API_URL + 'import-batches/'
+const BATCHES_URL = 'import-batches/'
 
 export default {
   components: {},
@@ -65,7 +65,7 @@ export default {
       var self = this
       this.isLoading = true
       logger.default.time('Loading import batches')
-      this.$http.get(url, {}).then((response) => {
+      axios.get(url, {}).then((response) => {
         self.results = response.data.results
         self.nextLink = response.data.next
         self.previousLink = response.data.previous
diff --git a/front/src/components/library/import/FileUpload.vue b/front/src/components/library/import/FileUpload.vue
index 93ca75c3..35b7b636 100644
--- a/front/src/components/library/import/FileUpload.vue
+++ b/front/src/components/library/import/FileUpload.vue
@@ -62,10 +62,9 @@
 </template>
 
 <script>
-import Vue from 'vue'
+import axios from 'axios'
 import logger from '@/logging'
 import FileUploadWidget from './FileUploadWidget'
-import config from '@/config'
 
 export default {
   components: {
@@ -74,7 +73,7 @@ export default {
   data () {
     return {
       files: [],
-      uploadUrl: config.API_URL + 'import-jobs/',
+      uploadUrl: 'import-jobs/',
       batch: null
     }
   },
@@ -106,9 +105,7 @@ export default {
     },
     createBatch () {
       let self = this
-      let url = config.API_URL + 'import-batches/'
-      let resource = Vue.resource(url)
-      resource.save({}, {}).then((response) => {
+      return axios.post('import-batches/', {}).then((response) => {
         self.batch = response.data
       }, (response) => {
         logger.default.error('error while launching creating batch')
diff --git a/front/src/components/library/import/ImportMixin.vue b/front/src/components/library/import/ImportMixin.vue
index 475241f3..33c6193b 100644
--- a/front/src/components/library/import/ImportMixin.vue
+++ b/front/src/components/library/import/ImportMixin.vue
@@ -3,9 +3,8 @@
 </template>
 
 <script>
+import axios from 'axios'
 import logger from '@/logging'
-import config from '@/config'
-import Vue from 'vue'
 import router from '@/router'
 
 export default {
@@ -31,10 +30,9 @@ export default {
     launchImport () {
       let self = this
       this.isImporting = true
-      let url = config.API_URL + 'submit/' + self.importType + '/'
+      let url = 'submit/' + self.importType + '/'
       let payload = self.importData
-      let resource = Vue.resource(url)
-      resource.save({}, payload).then((response) => {
+      axios.post(url, payload).then((response) => {
         logger.default.info('launched import for', self.type, self.metadata.id)
         self.isImporting = false
         router.push({
diff --git a/front/src/components/library/import/TrackImport.vue b/front/src/components/library/import/TrackImport.vue
index 2275bcf3..edd444d9 100644
--- a/front/src/components/library/import/TrackImport.vue
+++ b/front/src/components/library/import/TrackImport.vue
@@ -70,9 +70,9 @@
 </template>
 
 <script>
+import axios from 'axios'
 import Vue from 'vue'
 import time from '@/utils/time'
-import config from '@/config'
 import logger from '@/logging'
 import ImportMixin from './ImportMixin'
 
@@ -117,10 +117,8 @@ export default Vue.extend({
     search () {
       let self = this
       this.isLoading = true
-      let url = config.API_URL + 'providers/' + this.currentBackendId + '/search/'
-      let resource = Vue.resource(url)
-
-      resource.get({query: this.query}).then((response) => {
+      let url = 'providers/' + this.currentBackendId + '/search/'
+      axios.get(url, {params: {query: this.query}}).then((response) => {
         logger.default.debug('searching', self.query, 'on', self.currentBackendId)
         self.results = response.data
         self.isLoading = false
diff --git a/front/src/components/library/radios/Builder.vue b/front/src/components/library/radios/Builder.vue
index f58d5003..8d67b61e 100644
--- a/front/src/components/library/radios/Builder.vue
+++ b/front/src/components/library/radios/Builder.vue
@@ -67,7 +67,7 @@
   </div>
 </template>
 <script>
-import config from '@/config'
+import axios from 'axios'
 import $ from 'jquery'
 import _ from 'lodash'
 import BuilderFilter from './Filter'
@@ -107,8 +107,8 @@ export default {
   methods: {
     fetchFilters: function () {
       let self = this
-      let url = config.API_URL + 'radios/radios/filters/'
-      return this.$http.get(url).then((response) => {
+      let url = 'radios/radios/filters/'
+      return axios.get(url).then((response) => {
         self.availableFilters = response.data
       })
     },
@@ -130,8 +130,8 @@ export default {
     },
     fetch: function () {
       let self = this
-      let url = config.API_URL + 'radios/radios/' + this.id + '/'
-      this.$http.get(url).then((response) => {
+      let url = 'radios/radios/' + this.id + '/'
+      axios.get(url).then((response) => {
         self.filters = response.data.config.map(f => {
           return {
             config: f,
@@ -145,7 +145,7 @@ export default {
     },
     fetchCandidates: function () {
       let self = this
-      let url = config.API_URL + 'radios/radios/validate/'
+      let url = 'radios/radios/validate/'
       let final = this.filters.map(f => {
         let c = _.clone(f.config)
         c.type = f.filter.type
@@ -156,7 +156,7 @@ export default {
           {'type': 'group', filters: final}
         ]
       }
-      this.$http.post(url, final).then((response) => {
+      axios.post(url, final).then((response) => {
         self.checkResult = response.data.filters[0]
       })
     },
@@ -173,12 +173,12 @@ export default {
         'config': final
       }
       if (this.id) {
-        let url = config.API_URL + 'radios/radios/' + this.id + '/'
-        this.$http.put(url, final).then((response) => {
+        let url = 'radios/radios/' + this.id + '/'
+        axios.put(url, final).then((response) => {
         })
       } else {
-        let url = config.API_URL + 'radios/radios/'
-        this.$http.post(url, final).then((response) => {
+        let url = 'radios/radios/'
+        axios.post(url, final).then((response) => {
           self.$router.push({
             name: 'library.radios.edit',
             params: {
diff --git a/front/src/components/library/radios/Filter.vue b/front/src/components/library/radios/Filter.vue
index dd170d8b..722ecbfb 100644
--- a/front/src/components/library/radios/Filter.vue
+++ b/front/src/components/library/radios/Filter.vue
@@ -62,6 +62,7 @@
   </tr>
 </template>
 <script>
+import axios from 'axios'
 import config from '@/config'
 import $ from 'jquery'
 import _ from 'lodash'
@@ -132,11 +133,11 @@ export default {
   methods: {
     fetchCandidates: function () {
       let self = this
-      let url = config.API_URL + 'radios/radios/validate/'
+      let url = 'radios/radios/validate/'
       let final = _.clone(this.config)
       final.type = this.filter.type
       final = {'filters': [final]}
-      this.$http.post(url, final).then((response) => {
+      axios.post(url, final).then((response) => {
         self.checkResult = response.data.filters[0]
       })
     }
diff --git a/front/src/components/metadata/CardMixin.vue b/front/src/components/metadata/CardMixin.vue
index 78aae5e7..a7cd476f 100644
--- a/front/src/components/metadata/CardMixin.vue
+++ b/front/src/components/metadata/CardMixin.vue
@@ -3,11 +3,9 @@
 </template>
 
 <script>
+import axios from 'axios'
 import logger from '@/logging'
 
-import config from '@/config'
-import Vue from 'vue'
-
 export default {
   props: {
     mbId: {type: String, required: true}
@@ -25,9 +23,8 @@ export default {
     fetchData () {
       let self = this
       this.isLoading = true
-      let url = config.API_URL + 'providers/musicbrainz/' + this.type + 's/' + this.mbId + '/'
-      let resource = Vue.resource(url)
-      resource.get({}).then((response) => {
+      let url = 'providers/musicbrainz/' + this.type + 's/' + this.mbId + '/'
+      axios.get(url).then((response) => {
         logger.default.info('successfully fetched', self.type, self.mbId)
         self.data = response.data[self.type]
         this.$emit('metadata-changed', self.data)
diff --git a/front/src/config.js b/front/src/config.js
index 76a6f5e5..b0ceb789 100644
--- a/front/src/config.js
+++ b/front/src/config.js
@@ -4,7 +4,7 @@ class Config {
     if (this.BACKEND_URL === '/') {
       this.BACKEND_URL = window.location.protocol + '//' + window.location.hostname + ':' + window.location.port
     }
-    if (!this.BACKEND_URL.slice(-1) === '/') {
+    if (this.BACKEND_URL.slice(-1) !== '/') {
       this.BACKEND_URL += '/'
     }
     this.API_URL = this.BACKEND_URL + 'api/v1/'
diff --git a/front/src/main.js b/front/src/main.js
index f7a6b65f..92711be5 100644
--- a/front/src/main.js
+++ b/front/src/main.js
@@ -8,9 +8,10 @@ logger.default.debug('Environment variables:', process.env)
 import Vue from 'vue'
 import App from './App'
 import router from './router'
-import VueResource from 'vue-resource'
+import axios from 'axios'
 import VueLazyload from 'vue-lazyload'
 import store from './store'
+import config from './config'
 
 window.$ = window.jQuery = require('jquery')
 
@@ -19,25 +20,33 @@ window.$ = window.jQuery = require('jquery')
 // require('./semantic/semantic.css')
 require('semantic-ui-css/semantic.js')
 
-Vue.use(VueResource)
 Vue.use(VueLazyload)
 Vue.config.productionTip = false
 
-Vue.http.interceptors.push(function (request, next) {
-  // modify headers
+axios.defaults.baseURL = config.API_URL
+axios.interceptors.request.use(function (config) {
+  // Do something before request is sent
   if (store.state.auth.authenticated) {
-    request.headers.set('Authorization', store.getters['auth/header'])
+    config.headers['Authorization'] = store.getters['auth/header']
   }
-  next(function (response) {
-    // redirect to login form when we get unauthorized response from server
-    if (response.status === 401) {
-      store.commit('auth/authenticated', false)
-      logger.default.warn('Received 401 response from API, redirecting to login form')
-      router.push({name: 'login', query: {next: router.currentRoute.fullPath}})
-    }
-  })
+  return config
+}, function (error) {
+  // Do something with request error
+  return Promise.reject(error)
 })
 
+// Add a response interceptor
+axios.interceptors.response.use(function (response) {
+  if (response.status === 401) {
+    store.commit('auth/authenticated', false)
+    logger.default.warn('Received 401 response from API, redirecting to login form')
+    router.push({name: 'login', query: {next: router.currentRoute.fullPath}})
+  }
+  return response
+}, function (error) {
+  // Do something with response error
+  return Promise.reject(error)
+})
 store.dispatch('auth/check')
 /* eslint-disable no-new */
 new Vue({
diff --git a/front/src/store/auth.js b/front/src/store/auth.js
index 6021f30f..e276d0a1 100644
--- a/front/src/store/auth.js
+++ b/front/src/store/auth.js
@@ -1,13 +1,8 @@
-import Vue from 'vue'
+import axios from 'axios'
 import jwtDecode from 'jwt-decode'
-import config from '@/config'
 import logger from '@/logging'
 import router from '@/router'
 
-const LOGIN_URL = config.API_URL + 'token/'
-const REFRESH_TOKEN_URL = config.API_URL + 'token/refresh/'
-const USER_PROFILE_URL = config.API_URL + 'users/users/me/'
-
 export default {
   namespaced: true,
   state: {
@@ -56,8 +51,7 @@ export default {
   actions: {
     // Send a request to the login URL and save the returned JWT
     login ({commit, dispatch, state}, {next, credentials, onError}) {
-      let resource = Vue.resource(LOGIN_URL)
-      return resource.save({}, credentials).then(response => {
+      return axios.post('token/', credentials).then(response => {
         logger.default.info('Successfully logged in as', credentials.username)
         commit('token', response.data.token)
         commit('username', credentials.username)
@@ -92,8 +86,7 @@ export default {
       }
     },
     fetchProfile ({commit, dispatch, state}) {
-      let resource = Vue.resource(USER_PROFILE_URL)
-      return resource.get({}).then((response) => {
+      return axios.get('users/users/me/').then((response) => {
         logger.default.info('Successfully fetched user profile')
         let data = response.data
         commit('profile', data)
@@ -108,8 +101,7 @@ export default {
       })
     },
     refreshToken ({commit, dispatch, state}) {
-      let resource = Vue.resource(REFRESH_TOKEN_URL)
-      return resource.save({}, {token: state.token}).then(response => {
+      return axios.post('token/refresh/', {token: state.token}).then(response => {
         logger.default.info('Refreshed auth token')
         commit('token', response.data.token)
       }, response => {
diff --git a/front/src/store/favorites.js b/front/src/store/favorites.js
index 9337966f..a4f85b23 100644
--- a/front/src/store/favorites.js
+++ b/front/src/store/favorites.js
@@ -1,10 +1,6 @@
-import Vue from 'vue'
-import config from '@/config'
+import axios from 'axios'
 import logger from '@/logging'
 
-const REMOVE_URL = config.API_URL + 'favorites/tracks/remove/'
-const FAVORITES_URL = config.API_URL + 'favorites/tracks/'
-
 export default {
   namespaced: true,
   state: {
@@ -35,16 +31,14 @@ export default {
     set ({commit, state}, {id, value}) {
       commit('track', {id, value})
       if (value) {
-        let resource = Vue.resource(FAVORITES_URL)
-        resource.save({}, {'track': id}).then((response) => {
+        return axios.post('favorites/tracks/', {'track': id}).then((response) => {
           logger.default.info('Successfully added track to favorites')
         }, (response) => {
           logger.default.info('Error while adding track to favorites')
           commit('track', {id, value: !value})
         })
       } else {
-        let resource = Vue.resource(REMOVE_URL)
-        resource.delete({}, {'track': id}).then((response) => {
+        return axios.post('favorites/tracks/remove/', {'track': id}).then((response) => {
           logger.default.info('Successfully removed track from favorites')
         }, (response) => {
           logger.default.info('Error while removing track from favorites')
@@ -57,9 +51,8 @@ export default {
     },
     fetch ({dispatch, state, commit}, url) {
       // will fetch favorites by batches from API to have them locally
-      url = url || FAVORITES_URL
-      let resource = Vue.resource(url)
-      resource.get().then((response) => {
+      url = url || 'favorites/tracks/'
+      return axios.get(url).then((response) => {
         logger.default.info('Fetched a batch of ' + response.data.results.length + ' favorites')
         response.data.results.forEach(result => {
           commit('track', {id: result.track, value: true})
diff --git a/front/src/store/player.js b/front/src/store/player.js
index 9e50d6c1..fb348042 100644
--- a/front/src/store/player.js
+++ b/front/src/store/player.js
@@ -1,5 +1,4 @@
-import Vue from 'vue'
-import config from '@/config'
+import axios from 'axios'
 import logger from '@/logging'
 import time from '@/utils/time'
 
@@ -70,9 +69,7 @@ export default {
       commit('playing', !state.playing)
     },
     trackListened ({commit}, track) {
-      let url = config.API_URL + 'history/listenings/'
-      let resource = Vue.resource(url)
-      resource.save({}, {'track': track.id}).then((response) => {}, (response) => {
+      return axios.post('history/listenings/', {'track': track.id}).then((response) => {}, (response) => {
         logger.default.error('Could not record track in history')
       })
     },
diff --git a/front/src/store/radios.js b/front/src/store/radios.js
index 600b24b3..922083d8 100644
--- a/front/src/store/radios.js
+++ b/front/src/store/radios.js
@@ -1,10 +1,6 @@
-import Vue from 'vue'
-import config from '@/config'
+import axios from 'axios'
 import logger from '@/logging'
 
-const CREATE_RADIO_URL = config.API_URL + 'radios/sessions/'
-const GET_TRACK_URL = config.API_URL + 'radios/tracks/'
-
 export default {
   namespaced: true,
   state: {
@@ -39,13 +35,12 @@ export default {
   },
   actions: {
     start ({commit, dispatch}, {type, objectId, customRadioId}) {
-      let resource = Vue.resource(CREATE_RADIO_URL)
       var params = {
         radio_type: type,
         related_object_id: objectId,
         custom_radio: customRadioId
       }
-      resource.save({}, params).then((response) => {
+      return axios.post('radios/sessions/', params).then((response) => {
         logger.default.info('Successfully started radio ', type)
         commit('current', {type, objectId, session: response.data.id, customRadioId})
         commit('running', true)
@@ -62,12 +57,10 @@ export default {
       if (!state.running) {
         return
       }
-      let resource = Vue.resource(GET_TRACK_URL)
       var params = {
         session: state.current.session
       }
-      let promise = resource.save({}, params)
-      promise.then((response) => {
+      return axios.post('radios/tracks/', params).then((response) => {
         logger.default.info('Adding track to queue from radio')
         dispatch('queue/append', {track: response.data.track}, {root: true})
       }, (response) => {
-- 
GitLab