Sunday, November 29, 2020

Django

 Django:

What is Django ?

Web Framework
Creates pre-existing code
Can be used to create mulitple apps like - blogs , authentication etc .,
Uses MVT architecture

MVT architecture (Model View Template)

No Controller unlike MVC
Browser > Django > urls.py > View
View pulls data from model(DB) and Displays it on Template (HTML)

How to use:

  • No need to stop Django server when doing development
  • There will be only 1 settings file in the main project to handle auths , templates etc.,
  • When you want to create a new webpage do not modify the auto generated Framework.
  • Always create your own app with the command ($python manage.py startapp app_name)
 

Example Source Code

Pre-Req:
  •     make sure python is installed.
  • $pip install virtual env
  •     $virtualenv venv
  •     $source venv/bin/activate
  •     $pip install django
  •     If ur using Pycharm than goto : Preference>Select virtual Env created
Create django specific project , Create APP 
  •     django-admin startproject Main #Start django project
  •     $cd Main
  •     python manage.py startapp PersonApp #Create App
  •     python manage.py runserver
  •     open http://127.0.0.1:8000/
  •     comment - settings.py > MIDDLEWARE >
Register APP:
  •     settings.py > Installed APP ['PersonApp']
  •     settings.py > TEMPLATES > 'DIRS': [os.path.join(BASE_DIR, 'PersonApp','html')] #import os
  •     Under urls.py
from django.urls import path,include
path('', include('PersonApp.urls'))

Steps:

1)PersonApp >html>person.html
<form method="POST">
<p>{{ data }}</p>
<textarea name="fname">{{fname}}</textarea>
<textarea name="sname">{{sname}}</textarea>
<input type="submit">
</form>

2) #Under PersonApp/views.py
from django.shortcuts import render
def person(request):
if request.method == "GET":
return render(request, 'person.html', {"data":"enter ur name"})
elif request.method == "POST":
fname = request.POST.get('fname', None)
sname= request.POST.get('sname', None)
print("accepted :"+fname)
return render(request, 'person.html', {"data":"Accepted !"})


3)#Under PersonApp/urls.py
from django.urls import path
from . import views
urlpatterns= [path('',views.person,name='person')]

4) Create Model  - #PersonApp/models.py
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)

    #Under admin.py
from .models import Person
admin.site.register(Person)

5) Create a DB from Model
python manage.py makemigrations
python manage.py migrate

python manage.py createsuperuser
0.0.0.0/admin

6) Adding and Retrieving Data fro Db
from .models import Person
def person():
person=Person()
person.first_name=fname
person.last_name=sname
person.save()
print("records ="+str(len(Person.objects.all())))

Ref for HTML looping and API:

URL Dispatching

  • Copy a urls.py from base Framework into the new App folder
  • Notice line "path('admin/', admin.site.urls)" in Framework urls.py eg: path is /admin than redirect to admin page
  • Add below line in url.py in Base Framework
path('test', include('app_name.urls')) #make sure "include" is imported
  • This redirects "/test" to urls.py in the App folder.
  • Add below lines in urls.py in app_name :
from app_name import views
urlpatterns = [path('test', views.test,name="test")]

  • In views.py of app_name add below lines:
from django.shortcuts import render,HttpResponse
def test(request):
return HttpResponse("Testpage")

  • Notice here controls goes from  url.py(base) >> url.py >> views.py

StaticFolders:

  • The files inside static folders are made public
  • Can Contain CSS / JS to be used in the webpage
  • Create folder "static" inside project
  • create file "test.txt" with some contents inside and save
  • Add this to settings.py : STATICFILES_DIRS = [BASE_DIR / "static",'/var/www/static/',]
  • open link -http://127.0.0.1:8000/static/test.txt

Create Templates with paramaters

  • Create folder "templates" inside project
  • Create a home.html inside templates with following :
<html><body>My First Heading {{key1}}</body></html>
  • Goto settings.py > Under TEMPLATES > Add 'DIRS': [BASE_DIR / "templates",],
  • Goto to the app views.py > Add line to the related resource method - 
return render(request,"home.html",{"key1":"value"})
  • BootStraping
  • Used for ready made websites : https://getbootstrap.com/docs/4.5/getting-started/introduction/
  • Copy Starter Template html
  • You can use replace the html in home.html and save
  • reload page

Template Inheritance

  • Inherit the base template across the whole of the application
  • Create base.html in templates folder
  • Add templates html here , add placeholder for replacement wherever needed 
Eg:{% block body %}{% endblock body %} , {% block title %}{% endblock title %}
  • delete contents of home.html and add :
  •  In first line {% extends 'base.html' %}
  •  Add replacements for placeholder - {% block body %} HI {% endblock body %}
  •  Save

Using Images in Website:

Save any images into static folder
Rename the extension as ".jfif"
In the html file use as "/static/file.jfif"

Admin Logging Creation(We need to create Tables)

  • $python manage.py createsuperuser
  • Open http://127.0.0.1:8000/admin

To Create DB Table:

    Model is a Table
    Inside models.py
        Eg:class Person(models.Model):
                first_name = models.CharField(max_length=30)
                last_name = models.CharField(max_length=30)

    Register in admin.py  :
        from home.models import Person
        admin.site.register(Person)

    Register in Settings.py(under INSTALLED_APPS):
        'home.apps.Person'

    whenever u touch models.py , u need to run below commands
    $python manage.py makemigrations #notice any changes and store in a DB.
    $python manage.py migrate #Apply changes 

API

1. Create a model
2. migrate it to create a DB
3. Create a serializer  : Converts models to Json 
4. Create a view and use the serializer 
5. Create url.py and use the view

#https://www.youtube.com/watch?v=263xt_4mBNc
#https://www.youtube.com/watch?v=QB9gGEwxxM4

Pre-Req

    pip install djangorestframework
    pip freeze > requirements.txt
    python manage.py startapp api 
  •       settings.py > INSTALLED_APPS = 'rest_framework'
  •       url.py > urlpatterns=[path('api/', include('api.urls')),]

create  api/serializers.py : Converts models to Json 

from rest_framework import serializers
from .models import Person

class personSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Person
fields = ("url","first_name","last_name")

api/views.py

from rest_framework import viewsets
from .models import Person
from .serializers import personSerializer


#make sure Person model is created in models.py and migrated
class personView(viewsets.ModelViewSet):
queryset = Person.objects.all()
serializer_class = personSerializer

create  api/url.py : Handles all API endpoint

from django.urls import path , include
from . import views
from rest_framework import routers


router = routers.DefaultRouter()
router.register('person',views.personview)
urlpatterns = [path('', include(router.urls))]

Ref:

https://www.youtube.com/watch?v=JxzZxdht-XY&t=5368s

Python Virtual Environment (venv)

 Python Virtual Environment (venv)


Pre-Req :

  • This is on Mac
  • Make sure Python3 is installed in the system
  • $pip3 install virtualenv #--upgrade
  • $virtualenv #help

Steps:

  1. create folder
  2. cd inside folderName
  3. $virtualenv env_name  #-p /folder_path_of_python_to_clone/bin/python
  4. $source ./env_name/bin/activate
    1. #if u get permission denied "$chmod -R 777 *"
    2. #Note u can also have multiple environments and activate which ever u want
  5. Notice "env_name" in the Terminal line meaning it is activated.
  6. Try:
    1. $python
    2. import requests # you will get error
    3. exit()
  7. Try2 (make sure virtual env is still activated)
    1. $pip install requests
    2. $python
    3. import requests
    4. exit()
  8. $pip freeze > requirements.txt
  9. To install requirements from above file #pip install -r requirements.txt
  10. $deactivate #Deactivate the env

Note:

  1. To use Virtual Environment in Pycharm
  2. Preferences> Settings > Add > Virtualenv 
  3. Make sure it is pointing to venv

Sunday, November 22, 2020

Nginx and Gunicorn

Nginx and Gunicorn

NGINX
  1. Serving Static Content
  2. Reverse Proxy (forward requests from clients to backend servers)
  3. load balancing / distributing traffic across multiple servers.
  4. API Gateway (single entry point for all API requests)
  5. Caching ( caching frequently requested content)

Unicorn (Web Server Gateway Interface - WSGI)
Unicorn is designed to handle multiple concurrent requests 

Ingress is a Kubernetes-specific solution (similar to Nginx) 

Sequence of Operation :


  1. Nginx sits in front of Gunicorn/ unicorn.
  2. Gunicorn (uWSGI can be used as well) serves your flask app
  3. For example, if the incoming request is an http request Nginx redirects it to gunicorn, if it is for a static file, it serves it itself.


Example 

Pre-Req: 

  1. Docker is installed
  2. Create Test Folder with below files:
    1. Dockerfile
    2. requirments.txt
    3. flask.py

---Dockerfile------
FROM python:3
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["gunicorn", "--workers=1", "--bind=0.0.0.0:5000", "flask:app"]

------requirments.txt------
flask==1.1.1
gunicorn

------flask.py------
from flask import Flask, request
app = Flask(__name__)
@app.route('/')
def hello_world() -> str: return "Hello world"
if __name__ == '__main__':app.run(debug=True, host='0.0.0.0')

------------------------------------

Steps:
  1. $ cd to Test Folder
  2. $ docker run -it --rm -p 5000:5000 -v ${PWD}:/app python:3 bash # cd /app
  3. cd /apps
  4. pip install -r requirements.txt
  5. export FLASK_APP=flask.py
  6. gunicorn --bind=0.0.0.0:5000 --workers=1 flask:app

Ref
https://stackoverflow.com/questions/43044659/what-is-the-purpose-of-using-nginx-with-gunicorn
https://rahmonov.me/posts/run-a-django-app-with-gunicorn-in-ubuntu-16-04/

Saturday, November 21, 2020

Login API with Jmeter and Python Request:

 Login API with Jmeter and Python Request:

Scenario:

  • To record a login API transaction using Jmeter
  • Run the same using Jmeter and check the response
  • Reproduce the same using Jmeter

Pre-Req:

  • FireFox Browser
  • Jmeter
  • Python 3.7+
  • pip install requests

Settings:

Configure Port numbers

  1. Inorder for Jmeter to capture recording , we need to place Jmeter in-between Browser and external connections 
  2. such that all data passes through Jmeter before reaching the Browser and vis versa. 
  3. This is done by changing the port number of Browser to use port number of Jmeter. So that Jmeter can listen to the interactions

Browser -----------> JMETER -------------> External Connections

  • open Jmeter 
  • File > templates > Select Recording >Create
  • In the folder structure > copy the port name
  • Open firefox > Preferences> 
  • Scroll to bottom > Network Settings >Click on Settings
  • Select Manul proxy config 
  • Http proxy = localhost and port = Paste the port number
  • click on OK

Installing Certificates :

Since configuration such as above is quiet dangerous if it is done by any malicious / unauthorised application . We need to install certificates from Jmeter into the Browser .

  1. In Jmeter , click on Https test Script Recorder
  2. Click on Start button
  3. You will get a message box saying a root CA certificate is created under "Jmeter bin Directory"
  4. Open FireFox preferences > Privacy and Security
  5. View Certificates
  6. Click on import 
  7. Select the certificate file created under "Jmeter/bin" 
  8. Click on Ok
  9. Close Preferences
  10. stop the recording in Jmeter

Steps to record Capture in Jmeter:

  1. Start recording in Jmeter
  2. Open FireFox 
  3. open link https://login.shrm.org/
  4. Enter email -abc@gmail.com , password = 123
  5. click on Sign in
  6. Stop recording in Jmeter
  7. Under Jmeter open Thread Group> Recording Controller and Notice the recording
  8. under Jmeter open Https Test Script Recorder > View Results Tree and Check the response as well
  9. Toggle between Http , Raw Tabs and  Sample Result , Request and Response Tabs to understand the Request method and how data is send and received
  10. Close the browser
  11. Now you can run the same for different username and password by changing values in Recording Controller > Http Header manager 

Steps to Reproduce in Python

  1. Open Terminal
  2. $python3

import requests
url="https://www.login.shrm.org/"
headers={'Content-Type': 'application/json'}
data={'LoginCredentials.Username': 'deep@xx.com', 'LoginCredential.Password': '123'}
r= requests.post(url,headers=headers,data=data)
print(r.status_code)
print(r.content)


Friday, November 20, 2020

Spark Streaming

 Spark Streaming (Scala)

Steps :

1. Open Terminal
2. nc -l 54321 #any port number given in the program
3. Run below code
4. Type anything in terminal
5. Notice the Code Output

build.sbt 
name := "MachineLearning"
version := "0.1"
scalaVersion := "2.11.0"
val sparkVersion = "2.4.7"
libraryDependencies ++= Seq(
"org.apache.spark" %% "spark-core" % sparkVersion,
"org.apache.spark" %% "spark-mllib" % sparkVersion,
"org.apache.spark" %% "spark-sql" % sparkVersion,
"org.apache.spark" %% "spark-streaming-flume" % "2.4.7"
)
libraryDependencies += "mysql" % "mysql-connector-java" % "5.1.24"

StreamingNetworkWordCount.scala 
package SparkStreaming
import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}

object StreamingNetworkWordCount {
def main(args:Array[String]) {
val sparkConf = new SparkConf().setAppName("NetworkWordCount").setMaster("local[2]")
val ssc = new StreamingContext(sparkConf, Seconds(10))
val lines = ssc.socketTextStream("localhost",54321)
val words = lines.flatMap(_.split(" "))
val wordCounts = words.map(x => (x, 1)).reduceByKey(_ + _)
wordCounts.print()
ssc.start() // Start the computation
ssc.awaitTermination() // Wait for the computation to terminate
}
}

Monday, November 9, 2020

AirFlow

AIRFLOW


Pre-Req:

1. Make Sure python3 is installed
2. pip show any_package_name #to get path of installed packages
3. UpGrade Packages 

Method 1

   pip3 install pip-review
   pip-review --local --interactive

Method 2

   pip freeze > requirements.txt
   pip3 install -r requirements.txt --upgrade

4. default configuration path " ~/airflow/airflow.config"
min_file_process_interval = 60 # after how much seconds a new DAGs should be picked up from the filesystem
max_threads = 1 # This defines how many threads will run.
5. Default Dags path: #/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/airflow/example_dags

Install
  •    pip3 install apache-airflow    
  •    $airflow version
  •    $airflow initdb
  •    Open New Terminal Window
  •    $airflow webserver
  •    Open new Terminal Window
  •    $airflow scheduler 
  •    In browser  - localhost:8080
  •    By default all Dags are stored in example_dags (/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/airflow/example_dags)
  •    Automtically this file should appear in Web UI
  •    run the Task
   ViewResult : Click on last Run > click on any Tasks (Graph View) >click on Download Log

Notes:

DAG consists of Operators with unique Task id which is executed in sequence
DAG name has to be unique and this would appear in webconsole
Each DAG file has 1 DAG object , which is passed as argument to all Operators
DAG object has Name , arguments and schedule 
Schedule arguement in DAG object should be of past date to trigger immediately

Operator : Used to execute different command / function for Bash , Python etc .,
Once operators are created  , symbol ">>" is used to give the sequence of Execution
SubDAG : This is useful when you have repeating processes within a DAG or among other DAGs.
Xcom(“cross-communication”)
 a ) lets you pass messages between tasks.It consists of 
 b) pusher - The pusher sends a message
 c) puller -the puller receives the message.
Ref: https://airflow.apache.org/docs/stable/concepts.html 
https://big-data-demystified.ninja/2020/04/15/airflow-xcoms-example-airflow-demystified/

##################
Create new SampleScript.py
summary : Create a 1 DAG object and pass it as argument to operators
args  -> DAG object -> Operator
For a DAG to be executed, the start_date must be a time in the past, 
##################
import logging
from airflow.operators.bash_operator import BashOperator
from airflow.operators.dummy_operator import DummyOperator
from airflow.utils.dates import days_ago
from airflow.models import DAG
from airflow.operators.python_operator import PythonOperator
from airflow.operators.subdag_operator import SubDagOperator

logger = logging.getLogger("airflow.task")
dagname='deepak_example_all_operator'
args = {'owner': 'Airflow', 'start_date': days_ago(2)}
dag = DAG(dag_id=dagname,default_args=args, schedule_interval='@once',tags=['python'])
subdag_id="subdagid"
logging.info('This is an info message  - {}'.format(dagname))

def print_kwargs(**op_kwargs):
    print (op_kwargs.keys())
    return 'Whatever you return gets printed in the logs'

def print_args(*op_args):
    print(op_args)
    return 'Whatever you return gets printed in the logs'

def my_subdag(parent_dag_name, child_dag_name, args):
    dag_subdag = DAG( dag_id="{}.{}".format(parent_dag_name,child_dag_name), default_args=args,schedule_interval="@daily",)
    # DummyOperator(task_id=child_dag_name,default_args=args,dag=dag_subdag, )
    BashOperator(task_id=child_dag_name, bash_command='echo "hi deepak"', dag=dag_subdag)
    return dag_subdag

subdag=my_subdag(dagname, subdag_id, args)

dummy = DummyOperator(task_id='Dummy', dag=dag)
bash_pass = BashOperator(task_id='bash_pass', bash_command='echo 1', dag=dag)
bash_fail = BashOperator(task_id='bash_fail', bash_command='wrong command', dag=dag)
python_dictionary = PythonOperator(task_id='python_dictionary', python_callable=print_kwargs, op_kwargs={"1": "A"}, dag=dag)
python_list = PythonOperator(task_id='python_list', python_callable=print_args, op_args=['one', 'two', 'three'], dag=dag, )
# provide_context=True, #if True , use jinja Template

subdag_operator = SubDagOperator(task_id=subdag_id,subdag=subdag,dag=dag,)

dummy >> python_list >> python_dictionary >> bash_pass >> bash_fail >>subdag_operator

if __name__ == "__main__":
    dag.cli()
  ##################

#Error 1:ImportError: cannot import name 'resolve_types'
  •    pip3 install attr
  •    pip3 install cattrs

#Error 2:unknown locale: UTF-8
  •    Append this to your ~/.bash_profile:
  •    export LC_ALL=en_US.UTF-8
  •    export LANG=en_US.UTF-8
  •    source ~/.bash_profile

#Error 3: airflow-webserver.pid' is stale error
  • sudo lsof -i tcp:8080
  • kill -9 PID#all PIDs
  • rm -rf airflow-webserver.pid
  • https://stackoverflow.com/a/59086513

Tuesday, July 21, 2020

Scala : Generic Types in Scala


Generic Types in Scala

a) def func1[T](a : T) : T = a

Explanation :

def listOfDuplicates[A](x: A, length: Int): List[A] = {
  if (length < 1)
    Nil
  else
    x :: listOfDuplicates(x, length - 1)
}

println(listOfDuplicates[Int](3, 4))  // List(3, 3, 3, 3)----1
println(listOfDuplicates("La", 8))  // List(La, La, La, La, La, La, La, La)---2

we explicitly provide the type parameter by writing [Int]. Therefore the first argument must be an Int and the return type will be List[Int].
You don’t always need to explicitly provide the type parameter. The compiler can often infer it based on context or on the types of the value arguments. In this example, "La" is a String so the compiler knows A must be String.


b) 

class Stack[A] {

  private var elements: List[A] = Nil
  def push(x: A) { elements = x :: elements }
  def peek: A = elements.head
  }
}

Explanation:

This implementation of a Stack class takes any type A as a parameter. 
This means the underlying list, var elements: List[A] = Nil, can only store elements of type A. 
The procedure def push only accepts objects of type A (note: elements = x :: elements prepending x to the current elements).
Nil here is an empty List and is not to be confused with null.

example 1:

val stack = new Stack[Int]
stack.push(1)
stack.push(2)
println(stack.peek)  // prints 2

example 2:

class Fruit
class Apple extends Fruit
class Banana extends Fruit

val stack = new Stack[Fruit]
val apple = new Apple
val banana = new Banana

stack.push(apple)
stack.push(banana)

Sunday, July 12, 2020

Test Drive Development (TDD)


Test Drive Development  (TDD)


 

What is TDD :
Write Failing test First and later test should pass as the development progress


Properties of TDD
  1. Red-Green Refractor ie., Write Failing test First and later test should pass as the development progress
  2. Canary Test = Blank test to validate if the environment is working
  3. Description / Console output / Naming should read like a book
  4. Pending tests ie., Only declared but not implemented
  5. Error message from the Unit test should drive the development
  6. Source Code should be separate from the Unit Test (As it does not need to go to production. It can be in the same repo not the same file)
  7. The method under test initially should return below as the development progress : 
    1.   "NULL"
    2.   Change "NULL"  >  Constant
    3.   Constant > "Complex Expression depending on the requirement"
Eg :
assert (mtsToKm(mtrs) == NULL)
def dev (mtrs) : return NULL

assert (mtsToKm(1000) == 1)
def dev (mtrs) : return 1

assert (mtsToKm(1000) == 1)
def dev (mtrs) : mtrs/1000 

Rules of Simple Design:
  1. Pass the tests
  2. Reveal Intention
  3. No Duplication  
  4. Fewest number of elements
Pass the tests :
  1. Always Unit test should come first than we start the actual code.
  2. List all the test initially with only declaration ie.,(only describe and it()) these will be considered as pending tests or todo list.
  3. 1st test in canary test (No test , pass by default)
Reveal Intention.
  1. Meaningful variable and methods names which reveal intention in tests /Actual Code.
  2. Comments are unnecessary if you have meaningful names.
No Duplication
  1. Code should not be duplicated 
  2.  should be < 1  
  3. use functions /methods for repetitions. 
Transformation premises

Pre-Req : 
  • Make Sure all the tests are declared initially
  • And only Canary Test has test definition.

Cyele 1 :
  1. Write a Unit test which sends null / blank as input to the function under test.
  2. Modify the Actual code to handle null / blank
  3. Run the test it should pass.
Cyele 2:
  1. Write a test / Add definition to empty test declaration which sends a simple constant as input to Actual Code
  2. Modify the Actual code to handle that constant either by returning it directly / other means and make sure both the test passes 
  3. Run the test it should pass both the tests.
Cyele 3:
  1. Add definition to next empty test declaration to send little bit complex input.
  2. Modify the Actual code to handle that constant either by using if statements
  3. Run the test it should pass all 3 tests.
Cyele 4:
  1. Add definition to next empty test declaration to send even more  complex input to actual code 
  2. Modify the Actual code to handle that constant either by using better logic and so on.
  3. .....

Friday, July 10, 2020

Dataframe : agg

Spark Dataframe : agg()


To perform column related operations

  • ds.agg(...) = ds.groupBy().agg(...)
  • agg() is a DataFrame method that accepts those aggregate functions as arguments.
Example :

val df3: DataFrame =Seq(1.6,7,42).toDF("CURRENCY")
.withColumn("c2", lit(8.6).cast(DoubleType))
.withColumn("c3", lit(1).cast(DoubleType))
+--------+---+---+
|CURRENCY| c2| c3| +--------+---+---+ | 1.6|8.6|1.0| | 7.0|8.6|1.0| | 42.0|8.6|1.0| +--------+---+---+
df3.agg(max("CURRENCY")).show()
+-------------+ |max(CURRENCY)| +-------------+
| 42.0|
+-------------+
println(df3.agg(max("CURRENCY")).collect()(0))
[42.0]
println(df3.agg(sum("CURRENCY")).collect()(0))
[50.6]
df3.agg(sum("CURRENCY"),sum("c2")).show()
+-------------+------------------+
|sum(CURRENCY)| sum(c2)|
+-------------+------------------+
| 50.6|25.799999999999997|
+-------------+------------------+
In the above example In order write .sum this method has to exist. It is hardcoded on the API. Using .agg you can provide other aggregating functions, sum("column") is just one of them.


Same as :
df3.groupBy().max("CURRENCY")
[42.0]



Sunday, July 5, 2020

POSTMAN:Extraction and parameterization

POSTMAN : Extraction and parameterization

Extraction:
  • Click on + symbol and Create a new Environment
  • Once Environmanr is created , add a varaible example "token" in the environment and keep other fields blank
  • Create a request which gives a response
  • Click on test tab and add below lines of code (Javascript)
var jsonData = pm.response.json();
pm.environment.set("token", jsonData);
  • once you run the request postman should be able to capture the token. You can verify by clicking on the "eye" button . 
  • to use the token , you need to use  {{variable}} Eg : {{token}}


Parametrize url:
  1. Select the environment under use
  2. Add a new varaible say "url"
  3. Set current value as url which is paramaterize as shown in the above picture
  4. Now u can use {{url}}/resourcename inplace of full url (which turns orange)
  5. You can hover over orange variable name to verify if is displaying the correct Endpoint.