Make an API call with AutoLISP / VisualLISP

Make an API call with AutoLISP / VisualLISP

CodeDing
Advisor Advisor
13,311 Views
8 Replies
Message 1 of 9

Make an API call with AutoLISP / VisualLISP

CodeDing
Advisor
Advisor

Hello All,

As somebody who feels comfortable with lisp and has yet to gain such familiarity in a couple other languages, I have tried to really explore my limits with the language. With APIs being SO HUGE these days, I find myself more-and-more seeking ways to implement them at work, where feasible, to make my workflows easier (especially since we still use "vanilla" AutoCAD). While there may be more effective / efficient ways to call APIs with either this language or others, I wanted to get this out there for others who may want to get their feet in the door.

 

Here is one method for you to easily call out to an API that returns JSON data, convert that information to a List, then easily manipulate it. This method clearly requires that you have the ActiveX extended functions installed via (vl-load-com). Please note, that no error checking of the actual JSON data has been included. If an error is returned by your API, you will need to account for that.

 

If anyone has better or other methods for lisp, please don't hesitate to share..

(defun GetFromWeb (strUrl / webObj stat res errobj)
  ;Code posted by user: BazzaCAD, 2010/03/29, from site:
  ;http://opendcl.com/forum/index.php?topic=1244.0
  (vl-load-com)
  ;; Set up variables
  (setq webObj nil stat nil res nil)
  ;; Create a new reference to the WinHttp object
  (setq webObj (vlax-invoke-method (vlax-get-acad-object) 'GetInterfaceObject "WinHttp.WinHttpRequest.5.1"))
  ;; Fetch web page
  (vlax-invoke-method webObj 'Open "GET" strUrl :vlax-false)
  (setq errobj (vl-catch-all-apply 'vlax-invoke-method (list webObj 'Send)))
  (if (null (vl-catch-all-error-p errobj))
    (progn
      (setq stat (vlax-get-property webObj 'Status))
      (if (= stat 200)
        (progn
          (setq res (vlax-get-property webObj 'ResponseText));_ Return the response value // 'ResponseText
        )
        (princ (strcat "\n!!! WEB server error: " (vlax-get-property webObj 'StatusText) "!!!"))
      )
    );_ progn
    (princ (strcat "\n!!! WEB server error:\n" (vl-catch-all-error-message errobj)))
  )
  res 
);defun

(defun JSON->LIST (json / )
;json - string, as json data
;returns - list, converted from json
(if (eq 'STR (type json)) (read (vl-string-translate "[]{}:," "()()  " json)))
);defun

(defun LIST->PAIRS (lst / ret tmp)
;this function is recursive
;lst - list, the list returned by "JSON->LIST", or similar
;returns - dotted pair lists or, in the case of nested lists, lists similar to points found in entities (item val1 val2 ...)
(setq ret '())
(if (listp lst)
  (foreach i lst
    (if (listp i)
      (setq ret (cons (list (LIST->PAIRS i)) ret))
      (if (eq 0 (rem (length (member i lst)) 2))
        (setq ret (cons (cons i (if (listp (setq tmp (cadr (member i lst)))) (LIST->PAIRS tmp) tmp)) ret))
      );if
    );if
  );foreach
;else
  (setq ret "")
);if
(reverse ret)
);defun

(defun c:CALL ( / url data)
(vl-load-com)
;this url is open to everybody, it contains example data for anybody to test
(setq url "https://jsonplaceholder.typicode.com/users")
(if (and (setq data (GetFromWeb url))
	 (setq data (JSON->LIST data)))
  (progn
    ;now that we have a list, manipulate however you want
    ;Here is the entire list (all json data)
    (prompt "\n---Here is the JSON->LIST list---\n")
    (princ data)
    (prompt "\n---------------------------------\n")
    ;we can use our list manipulation functions to get specific items
    ;for example, we can loop through all users and print their names & emails
    (prompt "\n---Here are the names & emails---\n")
    (mapcar '(lambda (user) (princ (strcat "\nName: " (cadr (member "name" user)) " // Email: " (cadr (member "email" user))))) data)
    (prompt "\n---------------------------------\n")
    ;sometimes it may be more useful to have "assoc" pairs to work with
    (prompt "\n---Here is the LIST->PAIRS list--\n")
    (princ (setq data (LIST->PAIRS data)))
    (prompt "\n---------------------------------\n")
    (prompt "\nCALL Complete...")
  );progn
;else
  (prompt "\nError Getting / Converting JSON data.")
);if
(princ)
);defun

Best,

~DD

Accepted solutions (1)
13,312 Views
8 Replies
Replies (8)
Message 2 of 9

hak_vz
Advisor
Advisor

@CodeDing wrote:

... to make my workflows easier (especially since we still use "vanilla" AutoCAD)


Nice work!

It's not a sin to use "vanilla" or basic AutoCAD. In professional environment companies are using various CAD software or branch specialized products. Some of them are using latest versions, some are satisfied with older versions or use products from "different universe" (wont' name them now). Interoperability is usualy doubtfull and rises possibility to lose applications specific data. Bracing "vanilla" AutoCAD with various APIs can achieve good results, sometime even more efficiently than with specialised extensions or software.

I'm lately playing with connecting Autocad and local NodeJS console applications. JSON has definitively become a standard in data transfer and has put xml aside.

 

 

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
Message 3 of 9

CodeDing
Advisor
Advisor

UPDATE:

 

Please note, that the "LIST->PAIRS" function returns unexpected duplicate items. I coded it recently and will need to post an updated version when I get time! Those darn recursive loops!

 

Best,

~DD

0 Likes
Message 4 of 9

SeeMSixty7
Advisor
Advisor

Great step! JSON data is pretty sweet. Add in that some many Web Interfaces provide API's that provide JSON data. There will be lots of opportunity to use it.

 

The method I've used is pipe it into a database server and allow it's db system internal JSON processing to work, then pull the data from the database in a consistent manner. I like that you are pulling it directly and initiating the calls from AutoLISP. Very cool!

 

 

Message 5 of 9

CodeDing
Advisor
Advisor
Accepted solution

UPDATE:

 

Here is the updated "LIST->PAIRS" function. Now working as expected!

(defun LIST->PAIRS (lst / ret tmp tmp1 tmp2 cnt allLists)
;this function is recursive
;lst - list, the list returned by "JSON->LIST", or similar
;returns - dotted pair lists or, in the case of nested lists, lists similar to points found in entities (item val1 val2 ...)
(setq ret '() tmp1 '() tmp2 '() allLists t)
(if (listp lst)
  (progn
    (foreach i lst (if (not (listp i)) (setq allLists nil)))
    (if (not allLists)
      (progn
        (repeat (setq cnt (length lst))
          (setq tmp (nth (setq cnt (1- cnt)) lst))
          (if (listp tmp) (setq tmp (LIST->PAIRS tmp)))
          (if (= 1 (rem cnt 2))
            (setq tmp2 (cons tmp tmp2))
            (setq tmp1 (cons tmp tmp1))
          );if
        );repeat
        (setq ret (mapcar 'cons tmp1 tmp2))
      );progn
    ;else
      (setq ret (mapcar 'LIST->PAIRS lst))
    );if
  );progn
;else
  (setq ret "")
);if
ret
);defun

Best,

~DD

Message 6 of 9

CodeDing
Advisor
Advisor

@hak_vz  & @SeeMSixty7 ,

 

Thank you both for the input! It's great hearing other solutions that may not get addressed as much in the forums. They just need their spotlight for people to hear these ideas and begin implementing them!

 

Best,

~DD

0 Likes
Message 7 of 9

martti.halminen
Collaborator
Collaborator

An alternative way of doing things where convenient libraries don't exist for AutoLISP:

there are plenty of libraries for handling JSON, XML etc for Common Lisp, so we are doing this kind of stuff in a CL application and having that communicate with AutoLISP.

- Getting two separate Lisp programs to talk with each other is easy. Just write a list into a file and read it with the other one. (with another file as a flag to tell that writing the file is finished so it can be read.)

Message 8 of 9

Anonymous
Not applicable

From what was published here I wrote a set of improved functions. you can find them in https://github.com/diegomcas/autolisp-web-and-json-utils 

Message 9 of 9

muzamil_jillani
Community Visitor
Community Visitor

Hi,

have you found a way to connect autodesk and local node js application? I am a node js developer and have no experience with autodesk or autolisp, so if you could share some tips, thanks.

0 Likes