How to draw shapes in the node editor with python bgl
Here is a basic bgl, blf (and gpu) example based on this answer:

import bpy
import bgl, blf, gpu
from gpu_extras.batch import batch_for_shader
from mathutils import Vector
import math


def draw_poly(coords, color, width):
    shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
    batch = batch_for_shader(shader,'LINE_STRIP', {&quot;pos&quot;: coords})
    bgl.glLineWidth(width)
    shader.bind()
    shader.uniform_float(&quot;color&quot;, color)
    batch.draw(shader)

# based on http://slabode.exofire.net/circle_draw.shtml
def draw_circle_2d(color, cx, cy, r, num_segments):
    theta = 2 * math.pi / num_segments
    c = math.cos(theta)
    s = math.sin(theta)
    x = r # we start at angle = 0
    y = 0
    
    vector_list = []
    for i in range (num_segments+1):
        vector_list.append(Vector((x + cx, y + cy)))
        t = x
        x = c * x - s * y
        y = s * t + c * y           
    draw_poly(vector_list, color, 1)
    

def draw_line_2d(color, start, end):
    shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
    batch = batch_for_shader(shader, 'LINES', {&quot;pos&quot;: [start,end]})
    shader.bind()
    shader.uniform_float(&quot;color&quot;, color)
    batch.draw(shader)
    
def draw_typo_2d(color, text):
    font_id = 0
    blf.position(font_id, 20, 70, 0)
    blf.color(font_id, color[0], color[1], color[2], color[3])
    blf.size(font_id, 20, 72)
    blf.draw(font_id, text)


def draw_callback_px(self, context):

    # ...api_current/bpy.types.Area.html?highlight=bpy.types.area
    width = context.area.width
    height = context.area.height - context.area.regions[0].height
    
    # 80% alpha, 2 pixel width line
    bgl.glEnable(bgl.GL_BLEND)
    bgl.glEnable(bgl.GL_LINE_SMOOTH)
    bgl.glEnable(bgl.GL_DEPTH_TEST)

    shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
    batch = batch_for_shader(shader, 'LINE_STRIP', {&quot;pos&quot;: self.mouse_path})
    shader.bind()
    shader.uniform_float(&quot;color&quot;, (1.0, 0.0, 1.0, 0.5))
    batch.draw(shader)

    draw_line_2d((0.0, 1.0, 0.0, 0.8), (0,0), (width, height))

    # yellow line
    draw_line_2d((1.0, 1.0, 0.0, 0.8), (width, 0), (0, height)) 

    # white circle
    draw_circle_2d((1.0, 1.0, 1.0, 0.8), width*.5, height*.5, 70, 360)

    # red circle
    draw_circle_2d((1.0, 0.0, 0.0, 0.4), width*.5, height*.5, 230, 5)

    # draw text
    draw_typo_2d((1.0, 0.0, 0.0, 1), &quot;Hello Word &quot; + str(len(self.mouse_path)))

    # restore opengl defaults
    bgl.glLineWidth(1)
    bgl.glDisable(bgl.GL_BLEND)
    bgl.glDisable(bgl.GL_LINE_SMOOTH)
    bgl.glEnable(bgl.GL_DEPTH_TEST)


class ModalDrawOperator(bpy.types.Operator):
    &quot;&quot;&quot;Draw a line with the mouse&quot;&quot;&quot;
    bl_idname = &quot;node.modal_operator&quot;
    bl_label = &quot;Simple Modal Node Editor Operator&quot;

    def modal(self, context, event):
        context.area.tag_redraw()

        if event.type == 'MOUSEMOVE':
            self.mouse_path.append((event.mouse_region_x, event.mouse_region_y))

        elif event.type == 'LEFTMOUSE':
            bpy.types.SpaceNodeEditor.draw_handler_remove(self._handle, 'WINDOW')
            return {'FINISHED'}

        elif event.type in {'RIGHTMOUSE', 'ESC'}:
            bpy.types.SpaceNodeEditor.draw_handler_remove(self._handle, 'WINDOW')
            return {'CANCELLED'}

        return {'RUNNING_MODAL'}

    def invoke(self, context, event):
        if context.area.type == 'NODE_EDITOR':
            # the arguments we pass the the callback
            args = (self, context)
            # Add the region OpenGL drawing callback
            # draw in view space with 'POST_VIEW' and 'PRE_VIEW'
            self._handle = bpy.types.SpaceNodeEditor.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_PIXEL')

            self.mouse_path = []

            context.window_manager.modal_handler_add(self)
            return {'RUNNING_MODAL'}
        else:
            self.report({'WARNING'}, &quot;NODE_EDITOR not found, cannot run operator&quot;)
            return {'CANCELLED'}


def register():
    bpy.utils.register_class(ModalDrawOperator)

def unregister():
    bpy.utils.unregister_class(ModalDrawOperator)

if __name__ == &quot;__main__&quot;:
    register()

Documentation: https://docs.blender.org/api/current/gpu.html

Blender 2.7x

import bpy
import bgl
import blf
import math

# based on http://slabode.exofire.net/circle_draw.shtml
def draw_circle_2d(color, cx, cy, r, num_segments):
    theta = 2 * 3.1415926 / num_segments
    c = math.cos(theta) #precalculate the sine and cosine
    s = math.sin(theta)
    x = r # we start at angle = 0 
    y = 0
    bgl.glColor4f(*color)
    bgl.glBegin(bgl.GL_LINE_LOOP)
    for i in range (num_segments):
        bgl.glVertex2f(x + cx, y + cy) # output vertex 
        # apply the rotation matrix
        t = x
        x = c * x - s * y
        y = s * t + c * y
    bgl.glEnd()

def draw_line_2d(color, start, end):
    bgl.glColor4f(*color)
    bgl.glBegin(bgl.GL_LINES)
    bgl.glVertex2f(*start)
    bgl.glVertex2f(*end)
    bgl.glEnd()

def draw_typo_2d(color, text):
    font_id = 0  # XXX, need to find out how best to get this.
    # draw some text
    bgl.glColor4f(*color)
    blf.position(font_id, 20, 70, 0)
    blf.size(font_id, 20, 72)
    blf.draw(font_id, text)
    
def draw_callback_px(self, context):

    bgl.glPushAttrib(bgl.GL_ENABLE_BIT)
    # glPushAttrib is done to return everything to normal after drawing

    bgl.glLineStipple(10, 0x9999)
    bgl.glEnable(bgl.GL_LINE_STIPPLE)

    # 50% alpha, 2 pixel width line
    bgl.glEnable(bgl.GL_BLEND)
    bgl.glColor4f(1.0, 1.0, 1.0, 0.8)
    bgl.glLineWidth(5)

    bgl.glBegin(bgl.GL_LINE_STRIP)
    for x, y in self.mouse_path:
        bgl.glVertex2i(x, y)

    bgl.glEnd()
    bgl.glPopAttrib()
    
    bgl.glEnable(bgl.GL_BLEND)
    
    # ...api_current/bpy.types.Area.html?highlight=bpy.types.area
    header_height = context.area.regions[0].height # 26px
    width = context.area.width
    height = context.area.height - header_height
    
    p1_2d = (0,0)
    p2_2d = (width, height)
    p3_2d = (width, 0)
    p4_2d = (0, height)
    
    # green line
    bgl.glLineWidth(3)
    
    draw_line_2d((0.0, 1.0, 0.0, 0.8), p1_2d, p2_2d)
    
    # yellow line
    bgl.glLineWidth(5)
    draw_line_2d((1.0, 1.0, 0.0, 0.8), p3_2d, p4_2d) 
    
    # white circle
    bgl.glLineWidth(4)
    draw_circle_2d((1.0, 1.0, 1.0, 0.8), width/2, height/2, 70, 360)
    
    # red circle
    bgl.glLineWidth(5)
    draw_circle_2d((1.0, 0.0, 0.0, 0.4), width/2, height/2, 230, 5)
    
    # draw text
    draw_typo_2d((1.0, 1.0, 1.0, 1), &quot;Hello Word &quot; + str(len(self.mouse_path)))
    
    # restore opengl defaults
    bgl.glLineWidth(1)
    bgl.glDisable(bgl.GL_BLEND)
    bgl.glColor4f(0.0, 0.0, 0.0, 1.0)


class ModalDrawOperator(bpy.types.Operator):
    &quot;&quot;&quot;Draw a line with the mouse&quot;&quot;&quot;
    bl_idname = &quot;node.modal_operator&quot;
    bl_label = &quot;Simple Modal Node Editor Operator&quot;

    def modal(self, context, event):
        context.area.tag_redraw()

        if event.type == 'MOUSEMOVE':
            self.mouse_path.append((event.mouse_region_x, event.mouse_region_y))

        elif event.type == 'LEFTMOUSE':
            bpy.types.SpaceNodeEditor.draw_handler_remove(self._handle, 'WINDOW')
            return {'FINISHED'}

        elif event.type in {'RIGHTMOUSE', 'ESC'}:
            bpy.types.SpaceNodeEditor.draw_handler_remove(self._handle, 'WINDOW')
            return {'CANCELLED'}

        return {'RUNNING_MODAL'}

    def invoke(self, context, event):
        if context.area.type == 'NODE_EDITOR':
            # the arguments we pass the the callback
            args = (self, context)
            # Add the region OpenGL drawing callback
            # draw in view space with 'POST_VIEW' and 'PRE_VIEW'
            self._handle = bpy.types.SpaceNodeEditor.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_PIXEL')

            self.mouse_path = []

            context.window_manager.modal_handler_add(self)
            return {'RUNNING_MODAL'}
        else:
            self.report({'WARNING'}, &quot;NODE_EDITOR not found, cannot run operator&quot;)
            return {'CANCELLED'}


def register():
    bpy.utils.register_class(ModalDrawOperator)

def unregister():
    bpy.utils.unregister_class(ModalDrawOperator)

if __name__ == &quot;__main__&quot;:
    register()

Documentation: https://docs.blender.org/api/current/bgl.html#module-bgl