Create a Crypto Converter with Svelte and Strapi
Tags: strapi, svelte, tutorial
Published: 2021-11-17 11:19:01

Cryptocurrencies have been in use since 2009, when Bitcoin was officially launched. As a result of its acceptance over time, numerous other cryptocurrencies and tokens have been created and are in use.

Today, people have crypto portfolios where they hold different cryptocurrencies. There is often the need to know the value of one crypto against another. This need has given birth to cryptocurrency converters. Cryptocurrency converters are applications that convert the value of one crypto to another. 

In this tutorial, we will build a simple cryptocurrency converter. It will consume external crypto APIs that return real-time cryptocurrency rates. It will be able to convert the value of one coin to another. An example would be converting Bitcoin to Ethereum. If the value of Bitcoin (BTC) is entered, it will calculate and give the equivalent value in Ethereum (ETH). Strapi will be used to build out the application's backend, and Svelte will be used for the front end. With that said, let's get started.
 

## Goal

This tutorial has two sections.

**Goals of the First Section**

By the end of the first section, the reader should understand the following concepts: Strapi, Strapi collection types, Strapi routes, & Strapi controllers and methods, and be able to create the backend of our Cryptocurrency converter using JavaScript in our Strapi controller.

**Goals of The Second Section**

By the end of the second section, the reader should:

- understand Svelte, its pros and cons, 
- be able to scaffold a new Svelte project using NPM, 
- understand Svelte components 
- and create the front end of our Cryptocurrency converter using Svelte.


## Prerequisite

Readers should have a basic knowledge of HTML, CSS, JavaScript, Node.js, Yarn, and ReactJs or VueJs to follow along.


## What is Strapi?

Strapi is an open-source headless CMS built with React and Node. It gives the developers the flexibility of using the technology of their choice in the front end of the application. With a good understanding of Node.js and the React framework, Strapi can be used to build anything. Let's get started building the backend of the application with Strapi.

## Step 1 - Create a Strapi Project

To get started, let's create a new Strapi project using Yarn like so:

```bash
    yarn create strapi-app crypto-converter --quickstart
```

The command above scaffolds a new Strapi project in your preferred directory. The `--quickstart` command makes the process even more seamless by handling databases and others 

Note that [NPM can also be used](https://strapi.io/documentation/developer-docs/latest/getting-started/quick-start.html) in place of Yarn. Once the installation is complete, you will be redirected to the page below and prompted to create an admin account needed to access the Strapi admin panel. 

![Strapi admin panel](https://paper-attachments.dropbox.com/s_D4E1A74BBCE535958F016A60B872DD9239D73CD228FE2207E91F6E4A0DDD748E_1631878422414_1craete_admin.png)


After creating the account, you will be redirected to the dashboard like the one in the image below. You have now become the first admin to your Strapi project.


![Strapi admin dashboard](https://paper-attachments.dropbox.com/s_D4E1A74BBCE535958F016A60B872DD9239D73CD228FE2207E91F6E4A0DDD748E_1634812958345_strapiSvelte1.png)

![](/static/img/pixel.gif)


Now we have created our admin user account, let’s proceed to creating our API in the next step below. 

## Crypto Converter API 

## Step 2 - Create a collection.

Now, we have created our project and an admin account to access the dashboard. Let’s dive into the main business of the day which is creating our crypto convert app. In our Strapi application, we need a **Route** and a **Controller** to keep stuff organized. Let’s create a collection type from our dashboard. To create a collection type, follow the steps outlined below on the Strapi admin panel:


- From the side menu in the dashboard, click on **Content-Types Builder** 
- Click the **"+ Create new collection type"** link
- Name it crypto-converter and click **continue**
- Add a **Text field** (short text) and name it *Name*
- Click the **"Finish"** button
- Click the **Save** button

If you still need help with creating your collection type, check [Strapi documentation](https://strapi.io/documentation/developer-docs/latest/getting-started/quick-start.html).

Creating a collection type in Strapi goes ahead to modify the structure of the codebase of our Strapi project. In our case, this is what our **API** folder looks like



![Strapi API structure](https://paper-attachments.dropbox.com/s_D4E1A74BBCE535958F016A60B872DD9239D73CD228FE2207E91F6E4A0DDD748E_1634817961766_strapisvelte5.png)




## Step 3 - Create a route

The collection type we created in the API folder modified the files and folders into an [MVC](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) design pattern. Strapi was built this way. Collection types created from the admin dashboard generate new files and folder structures. Next, we need to create a new controller file and a route that will point to the controller where all of our logic and external API calls will be implemented.

**Create controller**

In Strapi, there are two ways of creating a controller. We can create a controller using the  `strapi generate` command as we have below:

```
    strapi generate:controller my-crypto-converter
```

or simply create a new JavaScript file in the controller folder (**API/crypto-converter/controller**). In our case, I chose the second option. I created a new JavaScript file in the project directory named **my-crypto-converter.js** **.**


![](https://paper-attachments.dropbox.com/s_D4E1A74BBCE535958F016A60B872DD9239D73CD228FE2207E91F6E4A0DDD748E_1634818086377_strapisvelte6.png)


In the newly created controller, let's add a new method like so.

```
    'use strict';
    /**
     * Read the documentation (https://strapi.io/documentation/developer-docs/latest/development/backend-customization.html#core-services)
     * to customize this service
     */
    module.exports = {
        convert: async ctx => {
            await ctx.send({
                message: "controller configured"
            })
        },
    };
```
    

Every Strapi controller must be an `async` and `await` JavaScript function like what we have above. The `ctx.send()` method is one of the many Strapi in-built methods. It is used to send responses in message form. 

Let us proceed by creating our route. Navigate to the **api/crypto-converter/config/routes.json** file. You will find already generated routes for our collection type. We will add one more router link pointing to our newly created controller like so: 


```
    {
          "method": "POST",
          "path": "/my-crypto-converter/convert",
          "handler": "my-crypto-converter.convert",
          "config": {
            "policies": []
          }
        } 
```

The `handler` points to the controller and the method. `my-crypto-converter` is the controller while `convert` is the method in the controller we need to trigger its action. `path` points to the router path. 


## Step 4 - Grant public access to the route

At this point, we have successfully created our route and controller. We need to grant public access to the route. This will make it accessible publicly. To grant access, navigate to **settings→users & permissions plugins→permissions→application** and grant public access to the `/my-crypto-converter/convert` route.
 
For more details on setting roles and permissions in Strapi, check the documentation [here](https://strapi.io/documentation/developer-docs/latest/getting-started/quick-start.html).
 
## Step 5 - Install Axios 

Now we are good to go. We need to make API calls to an external crypto API endpoint (for real time exchange rates). There are plenty of ways we can achieve this but for this tutorial, we will use [Axios](https://github.com/axios/axios). To install  `Axios` in our app use the following command:

```bash
    yarn add Axios
```


## Step 6 - Create a Nomics.com API key and fetch rates using Axios

After installing Axios, we should be ready to make external API calls using it. We need a way to get up-to-date exchange rates of cryptocurrencies. For this, we will consume the [nomics.com](https://nomics.com/) API. I choose it because of how easy it is to create an account and generate your API key. I have created my account and generated my API key. If you are coding along, you should do the same too. 
Check the [documentation](https://nomics.com/docs/#section/Introduction) for more details on creating your API key.

We will make an **HTTP Get request** to the endpoint below to get the exchange rate of any cryptocurrency against US dollars (USD).


    https://api.nomics.com/v1/currencies/ticker?key=YOUR_API_KEY&ids=BTC,ETH,XRP,

The result of the API call will enable us to calculate the rate of one crypto to another.

In `my-crypto-converter.js` modify the contents like so:

```
            'use strict';
        const axios = require('axios');
        /**
         * Read the documentation (https://strapi.io/documentation/developer-docs/latest/development/backend-customization.html#core-services)
         * to customize this service
         */
        module.exports = {
            convert: async ctx => {
                //post values
                const amount = ctx.request.body.amount;
                const baseCoin = ctx.request.body.baseCoin;
                const compareCoin = ctx.request.body.compareCoin;
    
                // fetch all rates in USD
                const baseCoinRate = await getRate(baseCoin);
                const compareCoinRate = await getRate(compareCoin);
                // get rate in crypto currency
                const exchange = await calculateExchange(baseCoinRate, compareCoinRate, amount);
                return exchange;
            },
        
        };
        //get exchange rate
        async function getRate(coin){
            //API key should be passed along as key in the URL below
            const { data } = await axios.get(`https://api.nomics.com/v1/currencies/ticker?key=169170*******************90&ids=${coin}`); 
            return data[0].price;
            
        }
        // calculate and return result
        async function calculateExchange (base, compare, amount){
            const rate =  await base/compare;
            const result = await rate * amount
            return result;
        }
    };
```

In the code above, we did the following:

- fetch coin values
- calculation and conversion 
- return result

I’ll explain every step in detail. In the `convert` method in our controller, we accepted a few arguments coming from the Svelte app. These are `amount`, `baseCoin`, `compareCoin`. 
`baseCoin` is the coin we have possession of and want to confirm its value against another. `compareCoin` is the currency we are comparing `baseCoin`  value against, `amount` is the total amount to convert.

We can convert crypto against another by dividing the value of the `baseCoin` by the value of  `compareCoin` and multiplying the result by the value of the `amount`. This was done in   `calculateExchange` function above.

**Fetch coin values**
We created two additional functions `getRate()` and `calculateExchange()`. `getRate()` fetches the rate of a particular coin using **Nomic API.** It accepts a parameter `coin`. This is the short code of the coin which is passed along with the API call. The function returns the current exchange rate of the coin in question.

```
    // fetch all rates in USD
    const baseCoinRate = await getRate(baseCoin);
    const compareCoinRate = await getRate(compareCoin);

`calculateExchange()` does the calculation and logic. It returns the final result. This function accepts three parameters `baseCoinRate`, `compareCoinRate`, `amount`.  This snippet below shows how we used it.


    // calculate and return result
        async function calculateExchange (base, compare, amount){
            const rate =  await base/compare;
            const result = await rate * amount
            return result;
        }
```

In `convert` , we called all the functions and return a response to our Svelte frontend. Let's proceed to create the Svelte app.

## What is Svelte?

Svelte is a modern-day JavaScript compiler for creating reactive web applications and interfaces. It can be used in parts of an already existing application or in a new single-page application (SPA).

Svelte is very similar to other frontend JavaScript frameworks like React and VueJS but it uses a different approach that avoids a virtual DOM. Svelte compiles your HTML, CSS, and JavaScript into a single build file that can be deployed. This makes it a lot faster and provides a better user experience.

**Why use Svelte?**

- Svelte is a compiler, not a framework. This simply means that Svelte is not shipped with dozens of framework script making it light weighted and easier to learn
- Compiles code into a single vanilla JavaScript file ready for deployment. Deployment of the compiled file only, not the entire Svelte technology results in a faster deployment process and better performance of our application in production.

**Cons**

- React, Vue, and the like are shipped with lots of features out of the box. This might not be the case with Svelte as you might have to do a lot of things yourself when using Svelte.

With that said, let’s proceed by creating the front end of our Cryptocurrency converter application using Svelte. The next step is to create a Svelte app.


## Step 7 - Create a Svelte project

To get started, let's create our svelte app using the command below:

```
    npx degit sveltejs/template crypto-converter-svelte
    cd crypto-converter-svelte
    npm install
    npm run dev
```


`npx degit sveltejs/template crypto-converter-svelte` scaffolds a Svelte in a directory named `crypto-converter-svelte`. `cd crypto-converter-svelte` navigates into the project directory of our newly created Svelte app. `npm install` installs all the dependencies in the `package.json` file of the svelte app needed for the app to function properly.

`npm run dev` starts the application in a local development environment making it available at `localhost:5000`. The application will automatically reload when we save any change. 


![](https://paper-attachments.dropbox.com/s_D4E1A74BBCE535958F016A60B872DD9239D73CD228FE2207E91F6E4A0DDD748E_1634816143697_strapisvelte2.png)


Let’s take a closer look at the folder structure of the Svelte application:


    moz-todo-svelte
    ├── README.md
    ├── package.json
    ├── package-lock.json
    ├── rollup.config.js
    ├── .gitignore
    ├── node_modules
    ├── public
    │   ├── favicon.png
    │   ├── index.html
    │   ├── global.css
    │   └── build
    │       ├── bundle.css
    │       ├── bundle.js
    │       └── bundle.js.map
    ├── scripts
    │   └── setupTypeScript.js
    └── src
        ├── App.svelte
        └── main.js

The `main.js` file is the main point of entry of the Svelte application. It imports the `App.svelte` component which is the main component of our Svelte application like you can see below.

```
    import App from './App.svelte';
    const app = new App({
        target: document.body,
        props: {
            name: 'Moses'
        }
    });
    export default App;
```

Svelte is a component-based framework. You can think of Svelte components as building blocks of the application. It has a `<script></script>` section for writing JavaScript, a mark up section for `HTML` and a `<style></style>` for writing `CSS`. The following is the content of our `App.svelte`.

```
    <script>
      export let name;
    </script>
    <main>
      <h1>Hello {name}!</h1>
      <p>
        Visit the <a href="https://svelte.dev/tutorial">Svelte tutorial</a> to learn
        how to build Svelte apps.
      </p>
    </main>
    <style>
      main {
        text-align: center;
        padding: 1em;
        max-width: 240px;
        margin: 0 auto;
      }
      h1 {
        color: #ff3e00;
        text-transform: uppercase;
        font-size: 4em;
        font-weight: 100;
      }
      @media (min-width: 640px) {
        main {
          max-width: none;
        }
      }
    </style>
```

Let's modify the content of `App.svelte` to build out our frontend. Replace the content of `App.svelte`  with the code below.

```
    <script>
      import Modal, { getModal } from "./Modal.svelte";
      let amount;
      let baseCoin;
      let convertCoin;
      let result;
      function handleSubmit(e) {
        conversion(amount, baseCoin, convertCoin);
      }
      async function conversion(amount, baseCoin, convertCoin) {
        const call = await fetch(
          "http://localhost:1337/my-crypto-converter/convert",
          {
            method: "POST",
            body: JSON.stringify({
              baseCoin: baseCoin,
              compareCoin: convertCoin,
              amount: amount,
            }),
            headers: {
              "Content-type": "application/json; charset=UTF-8",
            },
          }
        );
        result = await call.json();
        //opens modal
        getModal().open();
      }
    </script>
    <div class="container">
      <h1>Crypto converter</h1>
      <form id="surveyForm" class="mt-4" on:submit|preventDefault={handleSubmit}>
        <div class="form-group">
          <label for="baseCoin">Choose base currency:</label>
          <select name="baseCoin" bind:value={baseCoin}>
            <option value="BTC">Bitcoin</option>
            <option value="ETH">Ethereum</option>
            <option value="XRP">Ripple</option>
            <option value="audi">Audi</option>
          </select>
        </div>
        <div class="form-group">
          <label for="compareCoin">Choose currency to convert to:</label>
          <select name="compareCoin" bind:value={convertCoin}>
            <option value="BTC">Bitcoin</option>
            <option value="ETH">Ethereum</option>
            <option value="XRP">Ripple</option>
            <option value="audi">Audi</option>
          </select>
        </div>
        <div class="form-group">
          <input
            type="num"
            class="form-control"
            placeholder="Enter amount in coin"
            bind:value={amount}
            required
          />
        </div>
        <button class="btn btn-full">Convert</button>
      </form>
      <Modal>
        <h4>Success!!</h4>
        <h3>
          <small>You will get</small>
          {result} <small>in</small>
          {convertCoin}
        </h3>
      </Modal>
    </div>
    <!-- the modal without an `id` -->
    <style>
      .container {
        max-width: 1200px;
        margin: 0 auto;
        margin-top: 8rem;
      }
      h2 {
        margin-top: 0;
      }
      .form-group > *,
      .btn-full {
        width: 100%;
      }
      .form-control,
      .btn-full {
        border-radius: 3px;
      }
      .submitted input:invalid {
        border: 1px solid #c00;
      }
      .submitted input:focus:invalid {
        outline: 1px solid #c00;
      }
      .error-alert {
        border: 1px solid #c00 !important;
        padding: 6px;
        text-align: center;
        color: #c00;
        border-radius: 3px;
      }
    </style>
```

Let's go over the code above. In the main section, we added an `HTML` form to accept the values of the cryptocurrency we want to exchange and the amount. We used svelte `bind:value={}` to bind the form input to the variables used in the API call. 

In the JavaScript section, we declared `amount` , `baseCoin`, `convertCoin` variables and made our API call to our Strapi backend. 

**Adding a Modal to our Svelte Application**
Just to spice it up a little, we added a modal to display the response nicely. Check [S](https://svelte.dev/repl/514f1335749a4eae9d34ad74dc277f20?version=3.37.0)[velte documentation](https://svelte.dev/repl/514f1335749a4eae9d34ad74dc277f20?version=3.37.0) for more on creating this simple modal.

  `getModal().open()` function opens up the modal to display response from the API.  

The body of the modal is contained in the code below.

```
    <Modal>
        <h4>Success!!</h4>
        <h3>
          <small>You will get</small>
          {result} <small>in</small>
          {convertCoin}
        </h3>
      </Modal>
```

The modal component functionality is done in `./Modal.svelte` component. We imported it using this `import Modal, { getModal } from "./Modal.svelte";`

In the **SRC** directory, create a **Modal.svelte** file and add the following code to create a modal.

```
    <script context="module" lang="ts">
      let onTop; //keeping track of which open modal is on top
      const modals = {}; //all modals get registered here for easy future access
      //  returns an object for the modal specified by `id`, which contains the API functions (`open` and `close` )
      export function getModal(id = "") {
        return modals[id];
      }
    </script>
    <script lang="ts">
      import { onDestroy } from "svelte";
      let topDiv;
      let visible = false;
      let prevOnTop;
      let closeCallback;
      export let id = "";
      function keyPress(ev) {
        //only respond if the current modal is the top one
        if (ev.key == "Escape" && onTop == topDiv) close(); //ESC
      }
      /**  API **/
      function open(callback) {
        closeCallback = callback;
        if (visible) return;
        prevOnTop = onTop;
        onTop = topDiv;
        window.addEventListener("keydown", keyPress);
        //this prevents scrolling of the main window on larger screens
        document.body.style.overflow = "hidden";
        visible = true;
        //Move the modal in the DOM to be the last child of <BODY> so that it can be on top of everything
        document.body.appendChild(topDiv);
      }
      function close(retVal) {
        if (!visible) return;
        window.removeEventListener("keydown", keyPress);
        onTop = prevOnTop;
        if (onTop == null) document.body.style.overflow = "";
        visible = false;
        if (closeCallback) closeCallback(retVal);
      }
      //expose the API
      modals[id] = { open, close };
      onDestroy(() => {
        delete modals[id];
        window.removeEventListener("keydown", keyPress);
      });
    </script>
    <div id="topModal" class:visible bind:this={topDiv} on:click={() => close()}>
      <div id="modal" on:click|stopPropagation={() => {}}>
        <svg id="close" on:click={() => close()} viewBox="0 0 12 12">
          <circle cx="6" cy="6" r="6" />
          <line x1="3" y1="3" x2="9" y2="9" />
          <line x1="9" y1="3" x2="3" y2="9" />
        </svg>
        <div id="modal-content">
          <slot />
        </div>
      </div>
    </div>
    <style>
      #topModal {
        visibility: hidden;
        z-index: 9999;
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background: #4448;
        display: flex;
        align-items: center;
        justify-content: center;
      }
      #modal {
        position: relative;
        border-radius: 6px;
        background: white;
        border: 2px solid #000;
        filter: drop-shadow(5px 5px 5px #555);
        padding: 1em;
      }
      .visible {
        visibility: visible !important;
      }
      #close {
        position: absolute;
        top: -12px;
        right: -12px;
        width: 24px;
        height: 24px;
        cursor: pointer;
        fill: #f44;
        transition: transform 0.3s;
      }
      #close:hover {
        transform: scale(2);
      }
      #close line {
        stroke: #fff;
        stroke-width: 2;
      }
      #modal-content {
        max-width: calc(100vw - 20px);
        max-height: calc(100vh - 20px);
        overflow: auto;
      }
    </style>
```

At this point, if you've followed along effectively, you should have a working crypto converter using Svelte in the front end and Strapi at the backend.


![](https://paper-attachments.dropbox.com/s_D4E1A74BBCE535958F016A60B872DD9239D73CD228FE2207E91F6E4A0DDD748E_1634816411398_strapisvelte3.png)

## Conclusion

Great job, you’ve made it to the end of this tutorial. If you followed along correctly you should have a working app same as mine by now. 

By now, you should be able to create an API to convert from one crypto to another using Nomic API and Strapi. You should have a basic understanding of Svelte enough to get started working with it.  

Feel free to play around with what you have, modify it to suit your needs and don’t forget to share your experience with the rest of the community.
A good idea might be creating a cryptocurrency blog that has a crypto exchanger built in using Strapi. 
[Here is a link to the Svelte project on Github](https://github.com/alloyking1/svelteCryptoConverter)