{"id":38676558,"url":"https://github.com/antoine-dh/iop-rest-client-framework","last_synced_at":"2026-01-17T10:01:16.208Z","repository":{"id":289938470,"uuid":"861397688","full_name":"Antoine-dh/iop-rest-client-framework","owner":"Antoine-dh","description":null,"archived":false,"fork":false,"pushed_at":"2024-09-25T10:00:22.000Z","size":36,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-25T21:30:03.670Z","etag":null,"topics":["intersystems-iris"],"latest_commit_sha":null,"homepage":"https://openexchange.intersystems.com/package/IOP-REST-Client-Framework-1","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Antoine-dh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-09-22T19:27:14.000Z","updated_at":"2024-09-25T10:00:26.000Z","dependencies_parsed_at":"2025-04-25T21:40:31.116Z","dependency_job_id":null,"html_url":"https://github.com/Antoine-dh/iop-rest-client-framework","commit_stats":null,"previous_names":["antoine-dh/iop-rest-client-framework"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Antoine-dh/iop-rest-client-framework","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Antoine-dh%2Fiop-rest-client-framework","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Antoine-dh%2Fiop-rest-client-framework/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Antoine-dh%2Fiop-rest-client-framework/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Antoine-dh%2Fiop-rest-client-framework/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Antoine-dh","download_url":"https://codeload.github.com/Antoine-dh/iop-rest-client-framework/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Antoine-dh%2Fiop-rest-client-framework/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28505570,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T06:57:29.758Z","status":"ssl_error","status_checked_at":"2026-01-17T06:56:03.931Z","response_time":85,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["intersystems-iris"],"created_at":"2026-01-17T10:01:15.542Z","updated_at":"2026-01-17T10:01:16.198Z","avatar_url":"https://github.com/Antoine-dh.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# iop-rest-client-framework\n\nThis framework is a Proof of Concept that aims to simplify the integration of REST API clients inside IRIS Interoperability-enabled productions using Python ([IOP](https://github.com/grongierisc/interoperability-embedded-python)) with minimal code required\n\n## Features\n\n- Define your API client in an elegant and declarative syntax, inspired by libraries such as [Retrofit](https://square.github.io/retrofit/) or [FastAPI](https://fastapi.tiangolo.com/)\n- Full interoperability with either native IRIS [EnsLib.HTTP.OutboundAdapter](https://docs.intersystems.com/irislatest/csp/documatic/%25CSP.Documatic.cls?LIBRARY=ENSLIB\u0026CLASSNAME=EnsLib.HTTP.OutboundAdapter) or python [requests](https://requests.readthedocs.io/en/latest/) as your HTTP backend\n- Automatically generate your dataclass models and API methods by providing an [OpenAPI specification](https://swagger.io/specification/)\n- Generated code is made to be human-readable with minimal boilerplate code to be easily editable if adjustments needs to be made\n\n## Dependencies\n\n- [iris-pex-embedded-python](https://github.com/grongierisc/interoperability-embedded-python) (IOP)\n- [uplink](https://pypi.org/project/uplink/) - This project uses Uplink as a \"frontend\" for the API client definition\n- [datamodel-code-generator](https://pypi.org/project/datamodel-code-generator/) + [pydantic](https://pypi.org/project/pydantic/) - Used to generate Pydantic dataclasses from OpenAPI specs\n- [prance](https://pypi.org/project/prance/) - Used to parse and validate OpenAPI specs\n\n## Example\n\n### api\\.py\n\nThis is all the code you need to define your models and API endpoints\n\n```python\nfrom iop_rest.api import BaseClientREST\nfrom iop import Message\nfrom pydantic import BaseModel\nfrom uplink.arguments import *\nfrom uplink.commands import *\nfrom uplink.decorators import *\nfrom uplink import returns\n\n\n@dataclass(init=False)\nclass Pet(BaseModel, Message):\n    id: int\n    name: str\n\n\n@returns.json\n@headers({\n    \"Content-Type\": \"application/json\",\n    \"Accept\": \"application/json\",\n    \"Charset\": \"utf-8\",\n})\nclass PetstoreClient(BaseClientREST):\n\n    @json\n    @post('pet')\n    def add_pet(self, body: Body(type=Pet)) -\u003e Pet:\n        pass\n\n    @json\n    @get('pet/{petId}')\n    def get_pet_by_id(self, pet_id: Path(\"petId\", type=int)) -\u003e Pet:\n        pass\n```\n\n### bo\\.py\n\nSimple Business Operation that uses a EnsLib.HTTP.OutboundAdapter by default and passes it to our HTTP client\n\n```python\nfrom iop_rest.bo import BaseRESTOperation\nfrom api import PetstoreClient\n# from uplink import RequestsClient\n\nclass PetstoreOperation(BaseRESTOperation):\n    client: PetstoreClient\n\n    def init_client(self, adapter):\n        return PetstoreClient(adapter)\n        # Alternatively use python requests as the HTTP backend\n        # but lose the capabilities of the adapter\n        # return PetstoreClient(adapter, client=RequestsClient())\n```\n\n### bs\\.py\n\n```python\nfrom iop import BusinessService\nfrom iop_rest.messages import RESTRequest\nfrom api import Pet\n\nclass PetstoreService(BusinessService):\n    @staticmethod\n    def get_adapter_type():\n        return \"Ens.InboundAdapter\"\n\n    def on_process_input(self, message_input):\n        pet = Pet(\n            id=1,\n            name=\"Robert\",\n        )\n        response: Pet = self.send_request_sync('PetstoreOperation', RESTRequest.create('add_pet', pet))\n        # do something with response...\n        self.log_info(response.name)\n\n```\n\n## Demo\n\nThe demo can be found inside `src/python/demo/` and is a full implementation of the [Petstore OpenAPI spec](https://petstore3.swagger.io/) based on the above example\n\n### Presentation video\n\n[See the demo in action on Youtube](https://www.youtube.com/watch?v=MtK2eNVG0Gc)\n*(Please enable subtitles)*\n\n\u003c/br\u003e\n\n- The `bs.py` file is a simple BusinessService that is used to call periodically the Petstore BusinessOperation with a sample Pet object\n\n\u003c/br\u003e\n\n- The `bo.py` file is a simple Business Operation that uses a native IRIS EnsLib.HTTP.OutboundAdapter by default and passes it to our HTTP client\n  - You can alternatively choose to use python's requests library as the HTTP backend, however you will lose capabilities offered by IRIS's HTTP OutboundAdapter\n\n\u003c/br\u003e\n\n- The `generated/api.py` file contains the API definition generated by the iop_rest module, the generated code uses the [uplink](https://uplink.readthedocs.io/en/stable/) library at its core, and provides numerous decorators and type-checking abilities to allow for a very elegant and declarative syntax\n\n\u003c/br\u003e\n\n- The `generated/models.py` file contains the dataclass models generated by the iop_rest module, it uses pydantic's base class to allow for automatic json serialization and deserialization by the uplink library\n\n\u003c/br\u003e\n\n- The `settings.py` file contains the production definition and settings, see the [IOP documentation](https://github.com/grongierisc/interoperability-embedded-python?tab=readme-ov-file#61241-settingpy-file) for more information\n\n## Prerequisites\n\nMake sure you have [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) and [Docker](https://www.docker.com/products/docker-desktop) installed.\n\n## Installation\n\n### With Docker\n\nClone/git pull the repo into any local directory\n\n```sh\ngit clone https://github.com/Antoine-dh/iop-rest-client-framework\n```\n\nOpen the terminal in this directory and run:\n\n```sh\ndocker compose build\n```\n\nRun the IRIS container with your project:\n\n```sh\ndocker compose up -d\n```\n\n### With ZPM\n\n```objectscript\nzpm \"install iop-rest-client-framework\" \n```\n\n## Usage\n\n### Code generation\n\nIf running Docker, open a bash terminal inside the container\n```sh\ndocker compose exec iris bash\n```\n\notherwise, make sure the iop_rest module is installed or accessible by the python interpreter (or just `cd src/python` before running the command)\n\nTo run the code generation program, use the following command\n\n```sh\npython -m iop_rest \u003cAPIClassName\u003e \u003cpath/to/openapi_spec\u003e \u003cpath/to/output_folder\u003e\n```\n\nFor this demo:\n\n```sh\npython -m iop_rest PetstoreClient ./misc/petstore.openapi.yaml ./src/python/demo/generated/\n```\n\n## Issues and technical limitations\n\nKeep in mind this is a proof of concept, and not a finished product, do not use for production.\n\n- For now, only JSON APIs and UTF-8 charset is supported\n- Exceptions are not currently handled properly\n- Endpoints that returns JSON lists at the root of the HTTP body are not supported, this is due to a technical limitation with IOP messages that needs to be wrapped into a singular class, see [issue](https://github.com/grongierisc/interoperability-embedded-python/issues/25)\n- Models' schemas inside OpenAPI specs are expected to be defined in `#/components/schemas/`, and responses to be `$ref`s to thoses schemas\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantoine-dh%2Fiop-rest-client-framework","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fantoine-dh%2Fiop-rest-client-framework","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantoine-dh%2Fiop-rest-client-framework/lists"}