Getting Started With Vue and Vapor

Vue.js provides declarative rendering and a component system to simplify building interactive web apps. In this tutorial, you’ll learn how to add a Vue frontend on top of a Vapor and Swift backend. By Joannis Orlandos.

4.7 (3) · 2 Reviews

Download materials
Save for later
You are currently viewing page 2 of 3 of this article. Click here to view the first page.

Creating a Basic Layout

First, for a clean starting point, delete the existing components directory. Then, delete all the code from the template and script sections.

Next, replace the contents of the template tag with:

<div class="container">
  <div class="col-sm-12 col-md-6 offset-md-3 offset-sm-0">
    <!-- Website Contents Here -->

This code sets up a bootstrap layout container with various responsive formats. A bootstrap layout is 12 columns wide. Because of col-sm-12, small, or sm, display sizes will take the full 12 column width, ensuring mobile users see their screen space used effectively.

When using the same pattern, medium, or md, display sizes use only half of the available columns. Any larger display sizes implicitly use the next lowest one, such as medium for large displays.

offset-md-3 means you get three columns of spacing to the left of the content, so it appears in the center.

Implementing Functionality

Next, replace the contents of the script tag with the following code:

export default {
  name: 'App',
  components: {
    // 1
  data() {
    // 2
    return {
      // The model received from Vapor. Contains an `id` and 
      // `answers` as an array of strings
      guess: Object,
      // `true` when successfully guessed, `false` when 
      // unsuccessfully guessed. Null when not guessed.
      correct: Boolean | undefined,
      // The selected guess, in the list `guess.answers`
      selected: Number | undefined,
      // The total amount of attempted guesses
      totalGuesses: Number,
      // The amount of correct guesses
      correctGuesses: Number,
      // Used to hide the UI when reloading
      updatingGuess: Boolean,
  methods: { // 3
    reloadGuess() {
      // 4
  mounted() {
    // 5
    this.totalGuesses = 0;
    this.correctGuesses = 0;
    this.correct = null;


Here’s what you added:

  1. Allows importing any external components used as part of this component. You’ll use this later.
  2. This data function defines the schema of the state that this component relies on.
  3. This methods function defines any functional implementations of this component, used by lifecycle hooks or user interaction.
  4. A specific definition of a function that will load new article titles to guess.
  5. A function that Vue calls when the component is inserted into the DOM. In this scenario, this initializes the state to default values.

Running the Backend

Now it’s time to get your backend running. Open a new Terminal window. Navigate to the Backend Vapor app contained in the downloaded tutorial materials and run:

vapor run serve

This code will compile and run the Vapor app. Backend development has never been so simple!

Reloading Guesses

As mentioned previously, you’ll use axios to load data from HTTP APIs. Before you can use axios, you have to import it. Add the following at the top of the script section in App.vue:

import axios from 'axios';

With axios imported, the script can now use this library. To load a guess from your Vapor Backend API running locally, the imported axios object has a get method to make requests. Calling this will return a Promise.

Note: If you’ve previously done asynchronous programming, Promises will feel familiar. In fact, they use many of the same concepts you may have seen in SwiftNIO. For a Swift refresher, check out SwiftNIO: A simple guide to async on the server

Continue by updating the reloadGuess implementation:

reloadGuess() {
  this.updatingGuess = true;
  // 1
  axios.get('http://localhost:8081/guess').then(response => {
    // 2
    this.updatingGuess = false;
    this.guess =;
    this.selected = null;
    // 3
    setTimeout(this.hideAlert, 3000);
hideAlert() {
  this.correct = null;

Here you:

  1. First, fetch the next guess object. This prompts the API to load new article titles and pass on a compilation of them.
  2. Then, once fetched, update the local state to represent the guess.
  3. Finally, after three seconds, hide the message containing an indication of success or failure for previous guesses.

Creating the Guess UI

Now that the guesses are loading, it’s time to render them in the UI. Add the following code where you find a comment marking the website’s content location:

  <!-- Add the guess success/failure message -->
  <h2>Which article is from</h2>
  <h3>You've guessed {{correctGuesses}} out of {{totalGuesses}} correctly!</h3>
  <ul class="list-group mt-5">
      :class="selected === index ? 'list-group-item active' 
        : 'list-group-item'"
      v-for="(option, index) in guess.answers"
  <!-- Add the Submit Button -->

There’s a lot going on there! Here’s a breakdown:

  • First, HTML classes don’t usually include a colon as a prefix. This colon tells Vue that you computed the class attribute from a JavaScript expression. This expression checks whether the index value matches the selected index in the component’s state.
  • Next, v-for tells Vue this element should repeat for each element in guess.answers. Since Vue needs to see each element as unique, you need a key attribute for Vue to distinguish the views. The index in the array serves as a simple and unique key.
  • Finally, you use the string in option, which is read from the answers array, in the template using a mustache notation. This renders the string as part of the HTML in that position.

Look at what you’ve created! Make sure the guesses are loading. The game will look like this:


Sending Guesses

Nothing happens when you click any of the titles! That’s because there’s no input handling. Luckily, handling events in Vue is straightforward.

Add the following line of code to the li element above:

@click="() => selectAnswer(index)"

This registers a left-click handler on each of the list items, calling the function selectAnswer. However, there’s no definition or implementation for selecting answers yet.

As before, functional implementations belong in the methods block. Add the following implementation there:

selectAnswer(index) {
  this.selected = index;

Make sure to separate each of the methods by a comma. You should include a trailing comma after each object value or array element whenever your code spans multiple lines. It’s an excellent Javascript habit and common code style.

Save the file. In your reloaded browser app, click one of the titles. You’ll see it highlighted like this: