SpotifyRandomizer REST API Backend


Link to repository: github.com/zysktomasz/spotify-randomizer


Overview

SpotifyRandomizer Backend - handles authenticated communication with Spotify API.

Exposes a few REST endpoints that can be used by clients (such as SpotifyRandomizer React Client) to invoke such actions as: retrieving authenticated user details, their playlists and songs, as well as a way to automatically reorganize order of songs in selected playlists.


Technologies used


Architecture

spotifyrandomizer backend architecture diagram

Rest API

Application exposes a few API endpoints. It allows to:

  • GET /api/spotify/playlist - get user playlists
  • GET /api/spotify/playlist/{playlistId}/tracks - get playlist tracks
  • PUT /api/spotify/playlist/{playlistId} - reorder songs in playlists

Authentication

Application follows Authorization Code Flow described in Spotify Authorization Guide to authenticate user.

Authentication is done by communication between backend (this project) and Spotify API through usage of thelinmichael/spotify-web-api-java.

This application secures its endpoints by JWT.

Docker

Application is dockerized.

Deployment

Docker image is built and deployed to Google Cloud Run.

Cloud Run is scaled to 0 - meaning that it is turned off when not in use and requires little time to spin up when invoked.

Entire process of image building and deployment is handled by Google Cloud Build and described later in this document.


Google Cloud Runtime Config Environments Configuration

To avoid storing sensitive information, like API secrets a number of application properties set in application.yml files are bootstrapped from Google Cloud Runtime Config environments. To access and manage them one has to have Cloud SDK installed with beta runtime-config added.

Spring Cloud Google Cloud Config project is used to achieve this functionality. It allows for application to load these properties from GCP environment during startup.


Continuous Integration & Continuous Deployment

Github Actions are used to achieve CI/CD. Actions are configured in github-ci.yml

Steps done during CI:

  1. Install Java SDK on Ubuntu 20.04
  2. Load cached maven packages (if available) from previous builds, to speed up process
  3. Run tests and build reports (by running mvn site)
  4. Verify output of previous step (mvn verify)
  5. Upload reports as Github artifacts - makes it possible to download and analyze

Steps done during CD:

  1. Check condition to confirm that master branch can run deployment job.
  2. Configure Cloud SDK with credentials stored in Github Secrets
  3. Build and push Docker image to Google Artifact Registry
  4. Deploy image to Cloud Run
name: Java Maven CI

on: [ push ]

env:
  PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
  SERVICE_ACCOUNT_KEY: ${{ secrets.GCP_SA_KEY }}
  ARTIFACT_REPOSITORY_NAME: spotifyrandomizer-repo
  SERVICE: spotifyrandomizer-backend
  REGION: europe-central2

jobs:
  test_and_build_reports:
    runs-on: ubuntu-20.04
    steps:
      - uses: actions/checkout@v2
      - run: |
          download_url="https://github.com/AdoptOpenJDK/openjdk16-binaries/releases/download/jdk-16.0.1%2B9/OpenJDK16U-jdk_x64_linux_hotspot_16.0.1_9.tar.gz"
          wget -O $RUNNER_TEMP/java_package.tar.gz $download_url
      - name: Set up JDK 16
        uses: actions/setup-java@v2
        with:
          distribution: 'jdkfile'
          jdkFile: ${{ runner.temp }}/java_package.tar.gz
          java-version: '16.0.1'
          architecture: x64
      - name: Cache Maven packages
        uses: actions/cache@v2
        with:
          path: ~/.m2
          key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
          restore-keys: ${{ runner.os }}-m2
      - name: mvn site - build reports
        run: mvn site
      - name: mvn verify
        run: mvn verify
      - name: Archive project reports (tests and coverage)
        uses: actions/upload-artifact@v2
        with:
          name: reports
          path: target/site
  build_and_release:
    if: ${{ github.ref == 'refs/heads/master' }}
    needs: test_and_build_reports
    runs-on: ubuntu-20.04
    steps:
      - uses: actions/checkout@v2
      - name: Set up Cloud SDK
        uses: google-github-actions/setup-gcloud@master
        with:
          project_id: ${{ env.PROJECT_ID }}
          service_account_key: ${{ env.SERVICE_ACCOUNT_KEY }}
          export_default_credentials: true
      - name: Authorize Docker push
        run: gcloud auth configure-docker europe-central2-docker.pkg.dev
      - name: Build and push to Artifact Registry
        run: |-
          docker build -t europe-central2-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.ARTIFACT_REPOSITORY_NAME }}/${{ env.SERVICE }}:${{ github.sha }} .
          docker push europe-central2-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.ARTIFACT_REPOSITORY_NAME }}/${{ env.SERVICE }}:${{ github.sha }}
      - name: Deploy to Cloud Run
        run: |-
          gcloud run deploy ${{ env.SERVICE }} \
            --region ${{ env.REGION }} \
            --image europe-central2-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.ARTIFACT_REPOSITORY_NAME }}/${{ env.SERVICE }}:${{ github.sha }} \
            --platform "managed" \