DEV Community

Cover image for ต่อยอด Laravel Debugbar เพื่อดีบัก Rest API Routes
Atthaphon Urairat
Atthaphon Urairat

Posted on

2

ต่อยอด Laravel Debugbar เพื่อดีบัก Rest API Routes

ปัญหา 👹

บทความนี้เขียนจากประสบการณ์จริง โปรเจ็คที่ผมทำอยู่มีปัญหาด้านความเร็วในการตอบสนอง เพราะ endpoint บางตัวใช้เวลาในการตอบสนองนานกว่า 10s ทำให้ไม่สามารถที่จะยอมรับได้ เพราะ ช้าเกินไปมากๆๆๆ 😩😩😩 ถ้าเป็นคนที่ทำโปรเจ็คมาตั้งแต่ต้น การดีบักก็คงไม่มีปัญหา

ผมลองจินตนาการดู ถ้าเราไม่ได้ทำโปรเจ็คต่อล่ะ สมมุติถ้าคนที่มาจับโปรเจ็คต่อไม่ได้มีงานแค่ตัวเดียวล่ะ เขาต้องมาเสียเวลาส่วนมากไปกับแก้ปัญหานิดๆ หน่อยๆ อย่างนั้นหรือ ดูไม่คุ้มเลย 😡

ผมเลย install package Debugbar เผื่อไว้เพื่อทีจะเอาไว้ดีบัก แต่ติดที่ว่า debugbar ไม่สามารถโชว์ผลลัพธ์ใน api route ได้ 😭😭 เอาล่ะสิต้องพึ่งพา อากู๋ หน่อยล่ะ แล้วในที่สุดหลังจากการ research ผมก็ได้มาซึ่งสิ่งที่ต้องการ 🎉🎉🎉

Framework & Packages ⚙️

# install laravel 5.4
composer create-project --prefer-dist laravel/laravel yourProjectName "5.4.*"
# install debugbar 2.4 that compatible with laravel 5.4
composer require barryvdh/laravel-debugbar:~2.4
# install dingo/api
composer require dingo/api
Enter fullscreen mode Exit fullscreen mode

ผมไม่ได้แสดงวิธี install ทุกขั้นตอนนะครับ เพื่อนๆ สามารถอ่านวิธีการ install และ config เบื้องต้นได้จาก link ที่ให้ไว้ได้นะครับ

วิธีทำ 👩‍🏫

จากที่เห็น โปรเจ็คตัวนี้ใช้ laravel v5.4, debugbar v2.4 และ dingo api v1 ส่ิงที่เราต้องการคือ การโชว์ข้อมูลจาก debugbar เมื่อเราทำการ access api route จาก browser หรือ postman

เริ่มด้วยการสร้าง Middleware

<?php

namespace App\Http\Middleware;

use Closure;
use Dingo\Api\Http\Response;

class ProfileDingoHttpResponse
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $response = $next($request);

        if ($response instanceof Response &&
            app()->bound('debugbar') &&
            app('debugbar')->isEnabled()
        ) {
            $queries_data = $this->sqlFilter(app('debugbar')->getData());
            $response->setContent(json_decode($response->morph()->getContent(), true) + [
                '_debugbar' => [
                    'total_queries' => count($queries_data),
                    'queries' => $queries_data,
                    'time' => app('debugbar')->getData()['time'],
                    'memory' => app('debugbar')->getData()['memory'],
                ],
            ]);
        }

        return $response;
    }

    /**
     * Get only sql and each duration
     *
     * @param $debugbar_data
     * @return array
     */
    protected function sqlFilter($debugbar_data)
    {
        $result = array_get($debugbar_data, 'queries.statements');

        return array_map(function ($item) {
            return [
                'sql' => array_get($item, 'sql'),
                'duration' => array_get($item, 'duration_str'),
            ];
        }, $result);
    }
}

Enter fullscreen mode Exit fullscreen mode

จากนั้นทำการเพิ่ม middleware ProfileDingoHttpResponse ที่เราเพิ่งสร้างไป ในไฟล์ Kernel.php ซึ่งอยู่ใน yourProjectName/app/Http/Kernel.php

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    ...

    protected $routeMiddleware = [
        ...
        'profile-dingo-http' => \App\Http\Middleware\ProfileDingoHttpResponse::class,
    ];
}
Enter fullscreen mode Exit fullscreen mode

หลังจากที่เราเพิ่ม 'profile-dingo-http' => \App\Http\Middleware\ProfileDingoHttpResponse::class, ไปใน $routeMiddleware จากนั้นเราก็สามารถเพิ่ม middleware ได้แล้ว โดยในโปรเจ็คนี้เราใช้ Dingo api ซึ่งจะเห็นวิธีเพิ่ม middleware ได้จากตัวอย่างด้านล่าง

<?php
$api = app('Dingo\Api\Routing\Router');

$api->version('v1', ['middleware' => 'profile-dingo-http'], function ($api) {
    ...
});
Enter fullscreen mode Exit fullscreen mode

🎉🎉🎉 เสร็จแล้วครับ

ผลลัพธ์ 💯

หลังจากทำการเรียก api จาก url เราจะได้ผลลัพธ์ซึ่งเป็นข้อมูลจาก debugbar ที่เราสร้างไว้ใน Middleware ProfileDingoHttpResponse ห้อยท้ายมาด้วย

นี่คือผลลัพธ์ที่ได้ห้อยท้ายเพิ่มเติมเมื่อเราเพิ่ม middleware เข้าไปครับ ถ้าหากไม่ชัดก็สามารถดูตัวอย่างจากด้านล่างได้ครับ

"_debugbar": {
    "total_queries": 1,
    "queries": [
        {
            "sql": "select `id`, `name`, `description` from `product` where `id` = '2' limit 1",
            "duration": "14.01ms"
        }
    ],
    "time": {
        "start": 1561688591.7021,
        "end": 1561688591.8966,
        "duration": 0.19451189041138,
        "duration_str": "194.51ms",
        "measures": [
            {
                "label": "Booting",
                "start": 1561688591.7021,
                "relative_start": 0,
                "end": 1561688591.786,
                "relative_end": 1561688591.786,
                "duration": 0.083874940872192,
                "duration_str": "83.87ms",
                "params": [],
                "collector": null
            },
            {
                "label": "Application",
                "start": 1561688591.7738,
                "relative_start": 0.071721792221069,
                "end": 1561688591.8966,
                "relative_end": 0.0000050067901611328,
                "duration": 0.12279510498047,
                "duration_str": "122.8ms",
                "params": [],
                "collector": null
            }
        ]
    },
    "memory": {
        "peak_usage": 19660800,
        "peak_usage_str": "18.75MB"
    }
}

Enter fullscreen mode Exit fullscreen mode

ด้วยเหตุฉนั้น เลยได้ผลลัพธ์ในแบบฉนี้ และแล้วในตอนนี้การ debug ก็จะง่ายขึ้นไม่ว่าจะสำหรับคนเก่าหรือใหม่ ซึ่งสามารถทำให้เราหาสาเหตุของสิ่งที่เราต้องการแก้หรือปรับปรุงได้ง่ายยิ่งขึ้น ขอบคุณครับ จบแล้วครับ 🥳 🥳 🥳

Source & so much thanks ❤️🎉🥰

REST API profiling #252

API Trace View

How I Cut 22.3 Seconds Off an API Call with Sentry

Struggling with slow API calls? Dan Mindru walks through how he used Sentry's new Trace View feature to shave off 22.3 seconds from an API call.

Get a practical walkthrough of how to identify bottlenecks, split tasks into multiple parallel tasks, identify slow AI model calls, and more.

Read more →

Top comments (0)

The Most Contextual AI Development Assistant

Pieces.app image

Our centralized storage agent works on-device, unifying various developer tools to proactively capture and enrich useful materials, streamline collaboration, and solve complex problems through a contextual understanding of your unique workflow.

👥 Ideal for solo developers, teams, and cross-company projects

Learn more