<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Khushi Singla</title>
    <description>The latest articles on DEV Community by Khushi Singla (@khushi_singla).</description>
    <link>https://dev.to/khushi_singla</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3216838%2Fe7bf54c0-e1a6-41f4-8ed6-1edf14cba04b.png</url>
      <title>DEV Community: Khushi Singla</title>
      <link>https://dev.to/khushi_singla</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/khushi_singla"/>
    <language>en</language>
    <item>
      <title>Building a Safe AI Database Assistant with Azure OpenAI, LangChain &amp; Function Calling</title>
      <dc:creator>Khushi Singla</dc:creator>
      <pubDate>Fri, 19 Dec 2025 06:50:06 +0000</pubDate>
      <link>https://dev.to/khushi_singla/building-a-safe-ai-database-assistant-with-azure-openai-langchain-function-calling-2fag</link>
      <guid>https://dev.to/khushi_singla/building-a-safe-ai-database-assistant-with-azure-openai-langchain-function-calling-2fag</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;From raw CSVs to a production-ready AI assistant that queries data safely — without hallucinating SQL.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this post, I’ll walk through how I built an AI-powered data analyst using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Azure OpenAI&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LangChain&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LangGraph&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Function Calling&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQLite&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The assistant can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Analyze CSV data using pandas&lt;/li&gt;
&lt;li&gt;Query a SQL database safely&lt;/li&gt;
&lt;li&gt;Choose predefined backend functions automatically&lt;/li&gt;
&lt;li&gt;Explain results clearly&lt;/li&gt;
&lt;li&gt;Avoid hallucinations and unsafe SQL&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧩 Problem Statement
&lt;/h2&gt;

&lt;p&gt;When working with AI models and databases, common problems include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ Hallucinated SQL queries&lt;/li&gt;
&lt;li&gt;❌ Unsafe eval or raw SQL execution&lt;/li&gt;
&lt;li&gt;❌ No control over what the model can access&lt;/li&gt;
&lt;li&gt;❌ No explanation of how results were computed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt;&lt;br&gt;
Build an AI assistant that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Answers analytical questions about COVID data&lt;/li&gt;
&lt;li&gt;Uses only allowed tools&lt;/li&gt;
&lt;li&gt;Never guesses&lt;/li&gt;
&lt;li&gt;Explains every answer&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  📊 Dataset
&lt;/h2&gt;

&lt;p&gt;We use the &lt;strong&gt;COVID all-states history dataset&lt;/strong&gt;, which includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;state&lt;/li&gt;
&lt;li&gt;date&lt;/li&gt;
&lt;li&gt;hospitalizedIncrease&lt;/li&gt;
&lt;li&gt;positiveIncrease&lt;/li&gt;
&lt;li&gt;…and more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The dataset is first used as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;pandas DataFrame&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;SQLite database&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  🧱 Architecture Overview
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Question
     ↓
Azure OpenAI (Assistant / LangChain)
     ↓
Tool Selection (Function / SQL / DataFrame)
     ↓
Safe Backend Execution
     ↓
Result
     ↓
Final Explanation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Key idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The model decides WHAT to do.&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Your backend decides HOW it is done.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  🔹 Part 1: Talking to Azure OpenAI via LangChain
&lt;/h2&gt;

&lt;p&gt;We start by connecting to Azure OpenAI using &lt;code&gt;AzureChatOpenAI&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;llm = AzureChatOpenAI(
    azure_endpoint="https://&amp;lt;your-endpoint&amp;gt;.cognitiveservices.azure.com/",
    api_key="YOUR_API_KEY",
    api_version="2024-12-01-preview",
    model="gpt-4o-mini"
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple sanity check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;response = llm.invoke([
    HumanMessage(content="Hello, Azure OpenAI via LangChain!")
])
print(response.content)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔹 Part 2: DataFrame Agent (CSV Analysis)
&lt;/h2&gt;

&lt;p&gt;We load the CSV into pandas and expose &lt;strong&gt;controlled computation&lt;/strong&gt; via a tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  DataFrame Tool
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@tool
def run_df(query: str) -&amp;gt; str:
    """Run Python code on the global dataframe `df` and return the result."""
    return str(eval(query))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ Note: In production, replace eval with a restricted execution layer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Enforcing Tool Usage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;llm_with_tools = llm.bind_tools([run_df])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The prompt &lt;strong&gt;forces the model&lt;/strong&gt; to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the tool&lt;/li&gt;
&lt;li&gt;Perform actual pandas calculations&lt;/li&gt;
&lt;li&gt;Explain results&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔹 Part 3: Moving from CSV → SQL (SQLite)
&lt;/h2&gt;

&lt;p&gt;We convert the CSV into SQLite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;engine = create_engine("sqlite:///./db/test.db")

df.to_sql(
    name="all_states_history",
    con=engine,
    if_exists="replace",
    index=False
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the same dataset can be queried via SQL.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔹 Part 4: SQL Agent with LangGraph
&lt;/h2&gt;

&lt;p&gt;Using LangGraph’s ReAct agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;agent_executor_SQL = create_react_agent(
    model=llm,
    tools=toolkit.get_tools()
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The system prompt enforces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only valid tables&lt;/li&gt;
&lt;li&gt;Only specific columns&lt;/li&gt;
&lt;li&gt;No hallucinated values&lt;/li&gt;
&lt;li&gt;Markdown-only output&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔹 Part 5: Function Calling (No Raw SQL)
&lt;/h2&gt;

&lt;p&gt;Instead of letting the model generate SQL, we define &lt;strong&gt;pre-approved backend functions&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Functions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def get_hospitalized_increase_for_state_on_date(state_abbr, specific_date):
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def get_positive_cases_for_state_on_date(state_abbr, specific_date):
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Function Registry (Critical!)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FUNCTION_MAP = {
    "get_hospitalized_increase_for_state_on_date": get_hospitalized_increase_for_state_on_date,
    "get_positive_cases_for_state_on_date": get_positive_cases_for_state_on_date,
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Only allowed functions run&lt;/li&gt;
&lt;li&gt;❌ No arbitrary code execution&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔹 Part 6: Azure OpenAI Function Calling (No Assistant API)
&lt;/h2&gt;

&lt;p&gt;Using &lt;strong&gt;Chat Completions + functions&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=messages,
    functions=functions,
    function_call="auto"
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the model calls a function:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Extract arguments &lt;/li&gt;
&lt;li&gt;Route via &lt;code&gt;FUNCTION_MAP&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Execute backend logic &lt;/li&gt;
&lt;li&gt;Send result back&lt;/li&gt;
&lt;li&gt;Get final grounded answer&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🔹 Part 7: Assistant API (Persistent Context)
&lt;/h2&gt;

&lt;p&gt;Now we level up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Assistant
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;assistant = client.beta.assistants.create(
    name="Covid Data Assistant",
    model="gpt-4o-mini",
    tools=[{"type": "function", "function": fn} for fn in functions]
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Assistant Loop (Key Concept)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;while True:
    run_status = client.beta.threads.runs.retrieve(...)

    if run_status.status == "requires_action":
        # extract function name
        # dispatch via FUNCTION_MAP
        # submit tool output

    elif run_status.status == "completed":
        break
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The assistant &lt;strong&gt;remembers conversation context&lt;/strong&gt;,&lt;br&gt;
but &lt;strong&gt;never caches database results&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🧠 Key Takeaways
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ What This Design Solves
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Prevents SQL hallucinations&lt;/li&gt;
&lt;li&gt;Enforces backend safety&lt;/li&gt;
&lt;li&gt;Keeps AI answers grounded in data&lt;/li&gt;
&lt;li&gt;Scales cleanly as tools grow&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🧩 Mental Model
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LLM&lt;/td&gt;
&lt;td&gt;Reasoning &amp;amp; intent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Assistant&lt;/td&gt;
&lt;td&gt;Tool selection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;Data access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Function Map&lt;/td&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  🎯 When to Use What?
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Best Choice&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;One-shot queries&lt;/td&gt;
&lt;td&gt;Chat + function calling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-turn analysis&lt;/td&gt;
&lt;td&gt;Assistant API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CSV exploration&lt;/td&gt;
&lt;td&gt;DataFrame tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production DB&lt;/td&gt;
&lt;td&gt;Predefined SQL functions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🚀 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This approach mirrors how &lt;strong&gt;real production AI systems&lt;/strong&gt; are built:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI decides &lt;strong&gt;what&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Backend controls &lt;strong&gt;how&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Data remains authoritative&lt;/li&gt;
&lt;li&gt;Explanations remain transparent&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Connect With Me
&lt;/h2&gt;

&lt;p&gt;Let’s learn and build cool data science and AI projects together!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💼 LinkedIn: &lt;a href="https://www.linkedin.com/in/singla-khushi/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/singla-khushi/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔗 GitHub: &lt;a href="https://github.com/KhushiSingla-tech" rel="noopener noreferrer"&gt;https://github.com/KhushiSingla-tech&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📩 Comments below are always welcome!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>azure</category>
      <category>openai</category>
      <category>datascience</category>
      <category>ai</category>
    </item>
    <item>
      <title>Predicting Football Player Market Value with a Simple ML Pipeline (Pandas + Scikit-Learn)</title>
      <dc:creator>Khushi Singla</dc:creator>
      <pubDate>Mon, 10 Nov 2025 09:15:40 +0000</pubDate>
      <link>https://dev.to/khushi_singla/predicting-football-player-market-value-with-a-simple-ml-pipeline-pandas-scikit-learn-5adh</link>
      <guid>https://dev.to/khushi_singla/predicting-football-player-market-value-with-a-simple-ml-pipeline-pandas-scikit-learn-5adh</guid>
      <description>&lt;p&gt;In this project, I explore how to predict football player market value using a clean and simple ML pipeline based on Python, Pandas, Seaborn, and Scikit-Learn.&lt;/p&gt;

&lt;p&gt;📌 Full code and notebook available on GitHub:&lt;br&gt;
👉 &lt;a href="https://github.com/KhushiSingla-tech/Football-player-price-pridiction" rel="noopener noreferrer"&gt;https://github.com/KhushiSingla-tech/Football-player-price-pridiction&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Dataset &amp;amp; Setup
&lt;/h2&gt;

&lt;p&gt;We start by loading a local &lt;code&gt;data.csv&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import numpy as np 
import matplotlib.pyplot as plt 
import pandas as pd
import seaborn as sns

dataset = pd.read_csv('data.csv')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First look:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dataset.head()
dataset.columns
dataset.describe()
dataset.shape
dataset.dtypes
dataset['nationality'].value_counts()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;: keep an eye on data types and missing values. position_cat should already be numeric in this workflow—if it weren’t, we’d need to encode it first.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick EDA
&lt;/h2&gt;

&lt;p&gt;Below are the core visuals I generated. I’m including placeholders so you can drop screenshots from your notebook. Keep the titles the same to stay consistent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Name vs Age&lt;/strong&gt; (top 50)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plt.figure(figsize=(10,6))
graph = sns.barplot(x='name', y='age', data=dataset[:50], palette="rocket")
graph.set(xlabel="Name", ylabel="Age", title="Name VS Age")
graph.set_xticklabels(graph.get_xticklabels(), rotation=90)
sns.set_context('talk'); sns.despine(); plt.show()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwipxhf5dok9oo8ue4qnf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwipxhf5dok9oo8ue4qnf.png" alt="Name vs Age" width="800" height="619"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Members per Club&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plt.figure(figsize=(10,6))
graph = sns.countplot(x='club', data=dataset, palette="vlag")
graph.set(xlabel="Club", ylabel="Member", title="Members per club")
graph.set_xticklabels(graph.get_xticklabels(), rotation=90)
sns.set_context('talk'); sns.despine(); plt.show()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fey3ctrnxtlikt0qne0q9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fey3ctrnxtlikt0qne0q9.png" alt="Members per Club" width="800" height="697"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Name vs Market Value&lt;/strong&gt; (top 50)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plt.figure(figsize=(16,6))
graph = sns.barplot(x='name', y='market_value', data=dataset[:50], palette="colorblind")
graph.set(xlabel="Name", ylabel="Market Value", title="Name VS Market Value")
graph.set_xticklabels(graph.get_xticklabels(), rotation=90)
sns.set_context('notebook'); sns.despine(); plt.show()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ruod5rmk5ocmvngdw52.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ruod5rmk5ocmvngdw52.png" alt="Name vs Market Value" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Name vs Position Category&lt;/strong&gt; (top 50)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plt.figure(figsize=(16,6))
graph = sns.pointplot(x='name', y='position_cat', data=dataset[:50], palette="deep")
graph.set(xlabel="Name", ylabel="Position category", title="Name VS Position Category")
graph.set_xticklabels(graph.get_xticklabels(), rotation=90)
sns.set_context('talk'); sns.despine(); plt.show()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fitqx8ww1fffs72xm0db0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fitqx8ww1fffs72xm0db0.png" alt="Name vs Position" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Name vs Region&lt;/strong&gt; (top 50)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plt.figure(figsize=(16,6))
graph = sns.pointplot(x='name', y='region', data=dataset[:50], palette="rocket")
graph.set(xlabel="Name", ylabel="Region", title="Name VS Region")
graph.set_xticklabels(graph.get_xticklabels(), rotation=90)
sns.set_context('poster'); sns.despine(); plt.show()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7dhpcxc3upxjxad5u61h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7dhpcxc3upxjxad5u61h.png" alt="Name vs Region" width="800" height="491"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Players by Nationality&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plt.figure(figsize=(20,6))
graph = sns.countplot(x='nationality', data=dataset, palette="muted")
graph.set(xlabel="Nationality", ylabel="Players", title="No. of players amoung different nationality")
graph.set_xticklabels(graph.get_xticklabels(), rotation=90)
sns.set_context('paper'); sns.despine(); plt.show()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc2jzeronks2y1wtny6ao.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc2jzeronks2y1wtny6ao.png" alt="Players by Nationality" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Players by Region&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph = sns.countplot(x='region', data=dataset, palette="vlag")
graph.set(xlabel="Region", ylabel="Players", title="No. of players amoung various regions")
sns.set_context('paper'); sns.despine(); plt.show()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0kflylbbenlx181k4re.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0kflylbbenlx181k4re.png" alt="Players by Region" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Name vs FPL Points&lt;/strong&gt; (top 50)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plt.figure(figsize=(16,6))
graph = sns.barplot(x='name', y='fpl_points', data=dataset[:50], palette="pastel")
graph.set(xlabel="Name", ylabel="FPL Points", title="Name VS FPL points")
graph.set_xticklabels(graph.get_xticklabels(), rotation=90)
sns.set_context('poster'); sns.despine(); plt.show()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fteqovi2ua1wp19vp3jqi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fteqovi2ua1wp19vp3jqi.png" alt="Name vs FPL Points" width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. Name vs FPL Value&lt;/strong&gt; (top 50)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plt.figure(figsize=(16,6))
graph = sns.pointplot(x='name', y='fpl_value', data=dataset[:50], palette="dark")
graph.set(xlabel="Name", ylabel="FPL Value", title="Name VS FPL value")
graph.set_xticklabels(graph.get_xticklabels(), rotation=90)
sns.set_context('notebook'); sns.despine(); plt.show()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1a802ypxrb6zhlxeeu4s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1a802ypxrb6zhlxeeu4s.png" alt="Name vs FPL Value" width="800" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. New Foreign (Count)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph = sns.countplot(x='new_foreign', data=dataset, palette="dark")
graph.set(xlabel="New Foreign", ylabel="Amount", title="How many are new signing from a different league")
sns.set_context('notebook'); sns.despine(); plt.show()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq72luxbyv1mg6dghfv3r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq72luxbyv1mg6dghfv3r.png" alt="New Foreign (Count)" width="800" height="549"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;11. New Foreign (By Name)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plt.figure(figsize=(20,6))
graph = sns.pointplot(x='name', y='new_foreign', data=dataset[:100], palette="dark")
graph.set(xlabel="Name", ylabel="New Foreign", title="Whether a new signing from a different league")
graph.set_xticklabels(graph.get_xticklabels(), rotation=90)
sns.set_context('notebook'); sns.despine(); plt.show()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faxsbd2r5c407p1epjh4r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faxsbd2r5c407p1epjh4r.png" alt="New Foreign (By Name)" width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12. New Signing (Count)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph = sns.countplot(x='new_signing', data=dataset, palette="rocket")
graph.set(xlabel="New Signing", ylabel="Amount", title="How many are new signing ")
sns.set_context('notebook'); sns.despine(); plt.show()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwjh2swwlm51o7ycxmbou.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwjh2swwlm51o7ycxmbou.png" alt="New Signing (Count)" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;13. New Signing (By Name)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plt.figure(figsize=(20,6))
graph = sns.pointplot(x='name', y='new_signing', data=dataset[:100], palette="bright")
graph.set(xlabel="Name", ylabel="New Signing", title="Whether a new signing")
graph.set_xticklabels(graph.get_xticklabels(), rotation=90)
sns.set_context('notebook'); sns.despine(); plt.show()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh9bsw6mx66ukae1nu49y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh9bsw6mx66ukae1nu49y.png" alt="New Signing (By Name)" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Feature Selection
&lt;/h2&gt;

&lt;p&gt;For modeling, I use the following five predictors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dataset = pd.read_csv('data.csv') 
X = dataset[['age', 'fpl_value', 'fpl_points', 'page_views', 'position_cat']]
Y = dataset['market_value']
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why these?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;age&lt;/code&gt; – price typically varies with age/prime years.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fpl_value, fpl_points&lt;/code&gt; – performance and fantasy value often correlate with perceived market value.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;page_views&lt;/code&gt; – a soft proxy for popularity/visibility.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;position_cat&lt;/code&gt; – price dynamics differ by position.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Train/Test Split + Scaling
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from sklearn.model_selection import train_test_split 
X_train, X_test, Y_train, Y_test = train_test_split(
    X, Y, test_size=0.2, random_state=0
)

from sklearn.preprocessing import StandardScaler 
sc_X = StandardScaler() 
X_train = sc_X.fit_transform(X_train) 
X_test = sc_X.transform(X_test)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why scaling?&lt;/strong&gt; Linear models are sensitive to feature scales; standardization helps stable coefficients and convergence.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Model: Linear Regression
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from sklearn.linear_model import LinearRegression 
regressor = LinearRegression() 
regressor.fit(X_train, Y_train)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make predictions on the test set:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Y_pred = regressor.predict(X_test)
df = pd.DataFrame({'Actual': Y_test, 'Predicted': Y_pred})
df.head()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fep099k7503dg8s1wih1h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fep099k7503dg8s1wih1h.png" alt="Linear Regression" width="516" height="820"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To see predictions across the full dataset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;X1 = sc_X.transform(X) 
Y_pred1 = regressor.predict(X1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output: -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;array([ 6.28665327e+01,  4.63344124e+01,  1.71999185e+01,  2.70542543e+01,
        1.67576333e+01,  2.31341678e+01,  3.06614290e+01,  1.26441319e+01,
        1.88859345e+01,  1.61778959e+01,  1.68413424e+01,  1.87550870e+01,
        1.53217919e+01,  2.00342164e+01,  5.03340141e+00,  9.45484552e+00,
        8.81515716e+00,  1.65135952e+01,  2.15921316e+01,  1.14508041e+01,
        4.94468838e+00,  2.20113374e+01,  5.06376105e+00,  9.02558975e+00,
        5.66032107e+00,  5.82966111e+00,  1.40691543e+01,  3.47309764e+01,
        2.54661370e+01,  3.17429798e+01,  9.84330289e+00,  6.72138221e+00,
        1.06760045e+01,  1.16738703e+01,  1.04311591e+01,  1.11660553e+01,
        4.62853856e+00,  1.29618040e+01,  8.85989508e+00,  2.93968695e+00,
        1.09260466e+01,  1.40564779e+01,  5.83211310e+00,  1.66622152e+00,
        6.92188866e+00,  5.12775349e+00,  4.77049269e+00,  8.60744252e-01,
        1.76621052e+00,  5.65940283e+00,  3.01078473e+00,  6.11320445e+00,
        4.77661984e-01,  6.86850732e+00,  4.09268232e+00,  4.45776943e+00,
       -1.21186324e+00, -4.32716636e+00,  2.27473673e+00, -1.88866900e+00,
        1.57521202e+00,  1.59605849e+00,  9.93010176e+00,  1.14337555e+00,
        4.70114334e-01, -5.69705594e-01,  5.49109710e+00,  2.42127613e+00,
        1.60229262e+00,  1.68421329e+00,  6.44917242e+00,  5.78379753e+00,
        9.27755719e-01,  1.58683879e+00,  1.39307739e+01,  1.21129834e+01,
        1.60684486e+01,  6.89538099e+00,  5.06714267e+00,  6.16871528e+00,
        7.97262607e+00,  1.09000523e+01,  6.59496956e+00,  8.34852473e+00,
        7.41193892e-01,  2.90238204e+00,  4.10618827e+00,  1.04340149e+01,
        5.29097527e+00,  1.77164410e+00,  9.12243523e-01, -1.71626246e+00,
        5.39393523e+01,  5.02586215e+01,  2.33287914e+01,  3.38398821e+01,
        2.27397252e+01,  2.76023255e+01,  2.06741282e+01,  2.40857909e+01,
        2.55614322e+01,  1.97780734e+01,  2.45654940e+01,  1.00361670e+01,
        2.12049333e+01,  8.44089635e+00,  2.72273014e+01,  1.32175831e+01,
        1.00032029e+01,  2.07556329e-02,  1.34878506e+01,  8.99831431e+00,
        2.46911471e+01,  2.84420802e+01,  1.37693399e+01,  1.39753539e+01,
        4.14940785e+00,  7.89296807e+00,  4.59603873e+00,  9.33580921e+00,
        9.17322247e+00,  5.91166865e+00,  7.20501161e+00,  1.62985464e+00,
        9.77106295e+00,  5.24199276e+00,  6.77506385e+00, -1.10826023e-01,
        6.70876820e+00,  1.51229913e+00,  3.64913411e+00,  5.86341313e+00,
       -1.71934842e+00,  2.64918075e+01,  1.53767278e+01,  2.08364791e+01,
        1.28360458e+01,  1.42769184e+01,  1.83438607e+01,  8.39739780e+00,
        1.54972711e+01,  9.24879295e+00,  8.84735296e+00,  4.27543923e+01,
        1.00334222e+01,  6.67323145e+00,  4.24451728e+00,  1.64599406e+01,
        8.93319695e+00,  1.36017222e+01,  9.23623029e+00,  4.75455136e+00,
        5.70086565e+00,  5.26865228e+00,  6.05140101e+00,  1.27525174e+01,
        3.33916737e+00,  5.90391575e+00,  2.80368956e+00,  1.71560146e+01,
        1.77938304e+01,  4.82038725e+00,  4.59853329e+00,  3.02243318e+00,
        2.64504042e+00,  6.44877606e+00,  3.59123084e+00, -8.69915834e-01,
        2.93424055e+00, -2.94119546e+00,  3.14294737e+00,  3.46717211e+00,
        8.45537926e+00,  2.31326804e+00,  5.60399756e-01,  3.76573016e+00,
        1.30656073e-01,  1.83081491e+00, -2.04944876e+00,  2.08635844e-01,
       -6.24129449e-01,  8.17555691e+00,  9.17157126e+00,  7.59654639e+00,
        5.81263224e+00,  2.15563645e+00, -4.78803512e-01,  4.23712894e+00,
        8.80441122e+00,  3.50444501e+01,  3.07869954e+01,  1.59727357e+01,
        9.11841002e+00,  1.07657645e+01,  9.27215255e+00,  6.23564852e+00,
        1.96676802e+01,  1.10408239e+01,  8.46461158e+00,  4.94055844e+00,
        6.76284129e+00,  1.13816079e+01,  1.06885705e+01,  6.05253148e+00,
        2.99910714e+00,  1.44952259e+01,  3.61337549e+00,  2.60868278e+00,
        7.41538690e+00,  2.92184993e+00,  4.45153531e+00,  3.78618026e+00,
        8.64074595e+00,  3.50352917e+01,  4.00189086e+01,  4.30005449e+01,
        2.43905161e+01,  2.12379487e+01,  2.52051293e+01,  1.54203647e+01,
        1.33076223e+01,  1.40963410e+01,  1.33599626e+01,  1.71506799e+01,
        2.39610467e+01,  1.30875717e+01,  2.62851963e+01,  4.77089334e+00,
        5.82049375e+00,  1.00155278e+01,  1.43421271e+01,  8.23561008e+00,
        5.30518579e+00,  7.40927061e+00,  5.53990619e+00,  7.30884677e+00,
        5.55237174e+00,  2.70476182e+01,  7.80253031e+00,  6.98958048e+00,
        4.33994048e+01,  5.54702805e+01,  3.20615354e+01,  2.21769627e+01,
        2.53293890e+01,  3.42494372e+01,  1.31454153e+01,  1.21667107e+01,
        1.97419795e+01,  6.30015138e+00,  8.82081099e+00,  5.06400874e+01,
        1.57180792e+01,  1.44266939e+01,  2.25336943e+01,  1.35383098e+01,
        5.05587301e-01,  3.04413219e+00,  1.27785472e+01,  2.29855522e+01,
        5.81554453e+01,  2.31388392e+01,  2.16422756e+01,  5.10021411e+01,
        2.18816842e+01,  2.28615104e+01,  1.47747468e+01,  1.52930900e+01,
        3.17042563e+01,  1.46778860e+01,  3.35870220e+01,  3.10865733e+01,
        1.64592195e+01,  1.69076901e+01,  1.11555766e+01,  1.29238188e+01,
        9.61917212e+00,  1.25204674e+01,  5.30423360e+00,  5.54871109e+00,
        1.00654973e+01,  4.98946114e+00,  7.42955630e+00,  6.31904380e+00,
        1.30403887e+01,  1.00392522e+00,  6.06577036e+00,  6.72085484e+00,
        3.73134019e+00,  4.18149614e+00,  4.22383012e+00,  1.91381534e+00,
       -1.28088146e+00,  3.41045955e+00,  1.79497319e+00,  1.05829507e+01,
        9.43534298e+00,  3.28532558e+00,  1.35250312e+00,  4.38494855e+00,
        2.07244010e+00,  1.75906926e+00,  1.43509874e+01,  6.87198964e+00,
        6.13033140e+00, -2.33888264e+00,  1.35990916e+01,  1.80634481e+01,
        1.46927448e+01,  1.44239848e+01,  1.12612981e+01,  1.29791664e+01,
        6.24648586e+00,  9.03304108e+00,  5.25226415e+00,  1.51571160e+01,
        1.41645531e+01,  1.01954205e+01,  9.91526470e+00,  1.17886001e+01,
        3.27217678e+00,  5.94602737e+00,  2.11646419e+01,  4.44317689e+00,
        6.10421380e+00,  2.47182931e+00,  9.65090120e-01,  5.44983836e+00,
        5.29387882e+00,  1.22565818e+01,  1.78140601e+01,  7.59876326e+00,
        9.32675979e+00,  5.76379440e+00,  9.09217109e+00,  1.39168840e+01,
        9.92486243e+00,  1.19482597e+00,  5.87981968e+00,  3.78964322e+00,
        4.60747657e+00,  6.09054273e+00,  7.18585630e+00,  5.48772878e+00,
        1.01458041e+01,  2.99328230e+00,  1.21505520e+01,  3.70836344e+00,
        1.08663018e+01,  3.86679739e+00,  7.27572286e+00,  2.95082669e+01,
        2.28551986e+01,  8.11729167e+00,  1.09926147e+01,  1.23986210e+01,
        6.04083954e+00,  5.54532532e+00,  5.13323449e+00,  8.13637450e+00,
        5.03507346e+00,  6.15626580e+00,  5.97910234e+00,  5.35986738e+00,
       -2.24795766e-01,  6.53422485e+00, -1.30726559e+00,  4.22683927e+00,
        3.46130466e+00,  2.62146976e+00,  5.16180438e+00, -6.12786456e-01,
        1.87310775e+00,  2.18184157e+00,  6.84458483e-01,  1.15822758e+01,
        5.43069136e+01,  6.54671081e+01,  3.79330854e+01,  3.21481995e+01,
        1.72037115e+01,  1.59411311e+01,  1.74161390e+01,  1.11834417e+01,
        1.28956970e+01,  1.40528607e+01,  1.94235419e+01,  9.06373403e+00,
        2.21515945e+01,  1.22072454e+01,  1.16944338e+01,  9.81890962e+00,
        1.34160836e+01,  6.47409346e+00,  8.09325423e+00,  5.34652950e+00,
        1.15204048e+01,  1.72578040e+01,  6.88453524e+00,  7.38962753e+00,
        3.82242989e+00,  4.63910853e+00,  3.52678463e+00,  4.17896473e+00,
        7.89789526e+00,  8.12813073e+00,  1.27843162e+00,  9.97198566e+00,
        8.03247501e+00,  6.45394674e+00,  5.12676355e+00,  3.96953706e+00,
        9.13592851e+00,  1.70473040e-01,  6.70820319e+00,  4.63104526e+00,
        4.59259892e+00,  3.44236036e+00,  2.69420533e+00,  6.32927942e+00,
        7.78319819e+00,  1.53732744e+01,  1.28845013e+01,  7.87680461e+00,
        1.26908110e+01,  9.99255503e+00,  8.46245403e+00,  8.29923735e+00,
        8.85993621e+00,  8.23448929e+00,  8.17877211e+00,  1.09487410e+01,
        2.08215886e+00,  4.43309931e+00,  5.53899424e+00,  3.45700961e+00,
        4.43442418e+00, -3.65736914e-01,  3.47071664e+00,  1.49935272e+01,
        1.97778766e+01,  2.34133710e+01,  9.59576755e+00,  9.65451702e+00,
        1.81178362e+01,  7.31740896e+00,  8.88841637e+00,  7.79515304e+00,
        3.52915171e+00,  1.30045353e+01,  6.92258405e+00,  8.99422402e+00,
        4.63065558e+00,  7.37182795e+00,  4.50268052e+00,  7.47405175e+00,
        5.66246456e+00,  6.41619652e+00,  6.22417826e+00,  3.21996267e+00,
        5.11293760e+00])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Evaluation: 10-Fold Cross-Validation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from sklearn.model_selection import cross_val_score 
accuracy = cross_val_score(estimator=regressor, X=X_train, y=Y_train, cv=10)
print(accuracy.mean())
print(accuracy.std())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Metric&lt;/strong&gt;: By default, &lt;code&gt;LinearRegression&lt;/code&gt; with &lt;code&gt;cross_val_score&lt;/code&gt; uses the estimator’s &lt;code&gt;.score()&lt;/code&gt; which is &lt;strong&gt;R²&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Report&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CV Mean R²&lt;/strong&gt;: &lt;code&gt;{{CV_MEAN_R2}}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CV Std&lt;/strong&gt;: &lt;code&gt;{{CV_STD_R2}}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcvf9d3v4x4pj82rxhx7n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcvf9d3v4x4pj82rxhx7n.png" alt="Metrics" width="350" height="88"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you prefer error metrics, add: from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score and compute MAE/RMSE/R² on the held-out test set.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Even a &lt;strong&gt;small, clean feature set&lt;/strong&gt; can drive a reasonable baseline.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fpl_value&lt;/code&gt; and &lt;code&gt;fpl_points&lt;/code&gt; usually show strong signal; if you have access to richer performance data (minutes, xG, assists/90, age-curve features), add them.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;page_views&lt;/code&gt; captures attention, which influences pricing; try other popularity proxies.&lt;/li&gt;
&lt;li&gt;Consider &lt;strong&gt;regularized models&lt;/strong&gt; (Ridge/Lasso) or &lt;strong&gt;tree ensembles&lt;/strong&gt; (RandomForest, XGBoost) and compare CV scores.&lt;/li&gt;
&lt;li&gt;Plot &lt;strong&gt;residuals vs. predicted&lt;/strong&gt; to check for systematic under/over-valuation (especially on very high-value players).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Follow-Up Questions
&lt;/h2&gt;

&lt;p&gt;I’d love to hear your thoughts!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which additional features would you include to improve prediction accuracy?&lt;/li&gt;
&lt;li&gt;Do you think football player value is more influenced by performance or popularity metrics?&lt;/li&gt;
&lt;li&gt;Would you like to see a version of this project using RandomForest/XGBoost?&lt;/li&gt;
&lt;li&gt;Should I deploy this model as an interactive web app where you can enter player stats and get predictions?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to comment below — I’d love to discuss and expand this project further!&lt;/p&gt;




&lt;h2&gt;
  
  
  Connect With Me
&lt;/h2&gt;

&lt;p&gt;Let’s learn and build cool data projects together!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💼 LinkedIn: &lt;a href="https://www.linkedin.com/in/singla-khushi/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/singla-khushi/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔗 GitHub: &lt;a href="https://github.com/KhushiSingla-tech" rel="noopener noreferrer"&gt;https://github.com/KhushiSingla-tech&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📩 Comments below are always welcome!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>machinelearning</category>
      <category>datascience</category>
      <category>python</category>
      <category>football</category>
    </item>
    <item>
      <title>Seamless API Test Automation: Integrating Karate Framework with Jenkins</title>
      <dc:creator>Khushi Singla</dc:creator>
      <pubDate>Thu, 29 May 2025 08:29:02 +0000</pubDate>
      <link>https://dev.to/khushi_singla/seamless-api-test-automation-integrating-karate-framework-with-jenkins-1onb</link>
      <guid>https://dev.to/khushi_singla/seamless-api-test-automation-integrating-karate-framework-with-jenkins-1onb</guid>
      <description>&lt;p&gt;Ensuring your APIs remain reliable with every new release can be time-consuming—unless you automate it. Integrating Karate, a powerful API testing framework, with Jenkins, your go-to CI/CD server, can drastically reduce manual testing efforts and catch issues early in the development cycle.&lt;/p&gt;

&lt;p&gt;In this blog post, you’ll learn how to set up and run Karate tests in Jenkins, create beautiful reports, and leverage advanced configuration to fit your workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is Karate?
&lt;/h2&gt;

&lt;p&gt;Karate is an open-source API test automation framework that combines API test-automation, mocks, performance-testing, and even UI automation into a single unified framework. Built on top of Cucumber, it uses &lt;strong&gt;Gherkin syntax&lt;/strong&gt; for writing test scenarios in plain language, making it ideal for both developers and testers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Integrate Karate with Jenkins?
&lt;/h2&gt;

&lt;p&gt;Here's why this duo is a win-win:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Automated Testing&lt;/strong&gt; — Run API tests automatically after each commit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Early Bug Detection&lt;/strong&gt; — Catch regressions before they hit production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Efficient Workflow&lt;/strong&gt; — Save time by reducing manual testing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-Time Feedback&lt;/strong&gt; — Get detailed, instantly available test reports.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved Code Quality&lt;/strong&gt; — Continuous testing ensures confidence in code changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt; — Supports parallel testing for large test suites.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Toolchain Friendly&lt;/strong&gt; — Plays nicely with other Jenkins plugins (like JUnit, HTML Publisher).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Centralized Management&lt;/strong&gt; — Control everything from Jenkins' UI.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Karate and Jenkins Integration &amp;amp; Execution Flow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Integration Steps (Setup Phase)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffpjxk79p5t03keknzq3n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffpjxk79p5t03keknzq3n.png" alt="Karata and Jenkins Integration" width="800" height="611"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Execution Steps (Per Build)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft24ddd7v1nntc093urim.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft24ddd7v1nntc093urim.png" alt="Steps" width="800" height="132"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Make sure the following are in place before you begin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jenkins installed and running&lt;/li&gt;
&lt;li&gt;Plugins: Pipeline, Git, and JUnit&lt;/li&gt;
&lt;li&gt;A Karate test project (Maven-based)&lt;/li&gt;
&lt;li&gt;Your code hosted in a version control system (e.g., GitHub)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Jenkins + Karate Integration: Step-by-Step
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1. Create a New Jenkins Pipeline
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open Jenkins and log in.&lt;/li&gt;
&lt;li&gt;Click on “New Item” from the dashboard.&lt;/li&gt;
&lt;li&gt;Enter a name for your pipeline job.&lt;/li&gt;
&lt;li&gt;Select “Pipeline” and click OK.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 2. Configure the Pipeline
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Option 1: Using Inline Script&lt;/strong&gt;&lt;br&gt;
Paste the following pipeline script under the Pipeline section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipeline {
    agent {
        node {
            label 'spot_security'
        }
    }
    tools {
        maven 'sonar-maven'
        jdk 'OpenJDK-11'
    }
    stages {
        stage('Karate Test') {
            steps {
                script {
                    try {
                        sh "mvn test -Dtest=&amp;lt;TestRunner&amp;gt; -s mvnsettings.xml"
                    } catch (Exception e) {
                        currentBuild.result = 'UNSTABLE'
                    }
                }
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Option 2: Using Jenkinsfile from SCM&lt;/strong&gt;&lt;br&gt;
Select "Pipeline script from SCM"&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choose Git as SCM&lt;/li&gt;
&lt;li&gt;Set Repository URL: &lt;code&gt;https://github.com/your-org/your-repo.git&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Set Script Path: Jenkinsfile&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Step 3. Add Karate to your pom.xml
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;dependencies&amp;gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;com.intuit.karate&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;karate-junit5&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;1.4.0&amp;lt;/version&amp;gt; &amp;lt;!-- Or latest --&amp;gt;
        &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
    &amp;lt;/dependency&amp;gt;
&amp;lt;/dependencies&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Advanced Configurations
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Passing Environment Variables
&lt;/h3&gt;

&lt;p&gt;Want to inject dynamic values (e.g., base URLs) into your tests?&lt;br&gt;
Update the pipeline like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stage('Karate Test') {
    steps {
        script {
            try {
                sh "mvn test -Dtest=&amp;lt;TestRunner&amp;gt; -Dkarate.env=${params.TEST_ENV} -s mvnsettings.xml"
            } catch (Exception e) {
                currentBuild.result = 'UNSTABLE'
            }
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensure your &lt;code&gt;karate-config.js&lt;/code&gt; handles &lt;code&gt;karate.env&lt;/code&gt; appropriately.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Publish Karate Test Report in Jenkins
&lt;/h3&gt;

&lt;p&gt;To generate a nice HTML report for each test run, use the publishHTML plugin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stage('Publish Karate Report') {
    steps {
        script {
            try {
                publishHTML(target: [
                    allowMissing: false,
                    alwaysLinkToLastBuild: true,
                    keepAll: true,
                    reportDir: 'target/cucumber-html-reports',
                    reportFiles: 'overview-features.html',
                    reportName: 'Karate Test Report'
                ])
            } catch (Exception e) {
                currentBuild.result = 'UNSTABLE'
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ Make sure karate.output.path is not overridden in your project if you rely on the default report location.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Running the Pipeline
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Trigger manually from Jenkins UI&lt;/li&gt;
&lt;li&gt;Or set up automatic triggers:

&lt;ul&gt;
&lt;li&gt;Poll SCM (e.g., H/5 * * * *)&lt;/li&gt;
&lt;li&gt;Webhook-based triggering from GitHub/GitLab/etc.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Once triggered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Watch logs in Console Output&lt;/li&gt;
&lt;li&gt;Navigate to Published Reports for visual test summaries&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Integrating Karate with Jenkins allows teams to automate API tests as part of their CI/CD pipeline. This ensures higher code quality, early bug detection, and streamlined collaboration between QA and development. With minimal setup, you’ll save hours of manual regression testing and boost release confidence.&lt;/p&gt;




&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;p&gt;📘 &lt;a href="https://karatelabs.io/docs/" rel="noopener noreferrer"&gt;Official Karate Documentation&lt;/a&gt;&lt;br&gt;
🧪 &lt;a href="https://github.com/karatelabs/karate" rel="noopener noreferrer"&gt;Karate GitHub Repository&lt;/a&gt;&lt;br&gt;
📦 &lt;a href="https://mvnrepository.com/artifact/com.intuit.karate/karate-junit5" rel="noopener noreferrer"&gt;Karate on Maven Central&lt;/a&gt;&lt;br&gt;
🎓 &lt;a href="https://github.com/karatelabs/karate/tree/master/karate-demo" rel="noopener noreferrer"&gt;Karate Tutorials on GitHub&lt;/a&gt;&lt;br&gt;
📺 &lt;a href="https://www.youtube.com/@KarateLabs" rel="noopener noreferrer"&gt;Karate YouTube Channel&lt;/a&gt;&lt;br&gt;
💡 &lt;a href="https://github.com/karatelabs/karate/releases" rel="noopener noreferrer"&gt;Karate Changelog &amp;amp; Release Notes&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>automationtesting</category>
      <category>karate</category>
      <category>apitestautomation</category>
    </item>
    <item>
      <title>A Developer’s Guide to API Testing with Karate Framework</title>
      <dc:creator>Khushi Singla</dc:creator>
      <pubDate>Thu, 29 May 2025 06:48:49 +0000</pubDate>
      <link>https://dev.to/khushi_singla/a-developers-guide-to-api-testing-with-karate-framework-2dpj</link>
      <guid>https://dev.to/khushi_singla/a-developers-guide-to-api-testing-with-karate-framework-2dpj</guid>
      <description>&lt;p&gt;In the world of modern software development, API testing is essential for validating backend services—ensuring they respond correctly, behave as expected, and remain reliable over time. Among the many tools available for API automation, Karate Framework stands out for its elegant syntax, powerful capabilities, and developer-friendly approach.&lt;/p&gt;

&lt;p&gt;This guide walks you through what Karate is, why it's a compelling choice for API testing, how to write your first test, and how to integrate Karate into your CI/CD pipeline for continuous quality assurance.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is Karate Framework?
&lt;/h2&gt;

&lt;p&gt;Karate is an open-source test automation tool designed specifically for API testing. Built on top of the Cucumber JVM, it enables developers and testers to write expressive, readable tests using simple Gherkin syntax inside &lt;code&gt;.feature&lt;/code&gt; files—no Java code required to get started.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Features of Karate
&lt;/h2&gt;

&lt;p&gt;✅ Supports testing of REST, SOAP, GraphQL, and HTTP APIs&lt;br&gt;
✅ Built-in assertions for JSON and XML payloads&lt;br&gt;
✅ Data-driven testing using Scenario Outline&lt;br&gt;
✅ Supports reusable test logic via call and external files&lt;br&gt;
✅ Includes tools for API mocking and performance testing&lt;br&gt;
✅ Parallel test execution out of the box&lt;br&gt;
✅ Native support for reporting and logging&lt;br&gt;
✅ Seamless integration with Maven, Gradle, and CI/CD pipelines&lt;/p&gt;


&lt;h2&gt;
  
  
  Why Choose Karate for API Testing?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity&lt;/strong&gt;: Write clean and concise tests without boilerplate code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unified Testing Tool&lt;/strong&gt;: Combine functional, mocking, and performance testing in one framework.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data-Driven&lt;/strong&gt;: Define test scenarios once and run them with multiple datasets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reusability&lt;/strong&gt;: Easily modularize tests using call for maintainable test suites.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active Community&lt;/strong&gt;: Strong documentation and support from the open-source community.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Setting Up Karate Framework
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Create a Maven Project
&lt;/h3&gt;

&lt;p&gt;If you're using Maven, start by adding the Karate dependency to your &lt;code&gt;pom.xml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;com.intuit.karate&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;karate-junit5&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.3.1&amp;lt;/version&amp;gt;
    &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Alternatively, you can use Gradle—Karate supports both build tools.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. Create the Directory Structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src
└── test
    └── java
        └── api
            └── test.feature
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Writing Your First Karate Test
&lt;/h2&gt;

&lt;p&gt;Let’s start with a simple GET request to the GitHub API.&lt;/p&gt;

&lt;p&gt;File: &lt;code&gt;src/test/java/api/test.feature&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Feature: Test GitHub API

  Scenario: Get user details
    Given url 'https://api.github.com/users/octocat'
    When method get
    Then status 200
    And match response.login == 'octocat'
    And match response.id == 583231
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What’s Happening Here?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Given url&lt;/code&gt; sets the target API endpoint.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;When method get&lt;/code&gt; performs a GET request.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Then status&lt;/code&gt; checks for HTTP 200 OK.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;match asserts&lt;/code&gt; the content of the response.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Running Karate Tests
&lt;/h2&gt;

&lt;p&gt;Create a Java test runner to execute your &lt;code&gt;.feature&lt;/code&gt; files using JUnit 5:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import com.intuit.karate.junit5.Karate;

class ApiTestRunner {
    @Karate.Test
    Karate testAll() {
        return Karate.run("api/test").relativeTo(getClass());
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run this test just like any JUnit test—either from your IDE or within a CI environment.&lt;/p&gt;




&lt;h2&gt;
  
  
  Advanced Examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Data-Driven Testing
&lt;/h3&gt;

&lt;p&gt;You can use &lt;code&gt;Scenario Outline&lt;/code&gt; and an &lt;code&gt;Examples&lt;/code&gt; table to test multiple variations of a scenario:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Feature: Test multiple GitHub users

  Scenario Outline: Validate GitHub users exist
    Given url 'https://api.github.com/users/&amp;lt;username&amp;gt;'
    When method get
    Then status 200
    And match response.login == '&amp;lt;username&amp;gt;'

  Examples:
    | username |
    | octocat  |
    | defunkt  |
    | mojombo  |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Sending POST Request with Headers and Params
&lt;/h3&gt;

&lt;p&gt;Here’s how to test a POST endpoint with headers, query parameters, and a request body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Feature: Create resource on mock API

  Scenario: Create a post with query params and headers
    Given url 'https://jsonplaceholder.typicode.com/posts'
    And param draft = true
    And header Authorization = 'Bearer dummyToken123'
    And header Content-Type = 'application/json'
    And request
      """
      {
        "title": "foo",
        "body": "bar",
        "userId": 1
      }
      """
    When method post
    Then status 201
    And match response.title == 'foo'
    And match response.body == 'bar'
    And match response.userId == 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Karate in CI/CD Pipelines
&lt;/h2&gt;

&lt;p&gt;Karate tests are easy to integrate into your build pipelines using Maven or Gradle. For example, a basic Maven command to run all tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mvn test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can plug this into your CI workflows (GitHub Actions, Jenkins, GitLab CI, etc.) to ensure automated API validation as part of every build.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Check out my next blog&lt;/strong&gt;: &lt;a href="https://dev.to/khushi_singla/seamless-api-test-automation-integrating-karate-framework-with-jenkins-1onb"&gt;Integrating Karate with Jenkins&lt;/a&gt; for CI/CD for a step-by-step guide on setting up Karate in a Jenkins pipeline.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Karate makes API testing both accessible and powerful. Whether you're validating REST endpoints, mocking responses, or setting up performance tests, Karate provides a unified solution that fits seamlessly into modern development workflows.&lt;/p&gt;

&lt;p&gt;If you're just getting started with API automation, Karate’s readable syntax and robust features make it one of the best tools to learn and use.&lt;/p&gt;




&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;p&gt;📘 &lt;a href="https://karatelabs.io/docs/" rel="noopener noreferrer"&gt;Official Karate Documentation&lt;/a&gt;&lt;br&gt;
🧪 &lt;a href="https://github.com/karatelabs/karate" rel="noopener noreferrer"&gt;Karate GitHub Repository&lt;/a&gt;&lt;br&gt;
📦 &lt;a href="https://mvnrepository.com/artifact/com.intuit.karate/karate-junit5" rel="noopener noreferrer"&gt;Karate on Maven Central&lt;/a&gt;&lt;br&gt;
🎓 &lt;a href="https://github.com/karatelabs/karate/tree/master/karate-demo" rel="noopener noreferrer"&gt;Karate Tutorials on GitHub&lt;/a&gt;&lt;br&gt;
📺 &lt;a href="https://www.youtube.com/@KarateLabs" rel="noopener noreferrer"&gt;Karate YouTube Channel&lt;/a&gt;&lt;br&gt;
💡 &lt;a href="https://github.com/karatelabs/karate/releases" rel="noopener noreferrer"&gt;Karate Changelog &amp;amp; Release Notes&lt;/a&gt;&lt;/p&gt;

</description>
      <category>karate</category>
      <category>apitesting</category>
      <category>tutorial</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
