In this post, we are going to learn how to add a Vue project that will utilize the contacts API we created a few weeks ago using a client-generated by NSwag. This post is part of the revamp of the ASP.NET Core Basics repo that was kicked off when .NET Core 3.0 was released which is now targeting .NET Core 3.1.
Create the Vue Project
Unlike the rest of the projects in this series, there is no .NET CLI template from Microsoft that has Vue support so to crate the Vue project we will be using the Vue CLI. Before getting started ensure you have npm installed.
npm install -g @vue/cli
Next, use the following command to start the project creation process using the Vue CLI. Keep in mind that the CLI creates a directory with the project name.
vue create contacts-vue
The above command kicks off a series of questions about the application. This sample is going to use TypeScript which means that the default can’t be used so we need to select Manually select features.
For the next question, we need to select TypeScript. I also included the Router and Linter / Formatter. I also found out later in the process that Babel was needed so feel free to select it on this question.
The project creation process asked a bunch more questions that I basically took the defaults on. Here is a screenshot of all the questions and the options I used.
Now that the project is created if we need to change directories to the one created in the above process.
cd contacts-vue
Use the following command to run the new project.
npm run serve
Use NSwagStudio to Generate an API Client
NSwag provides multiple options for client generation including a CLI, code, or a Windows application. This post is going to use the Windows application which is called NSwagStudio. NSwagStudio can be downloaded and installed from here.
Next, make sure your API is running and get the URL of its OpenAPI/Swagger specification URL. For example, using a local instance of the sample solution’s Contacts API the URL is https://localhost:5001/swagger/v1/swagger.json. If you are using the Swagger UI you can find a link to your swagger.json under the API title.
Now that we have the OpenAPI/Swager specification URL for the API switch over to NSwagStudio. The application will open with a new document ready to go. There are a few options we will need to set. First, select the OpenAPI/Swagger Specification tab and enter your API’s specification URL in the Specification URL box.
In the Outputs section check the TypeScript Client checkbox and then select the TypeScript Client tab. There are a lot of options to play with, the highlighted options are the ones that are important for this sample. First, make sure Module name and Namespace are both empty. I’m sure there is a way to get the client working with a module or namespace, but I didn’t have any luck. For Template, we just need a Fetch based client. The final option that needs to be set is the Output file path and this is the location you want the generated file to be. I output to the Vue project directory under /src/apis/contactApi.ts. After all the options are set click Generate Files.
Create UI and Use Generated Client
Note that I haven’t touch Vue in a long time so the actually UI bits may or may not be the “proper” way to do this stuff in Vue, but it should be understandable enough that you can see how the API client is used. As with the other post in this same vein, we are going to create a contact list that gets its data from an API.
First, we are going to create a new component for the contact list in the /src/component directory with the filename of ContactList.vue with the following contents. The lines specific to the usage of the NSwag generated client are highlighted.
<template>
<div>
<table class="table table-striped" aria-labelledby="tabelLabel">
<thead>
<tr>
<th>Name</th>
<th>Address</th>
<th>City</th>
<th>State</th>
<th>Postal Code</th>
<th>Phone</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<tr v-for="contact in contacts" v-bind:key="contact.id">
<td>{{contact.name}}</td>
<td>{{contact.address}}</td>
<td>{{contact.city}}</td>
<td>{{contact.state}}</td>
<td>{{contact.postalCode}}</td>
<td>{{contact.phone}}</td>
<td>{{contact.email}}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'
import { ContactsClient, Contact } from '../apis/contactsApi'
@Component
export default class HelloWorld extends Vue {
name: string = 'ContactList';
contacts: Contact[] = [];
private created () {
let client = new ContactsClient()
client.getContacts().then(data => (this.contacts = data))
}
}
</script>
<style scoped>
</style>
As you can see from the created function above we are creating a new instance of the ContactsClient and calling its getContacts function and using the data we get back from the API to replace the contacts field with the results of the API call.
Next, we are going to create a ContactList.vue under the /src/views directory with the following code. This is basically a wrapper around the component we created above.
<template>
<div>
<ContactListComponent/>
</div>
</template>
<script>
import ContactListComponent from '@/components/ContacList'
export default {
name: 'contactList',
components: {
ContactListComponent
}
}
</script>
Now that we have our view ready we need to add a link to the application’s navigation so a user can get to the contact list. Open App.vue and a router link to the nav div for the contact list.
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/contactList">Contacts</router-link> |
<router-link to="/about">About</router-link>
</div>
Now we need to add the new component to the routes for the application. Open index.ts in the /src/router directory and add an import for the contact list view.
import ContactList from '../views/ContactList.vue'
Finally, add the contact list to the routes array.
const routes = [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/contactList',
name: 'contactList',
component: ContactList
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
Wrapping Up
As always NSwag makes it very easy to create a client to interact with an API. Hopefully, this was useful even if my Vue code might not be idiomatic.