Sharing my learnings....

Category: Programming Languages

Deploying Node JS Application with AWS App Runner

AWS App Runner is a fully managed service provided by Amazon Web Services (AWS). It makes it easy for developers to quickly deploy containerized web applications and APIs, at scale and with no prior infrastructure experience required. It automates management tasks such as provisioning, scaling, and security, enabling developers to focus on writing code rather than managing infrastructure.

How It’s Useful:

  1. Simplicity and Speed: It simplifies the deployment process by abstracting away the underlying infrastructure. Developers can deploy their applications quickly by providing the source code or a container image.
  2. Scalability: App Runner automatically scales the application up or down based on traffic, ensuring that the application can handle peaks in demand without manual intervention.
  3. Integrated with AWS ecosystem: It seamlessly integrates with other AWS services, providing a comprehensive and secure environment for deploying applications.
  4. Cost-Effective: Pay only for the resources used without having to manage underlying servers, potentially reducing the cost of running web applications and APIs.
  5. No infrastructure management: It eliminates the need to provision, configure, or manage servers, load balancers, and scaling mechanisms.

Comparison with Other Providers:

  • DigitalOcean App Platform: Like AWS App Runner, DigitalOcean’s App Platform is a platform-as-a-service (PaaS) offering that allows developers to build, deploy, and scale apps quickly. While App Runner focuses on the AWS ecosystem, DigitalOcean’s App Platform provides a simpler, more straightforward pricing model and is often appreciated for its user-friendly interface and lower entry cost.
  • Heroku: Heroku is another popular PaaS that simplifies the deployment process. It’s known for its ease of use and was one of the pioneers in platform as a service. Heroku supports multiple programming languages and has a strong add-on ecosystem. Compared to AWS App Runner, Heroku may offer more flexibility regarding language and framework support but might not provide the same level of integration with AWS services or the same scale of infrastructure.
  • Google Cloud Run: This is Google’s fully managed compute platform that automatically scales your stateless containers. Google Cloud Run is similar to AWS App Runner in that it abstracts away the infrastructure, allowing developers to focus on their applications. Cloud Run is deeply integrated with Google Cloud services and offers both a fully managed environment and an Anthos-based environment for more control.

Deploying Apps Using AWS App Runner:

  1. Preparation:
    • Have a Docker container image ready in a registry (Amazon ECR or any public registry) or source code hosted in a supported repository (e.g., GitHub).
    • Ensure your application listens for HTTP requests on the port defined by the PORT environment variable.
  2. Creating a Service:
    • Go to the AWS App Runner console and choose to create a new service.
    • Select the source of your application (repository or container registry) and configure the settings (e.g., deployment method, instance configuration, and environment variables).
    • Configure the service settings, including the automatic deployment of source changes if desired.
  3. Deployment:
    • After configuring the service, deploy your application. App Runner will build and deploy the application, handling all the infrastructure, including networking, security, and scaling.
  4. Monitoring and Management:
    • Once deployed, you can monitor the application’s health and performance directly from the AWS console.
    • App Runner provides automatic scaling, but you can adjust settings and configurations as needed.

Demo of Deploying a Node JS Application using App Runner

Go to the App Runner Service Page in AWS Console -> click “Create an App Runner Service”

We will be shown up with 2 types of deployment methods.

  1. Docker Images: Using Amazon ECR (Elastic Container Registry), can use both Private or Public Images
  2. Source Code Repository (For this we must need to select the provider among Github & Bitbucket)

In this article, I will go with Github, (Select Source code repository -> Provider ->> Github)

For the Github connection, if we are new then we need to add our Github connection to App Runner to access the repositories from our account.

After providing the Authorization to the “AWS Connector” app, in the window it will ask to name the connection -> The name can be anything to distinguish easily from the GitHub account we authorized.

And then, we need to install the AWS Connector app to authorize the repositories.

After configuring the authorization part, we can see the list of the repositories we allowed the AWS Connector to access.

Then, we will select the repository we need for deployment and the branch that we need to get deployed.

We can configure the Source Directory, where if we are given any folder path, then the build and start commands that we will provide in the next setup will be executed in this directory. By default, the source directory is the root directory.

In the Deployment settings option, we can either select Manual or Automatic deployment. Where Automatic deployment will provide the option to trigger and deploy the app whenever the specific branch gets updated.

In the Next screen we will be shown to configure the Build settings:

Currently, we can deploy

  • Coretto
  • .NET
  • Go
  • NodeJS
  • Python
  • Php
  • Ruby

applications.

So, let’s go with Node JS.

If we have any specific configuration and have customized it from the repository level,

then we can select the ‘Use a configuration file’ option, which will read the ‘apprunner. yaml‘ file for configuration and do the build settings.

I will go with setting up everything right here,

so for the build command:

npm install

Start command:

node index.js

On the next page, we will be shown up to configure the service settings:

According to our application needs, we can customize the CPU and Virtual memory allocation along with setting up the Environment Variables.

We can set up the IAM policy, and Autoscaling configurations on this page. For now, let’s keep everything with default values and set the service first.

The next page will show all the configurations for review and if we are good with it let’s click “Create & deploy”

On the next page, we will be redirected to the app runner service detailed page. Where we can see a message that the app is currently being deployed. We can also see the logs of the app as well.

The following image shows what the app runner properties will look like. We will get a default domain or we can customize it with our domain as well.

Now, whenever we make changes to the branch that we configured to deploy, the deployment will triggered. That’s the beauty of the App Runner.

AWS App Runner is particularly useful for developers looking to deploy applications quickly without the hassle of managing infrastructure. It stands out for its integration with the AWS ecosystem and its ability to scale applications automatically. When compared to other services like DigitalOcean’s App Platform, Heroku, and Google Cloud Run, the choice often comes down to the specific needs of the project, cost considerations, and preferred cloud ecosystem. Each platform has its strengths, and the best choice depends on the requirements of the application you’re deploying.

Send SMS in NodeJS using Nexmo

Hi, As I’m a JS enthusiast; I love doing JavaScript development due to its easiness & lot of people there to help.

Today, I have come up to show you how to implement, message sending facility using NodeJS using Nexmo service provider.

A lot of people are interested in start-ups & need to grow their business using SMS promotions.

Let’s move to the coding portion.

First of all, you have to create Nexmo account: Click Here

Now, create a new folder with a name you want

Create package.json using

npm init

Now,

We have to install express & body-parser to the application to use.

npm install express body-parser — save

Then, create an index.js file in the root folder

const express = require('express');
//importing express to useconst

bodyParser = require('body-parser');
//importing body parser to get the body input const

app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

require('./controller.js')(app);

//requiring app Which is an express instance to use in controller file

const server = app.listen(3000);
//configure the server to run on port 3000

console.log("Server working on 3000")

Now, create the controller.js file in the root folder.

module.exports = function (app) {
	const Nexmo = require('nexmo');
	const nexmo = new Nexmo({
	        apiKey: Your_API_KEY,
	        apiSecret: Your_API_SECRET_KEY
	});

	const config = {
		number: YOUR_REGISTERED_MOBILE_NUMBER
	}

	app.post('/send', (req, res) => {
	//Setting endpoint of /send
	// Send SMS
	     nexmo.message.sendSms(
	     config.number,
	     req.body.toNumber,
	     req.body.message, { type: 'unicode'},
     (err, responseData) => { if (responseData)
     {
	     console.log(responseData)
     }
	});
});
}

Here we are using the app instance which we declared in the index.js.

Then, we are importing the Nexmo module & create an instance of the Nexmo module;

for apiKey & apiSecret you have to give your Nexmo account details.

In the config object, you have to put the registered mobile number for your Nexmo account as a value for the number attribute.

And, after that, a POST request with a “/send” endpoint.

Wrapping the nexmo.message.sendSms() method which is predefined in the Nexmo to send message inside the POST request.

Finally, we are console the message details in the terminal/command line.

Now, Start the server using

node index.js

And test it with Postman.

If you get Non White-listed Destination — rejected error.

You have to register it in your Nexmo Account.

To do that Click Here

Yes, you have done it.

Happy Coding Folks..!!

Annotation & their uses in Java

Hello, I’m newbie to Java world & so new to Spring Boot. So, I don’t have a prior experience with spring also. As a new one, I’m writing this to new people to Java. Experts, correct me in the comments if its wrong.

What is Annotation..?

a note by way of explanation or comment added to a text or diagram.

Above, is the dictionary explanation for Annotation.

In Java

Annotation is a tag that used for

  1. methods
  2. class
  3. interface

which adds more information about those for Java compiler / JVM(Java Virtual Machine).

You may have already experienced with some built-in Java function when you done with basic Java stuffs.

Like,

  1. @override — used to override the parent class method in sub class method
  2. @SuppressWarnings — used to suppress warnings issued by the compiler.
  3. @Deprecated — compiler prints warning because of the method is deprecated as it could be removed in the future versions. So that its better not to use such method.

Let’s have a look at Java Custom Annotation

Java Custom Annotation or Java User defined annotations are easy to use and create (That means even you and me can create an annotation according to our need).

@interface element is used to declare an annotation.

Like this

@interface parathan{}

to create annotation; annotation should have the following characters

  • method should not have parameters
  • should not throw any clause
  • may have default values
  • should return a class, method, enum, String like primitive data type

Type of Annotation

  1. Marker Annotation
  2. Single Value Annotation
  3. Multi-value Annotation
  4. Marker Annotation — Annotation that have no methods inside it.

Eg: @Deprecated @Override

@interface parathan{}

  1. Single-value Annotation — Annotation that have one method

@interface parathan{

int value();

}

Default value can be provided for it by following code snippet

@interface parathan{

int value() default 0;

}

Applying a Single Annotation in code

@parathan(value=10)

3.Multi-value Annotation — Annotation that has more method than one

@interface parathan{

int age();

String name();

String country();

}

Applying Multi Annotation can be as follows

@parathan(age=20,name=”Parathan Thiyagalingam”,country=”Sri Lanka”)

Built in Annotations used in Custom Annotations

  1. @Target
  2. @Retention
  3. @Inherited
  4. @Documented

1. @Target —

used to betoken to which type the annotation to be used

For that we have to import java.lang.annotation.ElementType

we use

@Target(ElementType.some_thing)

Here some_thing need to be replaced by the following keywords if you are using where the annotation need to be applied.

If you are going to use it for “class,interface,enumeration”

then

@Target(ElementType.Type)

If you are going to use it for methods

then

@Target(ElementType.METHOD)

Credit: Javatpoint.com

Eg to use for class and method is follow

@Target({ElementType.Type,ElementType.METHOD})

@interface parathan{

int age();

String name();

}

2. @Retention

Used to betoken for what level the annotation need to be available.

There are 3 level

  • SOURCE — this refers the source code, which the annotation will not be available in compiled class.
  • CLASS — this refers to the .class file, which the annotation will not available to JVM but available for java compiler. So, it will be in the class file.
  • RUNTIME — refers runtime, which is available to bothe java compiler & jvm.

Eg:

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

@interface parathan{

int age();

String name();

}

The above snippet represents the annotation will be available at the run time & the annotation is targeted to the class.

3. @Inherited :

Normally the annotations are not inherited to sub classes to inherit the annotation to sub class @Inherited is used.

@Inherited

@interface parathan{ } //Now it will be available to subclass also

@interface parathan{ }

class MainClass{}

class Subclass extends MainClass{} //sub class extends the super class

As the annotation “parathan” is inherited;

the MainClass uses the annotation as the SubClass extends the MainClass,

therefore, the SubClass can also access the annotation

4.@Documented

It is used to include the annotation in the Java documentation.

The annotation I’m writing here, is because I’m posting REST API in Java using Spring Boot & MySQL as Parts.

So, there we are using a lot of annotations to make our tasks easy.

If I made any mistakes.. Please comment below. Or share with your friends.

Happy Coding Folks…!!

Split & Map a String in Java

Hi, everyone. I’m learning the basic concepts of Java since last month. So, while I’m learning I did some example by my own. In future post I’m planning to publish those code with you about what I learnt & how I did it.

Here, I want to show you how I split & mapped a string which in the following format.

key1=value1;key2=value2;key3=value3

This is my code

import java.util.*;

public class App {

    public static void main (String args[]) {

        Map<String, String> map = new HashMap<String, String>();
        String gotData = "key1=value1;key2=value2;key3=value3";

        if(gotData == **""**){
        	map = null;
	} else {

   		for(String keyValue : gotData.split(";")) {
        		String[] key = keyValue.split("=");
        		map.put(key[0], key[1]);
    		}
	}
        Map<String,String> finalOutput= map;

        System.**_out_**.println(finalOutput);

    }
}

Could you get it out…??

I’m explain it according to my knowledge…

I imported all java.util package modules to use “Map, Hash Map, put” keyword which are belong to the util package.

Then in the App class I declared a map of datatype Map.

For loop is used to loop until the string fully read by the program.

Inside that if else is used to avoid the “ArrayBoundExcaption” which is very common exception when using Map, Arrays in Java.

Splitting the string by “ ; ” and “ = ” and assigning the key to the o th index of Map & value to the 1st index of Map

This is what I got as the output

{key1=value1, key2=value2, key3=value3}

Screenshot of What I got as Output using Debugger mode

for o (zero(th Index

value1 assigned to key1

value2 assigned to key2

value3 assigned to key3

If you have another simple code Share it in the comment.

Thanks,

Django Views are Synchronous, You can’t have Asynchronous things inside views

python=django-learning

The core issue I was facing was related to the inherent nature of how web servers and Django handle requests and responses, especially in relation to performing time-consuming tasks like sending emails and Slack messages within a Django view.

Understanding the Problem:

  1. Synchronous Nature of Django Views:
    • Django views, by default, operate synchronously. This means that when a request hits a Django view, the server processes the request in a linear, blocking fashion. It executes each line of code in the view one by one, and the response to the client (frontend) is not sent back until the entire view function completes its execution.
  2. Frontend Loading Time:
    • When you include operations like sending emails or Slack messages directly in your Django view, these operations are executed as part of the request-processing pipeline. Since these tasks can be time-consuming (network I/O, waiting for external API responses), they block the completion of the view function. As a result, the response is delayed until these tasks are finished, leading to increased loading times on the frontend.
  3. Asynchronous Functions in Django:
    • Even if I make certain functions asynchronous within the Django view (using async def and await), it doesn’t change the fundamental synchronous nature of the view’s response cycle. The view still waits for all operations, including the asynchronous ones, to complete before sending back a response. This means that making functions asynchronous inside a view won’t reduce the frontend loading time if these tasks are part of the request-response cycle.
  4. Event-Driven Architecture Approach:
    • You mentioned an alternative approach using an event-driven architecture, where an event is published to a queue, and a separate consumer service handles the notifications. This method is indeed a way to offload time-consuming tasks from the request-response cycle. The view would quickly publish an event to the queue and then immediately respond to the frontend, significantly reducing loading times. However, this approach introduces complexity, such as setting up and managing a message queue and a consumer service, and it might incur additional costs.
  5. Other Solutions – Background Task Processing:
    • Another common solution in Django is to use a background task processing system like Celery. With Celery, you can quickly dispatch time-consuming tasks to be handled asynchronously outside of the request-response cycle. This allows your view to respond immediately, while the tasks like sending emails or Slack messages are processed in the background.

Conclusion:

  • In summary, simply converting functions within a Django view to asynchronous won’t solve the issue of frontend loading times when performing time-consuming tasks within the view. The response to the client is still delayed until these tasks complete.
  • To effectively reduce frontend loading times, you need to offload these time-consuming tasks from the request-response cycle. This can be achieved using an event-driven architecture with a message queue and a consumer service or by implementing a background task processing system like Celery.

Higher Order Component (HOC) in React

Higher Order Component (HOC) is a JavaScript function that takes a React component as input and returns a newly updated component. Using Higher Order Components in React is an advanced technique for reusing component logic.

HOC can be used for the following use cases:

  1. Code reuse, logic, and bootstrap abstraction
  2. Render high jacking
  3. State Abstraction & Manipulation
  4. Props Manipulation

HOC can be used in implementing authentication, error handling, logging, and performance tracking.

Let’s implement the React code and see how it works:

Create a new Counter component:

import {useState} from 'react';
import PropTypes from "prop-types";

function Component1() {  const [count, setCount} = useState(0)  return (
    <div>
      Component1 ${count}
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

PropTypes.propTypes = {
  count: PropTypes.number.isRequired,
  setCount: PropTypes.func.isRequired,
};

export default HOC(Component1);

If we need another Counter then we will create a new component called Component2 and create new state, where we can see the code duplication. Instead of implementing it like that, we will create a new Higher Order Component which will accept a React Node Component, and inside that HOC it will have the state and any other logics of it and return the newly modified component.

import { useState } from "react";

function HOC(Component) {
  function NewComponent() {
    const [count, setCount] = useState(0);
    return <Component count={count} setCount={setCount} />;
  }
  return NewComponent;
}

export default HOC;

So, the NewComponent function passes the state variable and the set state variable to the passed component.

Now, let’s modify Component1 to accept props and wrap Component1 with the HOC component which we wrote just before.

import PropTypes from "prop-types";
import HOC from "./HOC";

function Component1({ count, setCount }) {
  return (
    <div>
      Component1 ${count}
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

PropTypes.propTypes = {
  count: PropTypes.number.isRequired,
  setCount: PropTypes.func.isRequired,
};

export default HOC(Component1);

By wrapping up Component 1 with HOC, the HOC component takes this Component and alters it according to the implementation and returns back. Let’s create another component called Component2 and wrap it with the HOC component as we did for Component1. Now, let’s import both these components in the App.tsx file and see the result.