Python API development

In this article, we will talk about basic Python API development.

Python API development

Install python3. Download from its official website and install.

Create API by first installing following modules:

pip3 install fastapi
pip3 install uvicorn

Create a file named api.py and write the following code in it:

from fastapi import FastAPI
app = FastAPI()

@app.get("/my-first-api")
def hello():
	return ("Hello world !")

if __name__ == "__main__":
	uvicorn.run(app, port=8000, host="127.0.0.1")

Run the following command in terminal to start the API:

uvicorn api:app --reload

Access it from browser:

http://127.0.0.1:8000/my-first-api

CORS error

If you are having CORS error, you can make the following changes in your code:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
	CORSMiddleware,
	allow_origins=["*"]
)

Connect Python with Mongo DB

To connect your Python application with Mongo DB, first install pymongo in your server by running the following command:

> pip3 install pymongo

Then you need to import it in your file:

from pymongo import MongoClient

MONGO_CONNECTING_STRING = "mongodb://localhost:27017"
client = MongoClient(MONGO_CONNECTING_STRING)
db = client["your_database_name"]

To insert a document in collection, write the following line:

db["your_collection"].insert_one({
	"name": "Adnan"
})

Form data

Let’s say you have a Javascript code that sends an AJAX request to your Python server.

const formData = new FormData()
formData.append("website", "adnan-tech.com")

Then, in order to get it in your Python API, first you need to run the following command to install “python-multipart” module:

pip3 install python-multipart

Then include the “Form” and “Annotated” module.

from fastapi import FastAPI, Form
from typing_extensions import Annotated

Then in your post API method parameter, define each form data value and its type.

@app.post("/my-api")
async def my_api(website: Annotated[str, Form()]):

	print(url)

Installing Django framework

For Python API development you can also use Django framework. First, you need to install Django framework in your project’s root directory:

pip3 install django

Then you can verify it by checking the version:

python3 -m django --version

You can also verify the version from following command as well:

django-admin --version

Then we will create our django application:

django-admin startproject ecommerce-website

A new folder will be created named “ecommerce-website”. If you go inside this folder, you will find files named “manage.py” and other files along with a directory named same as “ecommerce-website”.

Now enter in the directory “ecommerce-website” and run the following command:

python3 manage.py startapp ecommerce

It will create a directory named “ecommerce”. Now run the following command to start the server:

python3 manage.py runserver

Now you can access your website by running the following URL in the browser:

http://127.0.0.1:8000/

You can access admin panel from:

http://127.0.0.1:8000/admin

It will ask for username and password. You can set it by first running the migration:

python3 manage.py migrate

Then you can create a super user.

python3 manage.py createsuperuser

Create app in Django

Run the following command at the root of your project:

python3 manage.py startapp pages

This will create a folder named “pages”.

Now open “ecommerce/settings.py” and add our app to the “INSTALLED_APPS” array.

INSTALLED_APPS = [
    ...
    "pages"
]

You can get your app name by opening the file “pages/apps.py”.

To create a view, open “pages/views.py” and add the following lines in it:

from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.

def index(request):
	return HttpResponse("<h1>Hello world</h1>")

To configure the URL, create a file named “urls.py” inside “pages” folder and write the following code in it:

from django.urls import path
from . import views

urlpatterns = [
	path("", views.index, name="index")
]

Now open your project’s root “ecommerce/urls.py” and add the following line in it:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path("", include("pages.urls")),
    path('admin/', admin.site.urls),
]

If you check your browser now at: http://127.0.0.1:8000/, you will see your message “Hello world” in it.

Creating models in Django

To create a model, open your app’s “models.py” file. In my case, it is “pages/models.py”. And write the following code in it:

class Page(models.Model):
	title = models.CharField(max_length = 255)
	content = models.TextField("Content", blank = True)

	def __str__(self):
		return self.title

It will create 2 fields (title and content). The “__str__” function is created to display the page title on admin panel where page listing is displayed.

Then you have to create its migration and migrate it. So run the following commands one-by-one:

python3 manage.py makemigrations pages
python3 manage.py migrate

Then in order to display it on admin panel, open your “pages/admin.py” file and add the following code in it:

from .models import Page

class PageAdmin(admin.ModelAdmin):
	list_display = ("title", "content",)
	ordering = ("title",)
	search_fields = ("title", "content",)

# Register your models here.
admin.site.register(Page, PageAdmin)

This will first import our Page model. Then it will create a class to handle it on admin panel. We will display 2 columns (title and content) on admin panel listing.

The ordering will be done by title field only.

And a search field will be displayed, from where user can search pages by their title or content.

At the end, we are registering both of these classes (Page and PageAdmin) to the admin panel.

Now if you go to your admin panel, you will see an option to manage pages.

Templating

First create a folder named “templates” in your “myEcommerce” folder.

Then goto your project’s “settings.py” file and first import the os module at the top of it.

import os

Then search for array “TEMPLATES”. Add your templates folder path in the DIRS array:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, "myEcommerce/templates")],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

Also, add the following array after the STATIC_URL variable:

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "myEcommerce/static")
]

In your templates folder, create a file named “base.html”.

Write the following code in your base.html file:

{% load static %}

<link rel="stylesheet" type="text/css" href="{% static 'main.css' %}" />

<h1>My template loaded</h1>

Then in your “myEcommerce/static” folder, create a filed named “main.css” and write the following code in it:

h1 {
	color: red;
}

And finally, change your “def index(request)” function inside “pages/views.py” to the following:

def index(request):
	return render(request, "base.html")

If you run the browser now, you will see your content from base.html file. And also it will load css from main.css file.

Template inheritance

You can create child template that extends from parent template. This will be helpful while creating header, footers or sidebars etc.

For that, add the following code in your “base.html” file:

{% block content %}

{% endblock content %}

You can set any name to your block. Now create a folder named “pages” inside “pages/templates” folder. This is necessary because Django will search for your files inside the “templates” folder.

Then create a file named “index.html” in your “pages/templates/pages” folder. Following will be the code of this file:

{% extends "base.html" %}

{% block content %}

<p>Hi</p>

{% endblock content %}

It first extends from base template. So the content of “base.html” will be display on top and “block content” will be displayed where it is mentioned in “base.html” file.

Finally, in your “pages/views.py” make the following changes:

# return render(request, "base.html")
return render(request, "pages/index.html")

If you refresh your page now, you will first see the content of base template. Then of your “pages/index.html” file.

Model to view (Overriding the view)

To fetch data from model and pass it to view, first goto “pages/urls.py” and comment out the previous path() function we created earlier in this post.

And add the following 2 paths, one for home page and one for other pages appending in the URL.

path("", views.index, {
	"pagename": 1
}, name="home"),
path("<str:pagename>", views.index, name="index")

This will pass variable named “pagename” to the view from the URL. So we need to catch that variable.

Open “pages/views.py” and change your index function to the following:

from django.shortcuts import render
from django.http import HttpResponse
from . models import Page

# Create your views here.

def index(request, pagename):
	page = Page.objects.get(id = pagename)
	context = {
		"title": page.title,
		"content": page.content
	}
	return render(request, "pages/index.html", context)

We have added “pagename” as an argument in the index function definition. Then we are getting the record from Page model using ID. And finally we are passing the page object from database to our view render function.

Then in our “pages/templates/pages/index.html”, we can display these values:

<h2>{{ title }}</h2>

<p>{{ content }}</p>

If your content contains HTML tags, then Django by default will escape them to prevent you from attacker’s attempts to inject executable code into your website.

You can render HTML tags by disabling the auto-escaping like this:

{% autoescape off %}

<p>{{ content }}</p>

{% endautoescape %}

If you run “http://127.0.0.1:8000” in your browser now, you will see the first page. Because its ID is 1.

But if you try “http://127.0.0.1:8000/2”, you will see second page. Because now it matches with ID.

Creating menus

To display all pages as menu hyperlinks, first we need to fetch all pages from database. So in your “pages/views.py”, change the context variable to the following:

context = {
	"title": page.title,
	"content": page.content,
	"pages": Page.objects.all()
}

Then in your “myEcommerce/templates/base.html” file, create a block where the child will render it:

{% block pages %}

{% endblock pages %}

And finally in your “pages/templates/pages/index.html”, you can render them as following:

{% block pages %}

<ul>
	{% for page in pages %}

		<li>
			<a href="{{ page.id }}">
				{{ page.title }}
			</a>
		</li>

	{% endfor %}
</ul>

{% endblock pages %}

If you refresh the browser now, you will see a list of all pages created from admin panel. On clicking any, will display the content of that page.

So these are all the basics for Python API development. You can move advance from here. But this is enough to get you started in API development using Python.

For frontend, you can use Vue JS. You can get our list of tutorials on Vue JS as well.

Record and save audio from web – Javascript, Node JS, PHP

In this article, we are going to teach you, how you can record and save audio from web using Javascript. For saving audio files, we will teach you how you can do that with PHP and Node JS.

Let’s get started

First, we will create a folder named “record-audio-from-web”. Inside this folder, create a file named “index.html” and include fontawesome CDN in it. We will be displaying a microphone icon to start recording.

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" />

Then we will create a microphone icon.

  1. Give it a unique ID so we can get it in Javascript.
  2. Attach an “onclick” listener that will be called whenever that icon is clicked.
  3. And set the cursor to pointer so user will know that this is clickable.
<i class="fa fa-microphone" id="icon-record-audio" onclick="recordAudio()" style="cursor: pointer;"></i>

Now in Javascript, we first have to create an instance of recorder.

let recorder = null

Get microphone permission

Then we will create that function that will be called when the microphone icon is clicked. This function will:

  1. Get the permission to access laptop’s microphone.
  2. Initialize a media recorder object.
  3. Start recording audio from microphone.
// function to record audio
async function recordAudio() {
    // get permission to access microphone
	navigator.permissions.query({name: 'microphone'})
		.then(function (permissionObj) {
			console.log(permissionObj.state)				
		})
		.catch(function (error) {
			console.log('Got error :', error);
		})

    // get recorder object
	recorder = await doRecordAudio()

    // start audio
	recorder.start()
}

Record audio

Then we will create “doRecordAudio” function that will handle all the recording and stoping mechanism.

function doRecordAudio() {
    return new Promise(function (resolve) {
        // get user audio media
        navigator.mediaDevices.getUserMedia({
            audio: true
        })
        .then(function (stream) {
            // [media recorder goes here]
        })
    })
}

After that, we need to create a media recorder object. Following code goes in the [media recorder goes here] section:

// create media recorder object
const mediaRecorder = new MediaRecorder(stream)

// save audio chunks in an array
const audioChunks = []
mediaRecorder.addEventListener("dataavailable", function (event) {
    audioChunks.push(event.data)
})

// [start and stop listener goes here]

This will create a media recorder object from stream and save all audio chunks (when available) in an array.

Then write the following code in [start and stop listener goes here] section to create start and stop listeners:

// create a start function
const start = function () {
    // [start listener goes here]
}

// create a stop function
const stop = function () {
    return new Promise(function (resolve) {
        // [stop listener goes here]
    })
}

// send the values back to promise
resolve({
    start,
    stop
})

This “start” function gets called from “recordAudio()” function.

Start recording audio

When the start function is called, we need to:

  1. Change the microphone icon to stop icon.
  2. Change onclick listener, so next time the icon is clicked, we will stop the recording.
  3. And play the audio.
  4. Tell the media to start recording.

Following code goes in the [start listener goes here] section:

// when recording starts, set the icon to stop
document.getElementById("icon-record-audio").className = "fa fa-stop-circle"

// on icon clicked
document.getElementById("icon-record-audio").onclick = async function() {
    // stop the recorder
    if (recorder != null) {
        const audio = await recorder.stop()

        // [play audio]

        // [get audio base64 string]
    }
}

// start media recorder
mediaRecorder.start()

If you test now, you will be able to record the audio. The microphone icon will be changed as well. But now you need to find a way to stop the recording.

Stop the recording

When you are done recording the audio, you can click the icon again to stop it. Following code goes in the [stop listener goes here] section. This will:

  1. Attach a listener that will be called when the recording is stopped.
  2. Change the icon back to microphone.
  3. Reset the onclick listener to its initial state.
  4. Convert the audio chunks array into a blob.
  5. Create URL object from blob.
  6. Create an audio object to play when required.
  7. And stop the media recorder.
// on recording stop listener
mediaRecorder.addEventListener("stop", function () {

    // change the icon back to microphone
    document.getElementById("icon-record-audio").className = "fa fa-microphone"

    // reset the onclick listener so when again clicked, it will record a new audio
    document.getElementById("icon-record-audio").onclick = async function() {
        recordAudio()
    }

    // convert the audio chunks array into blob
    const audioBlob = new Blob(audioChunks)

    // create URL object from URL
    const audioUrl = URL.createObjectURL(audioBlob)

    // create an audio object to play
    const audio = new Audio(audioUrl)
    const play = function () {
        audio.play()
    }

    // send the values back to the promise
    resolve({
        audioBlob,
        play
    })
})

// stop the media recorder
mediaRecorder.stop()

If you test now, you can record the audio and stop the audio. The icon will change from microphone to stop and then from stop to microphone.

Play the audio after recording

In order to play the audio you just recorded, write the following line in the [play audio] section:

audio.play()

“stop” function will return the promise containing the “new Audio” object and calling “play()” will play the audio.

Converting audio to base64

We are already sending audioBlob from “stop” function, so we can create base64 string from it. Write the following code in your [get audio base64 string] section:

// get audio stream
const reader = new FileReader()
reader.readAsDataURL(audio.audioBlob)
reader.onloadend = function() {
    // get base64
    let base64 = reader.result

    // get only base64 data
    base64 = base64.split(',')[1]

    // send base64 to server to save
    sendVoiceNote(base64)
}

This will create a base64 string fom audio.

Sending audio base64 to server

Now we will create a function that will call an AJAX to save this base64 string as audio.

function sendVoiceNote(base64) {
        // create an instance for AJAX
        var ajax = new XMLHttpRequest()

        // set request method as POST, set URL and set asynchronous to true
        ajax.open("POST", "http://localhost:8888/tutorials/record-audio-from-web/sendVoiceNote.php", true)

        // send base64 string to server
        const formData = new FormData()
        formData.append("base64", base64)
        ajax.send(formData)
}

Note: In your server, create a folder named “audios” where all audio files will be saved.

Saving audio file on server – PHP

First, we will teach you how can you save it using PHP. Create a file named “sendVoiceNote.php” and write the following code in it:

<?php

$base64 = $_POST["base64"];

$file_name = "audios/" . time() . ".webm";
file_put_contents($file_name, base64_decode($base64));

echo $file_name;

Try recording an audio again. When you stop the audio, you will see that a new file will be saved in your “audios” folder. You can listen to your audio in your favorite media player (VLC etc).

Saving audio file on server – Node JS

Now we will teach you, how you can save the file using Node JS. Create a Node JS project by running the following commands one-by-one:

> npm install express http express-formidable fs cors
> npm install -g nodemon
> nodemon server.js

Create a file named “server.js” and write the following code in it:

const express = require("express")
const app = express()

const expressFormidable = require("express-formidable")
app.use(expressFormidable())

const cors = require("cors")
app.use(cors())

const fileSystem = require("fs")
const http = require("http").createServer(app)

http.listen(3000, function () {
	app.post("/sendVoiceNote", async function (request, result) {
		const base64 = request.fields.base64

        const buffer = Buffer.from(base64, "base64")
        const voiceNote = "audios/" + new Date().getTime() + ".webm"
        await fileSystem.writeFileSync(voiceNote, buffer)

        result.send(voiceNote)
	})
})

In your client side, change the AJAX “open” function call from:

ajax.open("POST", "http://localhost/record-audio-from-web/sendVoiceNote.php", true)

To:

ajax.open("POST", "http://localhost:3000/sendVoiceNote", true)

So that’s it. That’s how you can record audio from web and save it in your server using Node JS or PHP. If you face any problem in following this, kindly do let me know.

Here is the complete code of all files:

index.html

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" />
<i class="fa fa-microphone" id="icon-record-audio" onclick="recordAudio()" style="cursor: pointer;"></i>

<script>

    let recorder = null

    function sendVoiceNote(base64) {
        // create an instance for AJAX
        var ajax = new XMLHttpRequest()

        // set request method as POST, set URL and set asynchronous to true
        // ajax.open("POST", "http://localhost:3000/sendVoiceNote", true)
        ajax.open("POST", "http://localhost/record-audio-from-web/sendVoiceNote.php", true)

        // whenever the status of request is changed
        // ajax.onreadystatechange = async function() {
        //     if (this.readyState == 4) {
        //         if (this.status == 200) {
        //             console.log(this.responseText)
        //         }

        //         if (this.status == 500) {
        //             console.log(this.responseText)
        //         }
        //     }
        // }

        // send base64 string to server
        const formData = new FormData()
        formData.append("base64", base64)
        ajax.send(formData)
    }

	function doRecordAudio() {
        return new Promise(function (resolve) {
            // get user audio media
            navigator.mediaDevices.getUserMedia({
                audio: true
            })
            .then(function (stream) {
                // create media recorder object
                const mediaRecorder = new MediaRecorder(stream)

                // save audio chunks in an array
                const audioChunks = []
                mediaRecorder.addEventListener("dataavailable", function (event) {
                    audioChunks.push(event.data)
                })

                // create a start function
                const start = function () {

                    // when recording starts, set the icon to stop
                    document.getElementById("icon-record-audio").className = "fa fa-stop-circle"

                    // on icon clicked
                    document.getElementById("icon-record-audio").onclick = async function() {
                        // stop the recorder
                        if (recorder != null) {
                            const audio = await recorder.stop()

                            // play the audio
                            audio.play()

                            // get audio stream
                            const reader = new FileReader()
                            reader.readAsDataURL(audio.audioBlob)
                            reader.onloadend = function() {
                                // get base64
                                let base64 = reader.result

                                // get only base64 data
                                base64 = base64.split(',')[1]

                                // send base64 to server to save
                                sendVoiceNote(base64)
                            }
                        }
                    }

                    // start media recorder
                    mediaRecorder.start()
                }

                // create a stop function
                const stop = function () {
                    return new Promise(function (resolve) {

                        // on recording stop listener
                        mediaRecorder.addEventListener("stop", function () {

                            // change the icon back to microphone
                            document.getElementById("icon-record-audio").className = "fa fa-microphone"

                            // reset the onclick listener so when again clicked, it will record a new audio
                            document.getElementById("icon-record-audio").onclick = async function() {
                                recordAudio()
                            }

                            // convert the audio chunks array into blob
                            const audioBlob = new Blob(audioChunks)

                            // create URL object from URL
                            const audioUrl = URL.createObjectURL(audioBlob)

                            // create an audio object to play
                            const audio = new Audio(audioUrl)
                            const play = function () {
                                audio.play()
                            }

                            // send the values back to the promise
                            resolve({
                                audioBlob,
                                play
                            })
                        })

                        // stop the media recorder
                        mediaRecorder.stop()
                    })
                }

                // send the values back to promise
                resolve({
                    start,
                    stop
                })
            })
        })
    }

    // function to record audio
	async function recordAudio() {
        // get permission to access microphone
		navigator.permissions.query({name: 'microphone'})
			.then(function (permissionObj) {
				console.log(permissionObj.state)				
			})
			.catch(function (error) {
				console.log('Got error :', error);
			})

        // get recorder object
		recorder = await doRecordAudio()

        // start audio
  		recorder.start()
	}
</script>

server.js

const express = require("express")
const app = express()

const expressFormidable = require("express-formidable")
app.use(expressFormidable())

const cors = require("cors")
app.use(cors())

const fileSystem = require("fs")
const http = require("http").createServer(app)

http.listen(3000, function () {
	app.post("/sendVoiceNote", async function (request, result) {
		const base64 = request.fields.base64

        const buffer = Buffer.from(base64, "base64")
        const voiceNote = "audios/" + new Date().getTime() + ".webm"
        await fileSystem.writeFileSync(voiceNote, buffer)

        result.send(voiceNote)
	})
})

sendVoiceNote.php

<?php

$base64 = $_POST["base64"];

$file_name = "audios/" . time() . ".webm";
file_put_contents($file_name, base64_decode($base64));

echo $file_name;

Gmail SMTP New Method 2023 – PHP

In this tutorial, I am going to show you, how you can use Gmail SMTP for sending emails in PHP.

Video tutorial – Gmail SMTP in PHP

I will be using PHPMailer library. You can find all the code for sending email from PHPMailer documentation.

<?php

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\SMTP;

require 'PHPMailer/src/Exception.php';
require 'PHPMailer/src/PHPMailer.php';
require 'PHPMailer/src/SMTP.php';

//Create an instance; passing `true` enables exceptions
$mail = new PHPMailer(true);

try {
    //Server settings
    $mail->SMTPDebug = SMTP::DEBUG_SERVER;                      //Enable verbose debug output
    $mail->isSMTP();                                            //Send using SMTP
    $mail->Host       = 'smtp.gmail.com';                     //Set the SMTP server to send through
    $mail->SMTPAuth   = true;                                   //Enable SMTP authentication
    $mail->Username   = 'your_email_address@gmail.com';                     //SMTP username
    $mail->Password   = 'app_password';                               //SMTP password
    $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;            //Enable implicit TLS encryption
    $mail->Port       = 465;                                    //TCP port to connect to; use 587 if you have set `SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS`

    //Recipients
    $mail->setFrom('your_email_address@gmail.com', 'Your name');
    $mail->addAddress('support@adnan-tech.com', 'Adnan Tech');

    //Content
    $mail->isHTML(true);                                  //Set email format to HTML
    $mail->Subject = 'Here is the subject';
    $mail->Body    = 'This is the HTML message body <b>in bold!</b>';
    $mail->AltBody = 'This is the body in plain text for non-HTML mail clients';

    $mail->send();
    echo 'Message has been sent';
} catch (Exception $e) {
    echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
}

Line #18: You need to set your host to smtp.gmail.com

Line #20: Write your email address

Line #21: Write the app password you will get from your google account in the next step.

First, you need to go to your google account.

Manage google account
Manage google account

Go to security.

Security
Security

Then go to 2-step verification.

2-step verification
2-step verification

After that, go to app passwords.

App passwords
App passwords

Set whatever name you want and generate.

This will generate an app password.

App password for Gmail SMTP - PHP
App password for Gmail SMTP – PHP

You can use this in your SMTP code. Line #21 of the above code.

Make sure there is no space in password. Then try again. You should receive an email now.

Learn how to do it in Node JS from here.

If you need any help in following this, kindly do let me know.

AJAX in Sweetalert 2

In this article, I am going to teach you, how you can use AJAX in sweetalert 2. As per sweetalert 2 documentation, you can use Fetch API for calling AJAX requests. Fetch API is good, but not for more control over your request, like using POST method, adding headers etc. Fetch API is not so suitable in those cases.

Video tutorial:

AJAX in Sweetalert 2

Following is your code that you get from sweetalert 2 documentation:

Swal.fire({
  title: 'Submit your Github username',
  input: 'text',
  inputAttributes: {
    autocapitalize: 'off'
  },
  showCancelButton: true,
  confirmButtonText: 'Look up',
  showLoaderOnConfirm: true,
  preConfirm: (login) => {
    return fetch(`//api.github.com/users/${login}`)
      .then(response => {
        if (!response.ok) {
          throw new Error(response.statusText)
        }
        return response.json()
      })
      .catch(error => {
        Swal.showValidationMessage(
          `Request failed: ${error}`
        )
      })
  },
  allowOutsideClick: () => !Swal.isLoading()
}).then((result) => {
  if (result.isConfirmed) {
    Swal.fire({
      title: `${result.value.login}'s avatar`,
      imageUrl: result.value.avatar_url
    })
  }
})

Replace that with the following function:

swal.fire({
	title: 'Submit your Github username',
	input: 'text',
	inputAttributes: {
		autocapitalize: 'off'
	},
	showCancelButton: true,
	confirmButtonText: 'Look up',
	showLoaderOnConfirm: true,
	preConfirm: (login) => {

		return new Promise(function (callback) {
			const ajax = new XMLHttpRequest()
			ajax.open("GET", "https://api.github.com/users/" + login, true)

				ajax.onreadystatechange = function () {
					if (this.readyState == 4 && this.status == 200) {
						callback( JSON.parse(this.responseText) )
					}
				}

			ajax.send()
		})
		
	},
	allowOutsideClick: () => !swal.isLoading()
}).then((result) => {
	if (result.isConfirmed) {
		swal.fire({
			title: `${result.value.login}'s avatar`,
			imageUrl: result.value.avatar_url
		})
	}
})

You can notice that the fetch() function has been replaced with a Promise. But now you can use XMLHttpRequest and have more control over your AJAX requests.

Learn more about promises from here.

Display ellipsis on long text HTML and CSS

In this article, I am going to show you how you can show an ellipsis on a long text using HTML and CSS. We will be using just 4 CSS properties.

Video tutorial:

For example, you have a paragraph like this:

<p>A quick brown fox jumps over the lazy dog.</p>

Then give it a width and you will start seeing it in wrap.

<p style="width: 200px;">A quick brown fox jumps over the lazy dog.</p>

To disable the wrap, you can give the following property:

<p style="width: 200px;
	white-space: nowrap;">A quick brown fox jumps over the lazy dog.</p>

Last thing you need to do, is to show ellipsis. To do that, just give the following 2 properties.

<p style="width: 200px;
	white-space: nowrap;
	text-overflow: ellipsis;
	overflow: hidden;
	display: block;">A quick brown fox jumps over the lazy dog.</p>

So that’s it. That’s how you can show an ellipsis on a long text using just HTML and CSS. If you face any problem in following this, kindly do let me know.