Vue

Learn how to configure Vue for use with Filebase.

What is Vue?

Vue is an open-source JavaScript framework used for building user interfaces and single-page applications (SPAs). Vue is designed to be incrementally adoptable, which means that it can be integrated into an existing project or used to build a new project from scratch. It is also highly modular, with a core library that focuses on the view layer of an application and a set of optional libraries that can be used to add more functionality.

Read below to learn how to use Vue with Filebase.

Prerequisites:

1. Start by creating a new directory for your Vue app, then navigate into that directory and initialize the workspace:

mkdir filebase-vue-app

cd filebase-vue-app

npm init

Accept the default options when prompted.

2. Next, install the following packages:

npm install --save express multer dotenv cors body-parser mongodb multer-s3 aws-sdk

3. Create an .env file with the following environment variables:

DATABASE=mongodb://127.0.0.1:27017/
PORT=5005
AWSAccessKeyId=FILEBASE_ACCESS_KEY
AWSSecretKey=FILEBASE_SECRET_KEY
AWSRegion=us-east-1
AWSBucket=filebase-bucket-name

Replace the environment variable values with the values that match your Filebase account and MongoDB configuration.

4. Create a new file called index.js that contains the following code:

const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')
const dotenv = require('dotenv')
const aws = require('aws-sdk')
const multer = require('multer')
const multerS3 = require('multer-s3')
const mongodb = require('mongodb')

dotenv.config()
const app = express()
//middleWare
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))
app.use(cors())

aws.config.update({
  apiVersion: "2006-03-01",
  accessKeyId: process.env.AWSAccessKeyId,
  secretAccessKey: process.env.AWSSecretKey,
  region: process.env.AWSRegion
  endpoint: "https://s3.filebase.com",
})

const s3 = new aws.S3()

const upload = multer({
  storage: multerS3({
    s3: s3,
    bucket: process.env.AWSBucket,
    acl: "public-read",
    contentType: multerS3.AUTO_CONTENT_TYPE,
    metadata: (req, file, cb) => {
      cb(null, { fieldName: file.fieldname})
    },
    key: (req, file, cb) => {
      cb(null, Date.now().toString() + file.originalname)
    }
  })
})

app.get('/', async (req, res) => {
  res.status(200).send('S3 Upload Backend')
})

app.post('/', upload.single('photo'), async (req, res) => {
  try {
    const users = await loadUsersCollection();
    await users.insertOne({
      first_name: req.body.first_name,
      last_name: req.body.last_name,
      phone: req.body.phone,
      email: req.body.email,
      gender: req.body.gender,
      photo: req.file.location,
    })
    res.status(201).send('success')
  }
  catch (err) {
    res.status(500).send({
      error: 'error occured creating user'
    })
  }
})
async function loadUsersCollection () {
  const client = await mongodb.MongoClient.connect(process.env.DATABASE, {
    useNewUrlParser: true,
    useUnifiedTopology: true
  })
  return client.db('vue-multers3').collection('users')
}

const port = process.env.PORT || 5000
app.listen(port, () => {
  console.log(server started on port ${port})
});

5. Then, start the server with the command:

node index.js

6. Next, install the Vue package to get started on the front end of the Vue app:

npm install -g @vue/cli

7. Then, create a new Vue app with the command:

vue create filebase-vue-app

8. Navigate inside the new Vue app directory and add the Vuetify package:

cd vue-multers3-frontend

vue add vuetify

9. Then, start the Vue front end with the command:

npm run serve

10. Navigate to the localhost:8080 address to view the Vue app:

11. Next, create a new file called register.vue in the components folder. Insert the following code into this file:

<template>
  <v-container fluid class="my-3">
    <v-row align="center" justify="center">
      <v-col cols="12">
        <v-card style="width: 100%" flat>
          <div class="text-center pt-6"><h1 class="font-weight-light display-2 primary--text">Register!</h1></div>
          <v-row class="pa-4">
            <v-col cols="12" md="6">
              <v-img src="@/assets/contactus.jpg" class="d-block ml-auto mr-auto" max-width="350px" />
            </v-col>
            <v-col cols="12" md="6">
              <v-form ref="forma" v-model="form1" lazy-validation>
                <v-row>
                  <v-col
                    cols="12"
                    md="6"
                  >
                    <v-text-field
                      v-model="first_name"
                      label="First Name"
                      outlined
                      dense
                      hide-details
                    ></v-text-field>
                  </v-col>
                  <v-col
                    cols="12"
                    md="6"
                  >
                    <v-text-field
                      v-model="last_name"
                      label="Last Name"
                      outlined
                      dense
                      hide-details
                    ></v-text-field>
                  </v-col>
                  <v-col
                    cols="12"
                    md="6"
                  >
                    <v-text-field
                      v-model="phone"
                      label="Phone"
                      outlined
                      dense
                      hide-details
                    ></v-text-field>
                  </v-col>
                  <v-col
                    cols="12"
                    md="6"
                  >
                    <v-text-field
                      v-model="email"
                      label="Email"
                      outlined
                      dense
                      hide-details
                    ></v-text-field>
                  </v-col>
                  <v-col
                    cols="12"
                    md="6"
                  >
                    <v-text-field
                      v-model="age"
                      type="number"
                      label="Age"
                      outlined
                      dense
                      hide-details
                    ></v-text-field>
                  </v-col>
                  <v-col
                    cols="12"
                    md="6"
                  >
                    <v-file-input
                      v-model="photo"
                      :rules="photoRules"
                      accept="image/png, image/jpeg"
                      label="Pick a Picture"
                      outlined
                      dense
                      prepend-icon=""
                      prepend-inner-icon="mdi-camera"
                      hide-details
                    >
                    </v-file-input>
                  </v-col>
                  <v-col
                    cols="12"
                    md="6"
                  >
                    <v-text-field
                      v-model="password"
                      :append-icon="show1 ? 'mdi-eye' : 'mdi-eye-off'"
                      :rules="passwordRules"
                      :type="show1 ? 'text' : 'password'"
                      hint="At least 6 characters"
                      @click:append="show1 = !show1"
                      outlined
                      dense
                      hide-details
                    >
                    </v-text-field>
                  </v-col>
                  <v-col
                    cols="12"
                    md="6"
                  >
                    <v-text-field
                      v-model="confirmPassword"
                      :append-icon="show1 ? 'mdi-eye' : 'mdi-eye-off'"
                      :rules="passwordConfirmation"
                      :type="show1 ? 'text' : 'password'"
                      hint="At least 6 characters"
                      @click:append="show1 = !show1"
                      outlined
                      dense
                      hide-details
                    >
                    </v-text-field>
                  </v-col>
                  <v-col
                    cols="12"
                    md="12"
                  >
                    <v-text-field
                      v-model="address"
                      label="Address"
                      outlined
                      dense
                      hide-details
                    ></v-text-field>
                  </v-col>
                  <v-col
                    cols="12"
                  >
                    <v-btn
                      color="primary"
                      rounded
                      block
                      class="mt-3"
                      @click="onSubmit"
                      :disabled="!form1"
                    >
                      Submit
                    </v-btn>
                  </v-col>
                </v-row>
              </v-form>
            </v-col>
          </v-row>
        </v-card>
      </v-col>
    </v-row>
    <v-snackbar
      v-model="snackbar"
      :timeout="timeout"
      color="success"
      top
    >
      {{ message }}
    </v-snackbar>
  </v-container>
</template>

<script>
export default {
  data () {
    return {
      message: 'success',
      snackbar: false,
      timeout: 2000,
      show1: false,
      form1: false,
      submitSuccess: false,
      first_name: '',
      last_name: '',
      phone: '',
      email: '',
      age: '',
      photo: null,
      address: '',
      password: '',
      confirmPassword: '',
      photoRules: [v => !v || v.size < 5000000 || 'Image should be less than 5MB'],
      passwordRules: [v => !!v || 'Password is required',
        v => (v && v.length >= 6) || 'password should be 6 characters'],
      passwordConfirmation: [v => !!v || 'Password is required',
        v => (v === this.password) || 'password should match'],
      required: [value => !!value || 'Required.']
    }
  }
}
</script>

<style>
</style>

12. Then, insert the following code in the app.vue file:

<template>
  <v-app>
    <v-app-bar
      app
      color="primary"
      dark
    >
      <div class="d-flex align-center">
        <v-img
          alt="Vuetify Logo"
          class="shrink mr-2"
          contain
          src="<https://cdn.vuetifyjs.com/images/logos/vuetify-logo-dark.png>"
          transition="scale-transition"
          width="40"
        />

        <v-img
          alt="Vuetify Name"
          class="shrink mt-1 hidden-sm-and-down"
          contain
          min-width="100"
          src="<https://cdn.vuetifyjs.com/images/logos/vuetify-name-dark.png>"
          width="100"
        />
      </div>

      <v-spacer></v-spacer>

      <v-btn
        href="<https://github.com/vuetifyjs/vuetify/releases/latest>"
        target="_blank"
        text
      >
        <span class="mr-2">Latest Release</span>
        <v-icon>mdi-open-in-new</v-icon>
      </v-btn>
    </v-app-bar>

    <v-main>
      <Register/>
    </v-main>
  </v-app>
</template>

<script>
import Register from './components/Register'
export default {
  name: 'App',
  components: {
    Register
  },
  data: () => ({
    //
  })
}
</script>

13. If you refresh your Vue app, it should now resemble this:

14. Next, install the axois package:

npm install axios

15. Then, create the file registeraxios.vue in the components folder and insert the following code:

<template>
      <v-container fluid class="my-3">
        <v-row align="center" justify="center">
          <v-col cols="12">
            <v-card style="width: 100%" flat>
              <div class="text-center pt-6"><h1 class="font-weight-light display-2 primary--text">Register!</h1></div>
              <v-row class="pa-4">
                <v-col cols="12" md="6">
                  <v-img src="@/assets/contactus.jpg" class="d-block ml-auto mr-auto" max-width="350px" />
                </v-col>
                <v-col cols="12" md="6">
                  <v-form ref="forma" v-model="form1" lazy-validation>
                    <v-row>
                      <v-col
                        cols="12"
                        md="6"
                      >
                        <v-text-field
                          v-model="first_name"
                          label="First Name"
                          outlined
                          dense
                          hide-details
                        ></v-text-field>
                      </v-col>
                      <v-col
                        cols="12"
                        md="6"
                      >
                        <v-text-field
                          v-model="last_name"
                          label="Last Name"
                          outlined
                          dense
                          hide-details
                        ></v-text-field>
                      </v-col>
                      <v-col
                        cols="12"
                        md="6"
                      >
                        <v-text-field
                          v-model="phone"
                          label="Phone"
                          outlined
                          dense
                          hide-details
                        ></v-text-field>
                      </v-col>
                      <v-col
                        cols="12"
                        md="6"
                      >
                        <v-text-field
                          v-model="email"
                          label="Email"
                          outlined
                          dense
                          hide-details
                        ></v-text-field>
                      </v-col>
                      <v-col
                        cols="12"
                        md="6"
                      >
                        <v-text-field
                          v-model="age"
                          type="number"
                          label="Age"
                          outlined
                          dense
                          hide-details
                        ></v-text-field>
                      </v-col>
                      <v-col
                        cols="12"
                        md="6"
                      >
                        <v-file-input
                          v-model="photo"
                          :rules="photoRules"
                          accept="image/png, image/jpeg"
                          label="Pick a Picture"
                          outlined
                          dense
                          prepend-icon=""
                          prepend-inner-icon="mdi-camera"
                          hide-details
                        >
                        </v-file-input>
                      </v-col>
                      <v-col
                        cols="12"
                        md="6"
                      >
                        <v-text-field
                          v-model="password"
                          :append-icon="show1 ? 'mdi-eye' : 'mdi-eye-off'"
                          :rules="passwordRules"
                          :type="show1 ? 'text' : 'password'"
                          hint="At least 6 characters"
                          @click:append="show1 = !show1"
                          outlined
                          dense
                          hide-details
                        >
                        </v-text-field>
                      </v-col>
                      <v-col
                        cols="12"
                        md="6"
                      >
                        <v-text-field
                          v-model="confirmPassword"
                          :append-icon="show1 ? 'mdi-eye' : 'mdi-eye-off'"
                          :rules="passwordConfirmation"
                          :type="show1 ? 'text' : 'password'"
                          hint="At least 6 characters"
                          @click:append="show1 = !show1"
                          outlined
                          dense
                          hide-details
                        >
                        </v-text-field>
                      </v-col>
                      <v-col
                        cols="12"
                        md="12"
                      >
                        <v-text-field
                          v-model="address"
                          label="Address"
                          outlined
                          dense
                          hide-details
                        ></v-text-field>
                      </v-col>
                      <v-col
                        cols="12"
                      >
                        <v-btn
                          color="primary"
                          rounded
                          block
                          class="mt-3"
                          @click="onSubmit"
                          :disabled="!form1"
                        >
                          Submit
                        </v-btn>
                      </v-col>
                    </v-row>
                  </v-form>
                </v-col>
              </v-row>
            </v-card>
          </v-col>
        </v-row>
        <v-snackbar
          v-model="snackbar"
          :timeout="timeout"
          color="success"
          top
        >
          {{ message }}
        </v-snackbar>
      </v-container>
    </template>
    
    <script>
    import axios from 'axios'
    const url = '<http://localhost:5005/>'
    export default {
      data () {
        return {
          message: 'submission success',
          snackbar: false,
          timeout: 4000,
          show1: false,
          form1: false,
          submitSuccess: false,
          first_name: '',
          last_name: '',
          phone: '',
          email: '',
          age: '',
          photo: null,
          address: '',
          password: '',
          confirmPassword: '',
          photoRules: [v => !v || v.size < 5000000 || 'Image should be less than 5MB'],
          passwordRules: [v => !!v || 'Password is required',
            v => (v && v.length >= 6) || 'password should be 6 characters'],
          passwordConfirmation: [v => !!v || 'Password is required',
            v => (v === this.password) || 'password should match'],
          required: [value => !!value || 'Required.']
        }
      },
      computed: {
        photoValidation () {
          if (this.photo) {
            return true
          } else return false
        }
      },
      methods: {
        clearForm () {
          this.$refs.forma.reset()
        },
        async onSubmit () {
          if (this.$refs.forma.validate() && this.photoValidation) {
            const blob = this.photo
            const formData = new FormData()
            formData.append('first_name', this.first_name)
            formData.append('last_name', this.last_name)
            formData.append('photo', blob)
            formData.append('phone', this.phone)
            formData.append('email', this.email)
            formData.append('age', this.age)
            formData.append('password', this.password)
            formData.append('address', this.address)
    
            axios.post(url, formData).then((res) => {
              if (res.status === 201) {
                console.log(res)
                this.clearForm()
                this.snackbar = true
              }
            }).catch((err) => {
              console.log(err.response)
            })
          }
        }
      }
    }
    </script>
    
    <style>
    
    </style>

16. Now, when a user submits the form in the Vue app, the image file they include in the form will be uploaded to the configured Filebase bucket!

If you have any questions, please join our Discord server, or send us an email at hello@filebase.com

Last updated