Project Awesome project awesome

OpenAPI, OData, OpenRPC > openapi-generator

OpenAPI client code generator. [AGPL-3.0][51].

Package 14 stars GitHub
  • Common Lisp OpenAPI Generator (openapi-generator)

OpenAPI-generator is an api client system generator.

** Features

** Warning

  • This software is still ALPHA quality. The APIs will be likely to change.

  • Make sure to review the openapi specification file if it is from an untrusted source or environment file before using openapi-generator, especially before using the generated system. This is to mitigate potential security risks such as code injection. For security vulnerabilities, please contact the maintainer of the library.

** Quickstart Load openapi-generator from [[https://ultralisp.org/][Ultralisp]] via ql:quickload, or from local project folder via asdf:load-system

#+begin_src lisp (ql:quickload :openapi-generator) #+end_src

Then put this in the REPL:

#+begin_src lisp (openapi-generator:make-openapi-client "codeberg" :url "https://codeberg.org/swagger.v1.json" :server "https://codeberg.org/api/v1" :parse t) #+end_src

This creates a client system to access the [[https://codeberg.org/api/swagger][codeberg api]] in the projects folder within openapi-generator library and loads it (by default). Now you can use e.g.:

#+begin_src lisp (codeberg:repo-get "kilianmh" "openapi-generator") #+end_src

** Interface *** parse-openapi #+begin_src lisp parse-openapi (name &key url collection-id source-directory content (dereference dereference)) #+end_src

Parse an OpenAPI to a openapi class object. This might be useful for exploration of the API specification, or you can pass it to the make-openapi-client function.

#+begin_src lisp (openapi-generator:parse-openapi "codeberg" :url "https://codeberg.org/swagger.v1.json") #+end_src

**** name name of the openapi-file which is opened/created **** url url to a openapi specification file **** collection-id apis-guru-id from [[https://apis.guru/][apis.guru]] **** source-directory source-directory (name will be inserted from name parameter) **** content openapi spec file string **** dereference If set to true, pointers within openapi spec are dereferenced before parsing into openapi CLOS object. This improves discoverability for humans (and algorithms). Can be turned off for faster parsing. *** make-openapi-client #+begin_src lisp make-openapi-client (system-name &key (server server) (parse parse) (query query) (headers headers) (authorization authorization) (cookie cookie) (alias (list :operation-id)) (system-directory :temporary) (load-system t) openapi (api-name system-name) url source-directory collection-id content (dereference dereference)) #+end_src

**** parameters ***** input same as parse-openapi ***** openapi openapi-object ***** api-name Name of file in openapi-generator/data folder ***** system-directory Options:

  • pathname-object -> pathname pathname-object + system-name Keyword-options
  • :temporary -> default, (uiop:temporary-directory)
  • :library -> openapi-generator/projects ***** parse default: nil, alternative: t, :json.

#+begin_src lisp (openapi-generator:make-openapi-client "wikitionary-api" :url "https://github.com/shreyashag/openapi-specs/raw/main/thesaurus.yaml" :parse t) #+end_src #+begin_src lisp (wikitionary-api:find-word "oligopoly") #+end_src

***** server set default server variable in system (e.g. if server not/incorrect in spec file) ***** query set default query parameters ***** headers set default headers (e.g. for api-tokens that have to be supplied often) ***** authorization set default authorization value ***** cookie set default cookie value ***** Alias system exported functions: (multiple options possible):

  • :operation-id (param-cased operation-id) (default if there is are operation-id specified)
  • :summary (param-cased summary)
  • :description (param-case description)
  • :path (operation-type + path) (default if no operation-id specified) ***** load-system Load system after making it (default: t) ***** dereference If set to true (default), then the openapi spec is fully dereferenced before parsing into the CLOS object. This might be necessary to properly generate the system, e.g. if pointers are used for schemas. Can be turned off for faster system generation. **** examples ***** content The request body content can be supplied either as "raw" Json or as lisp data structures. Both are type-checked at run-time. Look at JZON documentation for the type mapping https://github.com/Zulu-Inuoe/jzon#type-mappings. You can supply the body-request to generated functions with the content keyword (default) or alternatively if existing in there is a title in the spec to the param-cased title keyword request-body id. Additionally for objects, the first level properties exist as function parameters.

#+begin_src lisp (openapi-generator:make-openapi-client "stacks" :url "https://raw.githubusercontent.com/hirosystems/stacks-blockchain-api/gh-pages/openapi.resolved.yaml") #+end_src #+begin_src lisp ;; make-openapi-client stacks as described in quickstart (stacks:call-read-only-function "SP187Y7NRSG3T9Z9WTSWNEN3XRV1YSJWS81C7JKV7" "imaginary-friends-zebras" "get-token-uri" :content "{ "sender": "STM9EQRAB3QAKF8NKTP15WJT7VHH4EWG3DJB4W29", "arguments": [ "0x0100000000000000000000000000000095" ] }") #+end_src #+begin_src lisp ;; make-openapi-client stacks as described in quickstart (stacks:call-read-only-function "SP187Y7NRSG3T9Z9WTSWNEN3XRV1YSJWS81C7JKV7" "imaginary-friends-zebras" "get-token-uri" :read-only-function-args ;; request-body title (only if existing in spec) (serapeum:dict "sender" "STM9EQRAB3QAKF8NKTP15WJT7VHH4EWG3DJB4W29" "arguments" (list "0x0100000000000000000000000000000095")) :parse t) #+end_src #+begin_src lisp ;; first level of the request-body objects can be supplied as lisp datastructures (stacks:call-read-only-function "SP187Y7NRSG3T9Z9WTSWNEN3XRV1YSJWS81C7JKV7" "imaginary-friends-zebras" "get-token-uri" :sender "STM9EQRAB3QAKF8NKTP15WJT7VHH4EWG3DJB4W29" :arguments (list "0x0100000000000000000000000000000095")) #+end_src #+begin_src lisp ;; first level of the request-body objects can be supplied as JSON strings (stacks:call-read-only-function "SP187Y7NRSG3T9Z9WTSWNEN3XRV1YSJWS81C7JKV7" "imaginary-friends-zebras" "get-token-uri" :sender "STM9EQRAB3QAKF8NKTP15WJT7VHH4EWG3DJB4W29" :arguments "["0x0100000000000000000000000000000095"]") #+end_src ***** header #+begin_src lisp ;; This example only works if you generate a valid apikey and insert it after Bearer ;; in the headers list (openapi-generator:make-openapi-client "openai" :url "https://raw.githubusercontent.com/openai/openai-openapi/master/openapi.yaml" :bearer "" :system-directory :temporary) #+end_src You have to first open an account and generate an api-key for using this api. If you supply value of authorization during client-creation, it will be saved directly in the file as variable. Beware and dont use this if in an untrusted environment. #+begin_src lisp ;; only working with valid API-KEY (openai:retrieve-engine "davinci") #+end_src You can also add add :authorization "Bearer " to each function call. This is equivalent to adding it to the headers. #+begin_src lisp (openai:list-engines :authorization "Bearer " ;; -> if not supplied during system generation ) #+end_src ***** collection-id #+begin_src lisp (openapi-generator:make-openapi-client "opendatasoft" :collection-id "opendatasoft.com" :parse nil) #+end_src This creates the api client for opendatasoft by accessing apis.guru forthe URL. Here an example query: #+begin_src lisp (opendatasoft:get-dataset "geonames-all-cities-with-a-population-1000") #+end_src ***** from openapi data folder Each time you load an api, a loadable json is stored in the openapi-generator/data folder. ELse you can put a file in the this folder manually. #+begin_src lisp ;; file with that name has to be present in the folder openapi-generator/data (openapi-generator:make-openapi-client "codeberg") #+end_src *** convert-to-openapi-3 #+begin_src lisp convert-to-openapi-3 (&key url content pathname (content-type "json")) #+end_src Conversion from Openapi 2.0 YAML/JSON to OpenAPI 3.0 JSON. #+begin_src lisp (openapi-generator:convert-to-openapi-3 :url "https://converter.swagger.io/api/openapi.json") #+end_src *** dereference Global variable that determines whether openapi spec is dereferenced before parsing into a CLOS object. Set to true by default. Can be overwritten in each call to parse-openapi / make-openapi-client. ** Possible Future Improvements

  • modularize the project (e.g. separate systems for parsing, function generation, system generation)
  • extensibility with custom classes
  • Auto-generation of request body classes for parsing them into CLOS objects
  • Response validation & access functions for response content
  • websocket support
  • integrate JSON-Schema to create an expanded API-Object
  • generate client from command line interface (CLI)
  • integration in workflows (CI/CD, etc.)
  • more regression tests
  • support multiple implementations
  • offline openapi-spec conversion
  • integrate other api standards: json:api, raml, postman collection, har, OData, GraphQL, gRPC

** License on generated code Generated code is intentionally not subject to this project license. Code generated shall be considered AS IS and owned by the user. There are no warranties--expressed or implied--for generated code. You can do what you wish with it, and once generated, the code is your responsibility and subject to the licensing terms that you deem appropriate.

** Call for collaboration Feel free to contribute by opening issues, pull request, feature requests etc. Your help is much appreciated.

** Copyright

(C) 2023 Kilian M. Haemmerle (kilian.haemmerle@protonmail.com)

** License

Licensed under the AGPLv3+ License.

Back to Common Lisp