{"id":17680711,"url":"https://github.com/elbywan/openapi-generator","last_synced_at":"2025-10-10T10:32:35.965Z","repository":{"id":47643737,"uuid":"245719786","full_name":"elbywan/openapi-generator","owner":"elbywan","description":"An OpenAPI document generator. ⚙️","archived":false,"fork":false,"pushed_at":"2021-08-19T22:54:56.000Z","size":382,"stargazers_count":22,"open_issues_count":4,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-05-12T21:46:10.558Z","etag":null,"topics":["amber-framework","crystal","openapi","swagger"],"latest_commit_sha":null,"homepage":"https://elbywan.github.io/openapi-generator/OpenAPI/Generator.html","language":"Crystal","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/elbywan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":"elbywan","custom":["https://www.paypal.me/elbywan"]}},"created_at":"2020-03-07T23:15:49.000Z","updated_at":"2024-05-30T13:38:01.000Z","dependencies_parsed_at":"2022-09-23T13:30:20.665Z","dependency_job_id":null,"html_url":"https://github.com/elbywan/openapi-generator","commit_stats":null,"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/elbywan/openapi-generator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elbywan%2Fopenapi-generator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elbywan%2Fopenapi-generator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elbywan%2Fopenapi-generator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elbywan%2Fopenapi-generator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elbywan","download_url":"https://codeload.github.com/elbywan/openapi-generator/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elbywan%2Fopenapi-generator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279003549,"owners_count":26083595,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-10T02:00:06.843Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["amber-framework","crystal","openapi","swagger"],"created_at":"2024-10-24T09:08:40.859Z","updated_at":"2025-10-10T10:32:35.938Z","avatar_url":"https://github.com/elbywan.png","language":"Crystal","funding_links":["https://github.com/sponsors/elbywan","https://www.paypal.me/elbywan"],"categories":[],"sub_categories":[],"readme":"# openapi-generator\n\n[![Build Status](https://travis-ci.org/elbywan/openapi-generator.svg?branch=master)](https://travis-ci.org/elbywan/openapi-generator)\n\n#### Generate an [OpenAPI v3 compliant](https://swagger.io/specification/) yaml file declaratively from your web framework code.\n\nThen serve it from a [Swagger UI](https://swagger.io/tools/swagger-ui/) instance.\n\n## Setup\n\n1. Add the dependency to your `shard.yml`:\n\n```yaml\ndependencies:\n  openapi-generator:\n    github: elbywan/openapi-generator\n```\n\n2. Run `shards install`\n\n3. Require the shard\n\n```crystal\nrequire \"openapi-generator\"\n```\n\n## API Documentation\n\n[**🔗 Full API documentation.**](https://elbywan.github.io/openapi-generator/OpenAPI/Generator.html)\n\n## Concepts\n\n### Declare Operations\n\n*From the [OpenAPI specification](https://swagger.io/docs/specification/paths-and-operations/).*\n\n\u003e In OpenAPI terms, paths are endpoints (resources), such as /users or /reports/summary/, that your API exposes, and operations are the HTTP methods used to manipulate these paths, such as GET, POST or DELETE.\n\n#### Method based (`Amber`, `Spider-gazelle`)\n\nUse the `@[OpenAPI]` annotation with a `yaml` encoded string argument.\n\n```crystal\nclass Controller\n  include OpenAPI::Generator::Controller\n\n  @[OpenAPI(\u003c\u003c-YAML\n    tags:\n      - tag\n    summary:\n      A brief summary.\n  YAML\n  )]\n  def handler\n    # …\n  end\nend\n```\n\n#### Class based (`Lucky`)\n\nUse the `open_api` macro with a `yaml` encoded string argument.\n\n```crystal\nclass Handler\n  include OpenAPI::Generator::Controller\n\n  open_api \u003c\u003c-YAML\n    tags:\n      - tag\n    summary:\n      A brief summary.\n  YAML\n\n  route do\n    # …\n  end\nend\n```\n\n#### Shorthands\n\nThe [`OpenAPI::Generator::Controller::Schema`](https://elbywan.github.io/openapi-generator/OpenAPI/Generator/Controller/Schema.html) class exposes shorthands for common OpenAPI yaml constructs.\n\n```crystal\n# Example:\n\nopen_api \u003c\u003c-YAML\n  tags:\n    - tag\n  summary:\n    A brief summary.\n  parameters:\n    #{Schema.qp name: \"id\", description: \"Filter by id.\", required: true}\n  responses:\n    200:\n      description: OK\n    #{Schema.error 404}\nYAML\n```\n\n- [`Schema.error(code, message = nil)`](https://elbywan.github.io/openapi-generator/OpenAPI/Generator/Controller/Schema.html#error(code,message=nil)-instance-method)\n- [`Schema.header(name, description, type = \"string\")`](https://elbywan.github.io/openapi-generator/OpenAPI/Generator/Controller/Schema.html#header(name,description,type=%22string%22)-instance-method)\n- [`Schema.header_param(name, description, *, required = false, type = \"string\")`](https://elbywan.github.io/openapi-generator/OpenAPI/Generator/Controller/Schema.html#header_param(name,description,*,required=false,type=%22string%22)-instance-method)\n- [`Schema.qp(name, description, *, required = false, type = \"string\")`](https://elbywan.github.io/openapi-generator/OpenAPI/Generator/Controller/Schema.html#qp(name,description,*,required=false,type=%22string%22)-instance-method)\n- [`Schema.ref(schema, *, content_type = \"application/json\")`](https://elbywan.github.io/openapi-generator/OpenAPI/Generator/Controller/Schema.html#ref(schema,*,content_type=%22application/json%22)-instance-method)\n- [`Schema.ref_array(schema, *, content_type = \"application/json\")`](https://elbywan.github.io/openapi-generator/OpenAPI/Generator/Controller/Schema.html#ref_array(schema,*,content_type=%22application/json%22)-instance-method)\n- [`Schema.string_array(*, content_type = \"application/json\")`](https://elbywan.github.io/openapi-generator/OpenAPI/Generator/Controller/Schema.html#string_array(*,content_type=%22application/json%22)-instance-method)\n\n### `openapi.yaml` Generation\n\n**After** declaring the operations, you can call `OpenAPI::Generator.generate` to generate the `openapi.yaml` file that will describe your server.\n\n**Note**: An [`OpenAPI::Generator::RoutesProvider::Base`](https://elbywan.github.io/openapi-generator/OpenAPI/Generator/RoutesProvider.html) implementation must be provided. A `RoutesProvider` is responsible from extracting the [server routes and mapping these routes with the declared operations](https://elbywan.github.io/openapi-generator/OpenAPI/Generator/RouteMapping.html) in order to produce the final openapi file.\n\n```crystal\nOpenAPI::Generator.generate(\n  provider: provider\n)\n```\n\nCurrently, the [Amber](https://amberframework.org/), [Lucky](https://luckyframework.org), [Spider-gazelle](https://spider-gazelle.net/) providers are included out of the box.\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eAmber\u003c/strong\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```crystal\n# Amber provider\nrequire \"openapi-generator/providers/amber\"\n\nOpenAPI::Generator.generate(\n  provider: OpenAPI::Generator::RoutesProvider::Amber.new\n)\n```\n\n\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eLucky\u003c/strong\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```crystal\n# Lucky provider\nrequire \"openapi-generator/providers/lucky\"\n\nOpenAPI::Generator.generate(\n  provider: OpenAPI::Generator::RoutesProvider::Lucky.new\n)\n```\n\n\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eSpider-gazelle\u003c/strong\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```crystal\n# Spider-gazelle provider\nrequire \"openapi-generator/providers/action-controller\"\n\nOpenAPI::Generator.generate(\n  provider: OpenAPI::Generator::RoutesProvider::ActionController.new\n)\n```\n\n\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eCustom\u003c/strong\u003e\u003c/summary\u003e\n\n```crystal\n# Or define your own…\nclass MockProvider \u003c OpenAPI::Generator::RoutesProvider::Base\n  def route_mappings : Array(OpenAPI::Generator::RouteMapping)\n    [\n      {\"get\", \"/{id}\", \"HelloController::index\", [\"id\"]},\n      {\"head\", \"/{id}\", \"HelloController::index\", [\"id\"]},\n      {\"options\", \"/{id}\", \"HelloController::index\", [\"id\"]},\n    ]\n  end\nend\n\nOpenAPI::Generator.generate(\n  provider: MockProvider.new\n)\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\nThe `.generate` method accepts additional options:\n\n```crystal\nOpenAPI::Generator.generate(\n  provider: provider,\n  options: {\n    # Customize output path\n    output: Path[Dir.current] / \"public\" / \"openapi.yaml\"\n  },\n  # Customize openapi.yaml base document fields\n  base_document: {\n    info: {\n        title:   \"My Server\",\n        version: \"v0.1\",\n      }\n  }\n)\n```\n\n### Schema Serialization\n\nAdding `extend OpenAPI::Generator::Serializable` to an existing class or struct will:\n- register the object as a reference making it useable anywhere in the openapi file\n- add a `.to_openapi_schema` method that will produce the associated `OpenAPI::Schema`\n\n```crystal\nclass Coordinates\n  extend OpenAPI::Generator::Serializable\n\n  def initialize(@lat, @long); end\n\n  property lat  : Int32\n  property long : Int32\nend\n\n# Produces an OpenAPI::Schema reference.\nputs Coordinates.to_openapi_schema.to_yaml\n# ---\n# allOf:\n# - $ref: '#/components/schemas/Coordinates'\n```\n\nAnd in the `openapi.yaml` file that gets generated, the `Coordinates` object is registered as a `/components/schemas/Coordinates` reference.\n\n```yaml\ncomponents:\n  schemas:\n    Coordinates:\n      required:\n      - lat\n      - long\n      type: object\n      properties:\n        lat:\n          type: integer\n        long:\n          type: integer\n```\n\n#### In practice\n\nThe object can now be referenced from the yaml declaration…\n\n```crystal\nclass Controller\n  include OpenAPI::Generator::Controller\n\n  @[OpenAPI(\u003c\u003c-YAML\n    requestBody:\n      required: true\n      content:\n        #{Schema.ref Coordinates}\n  YAML\n  )]\n  def method\n    # …\n  end\nend\n```\n\n…and it can be used by the schema inference (more on that later).\n\n```crystal\nclass Hello::Index \u003c Lucky::Action\n  include OpenAPI::Generator::Helpers::Lucky\n\n  disable_cookies\n  default_format :text\n\n  post \"/hello\" do\n    coordinates = body_as Coordinates?, description: \"Some coordinates.\"\n\n    plain_text \"Hello (#{coordinates.x}, #{coordinates.y})\"\n  end\nend\n```\n\n#### Customize fields\n\nUse the `@[OpenAPI::Field]` annotation to add properties to the fields.\n\n```crystal\nclass MyClass\n  extend OpenAPI::Generator::Serializable\n\n  # Ignore the field. It will not appear in the schema.\n  @[OpenAPI::Field(ignore: true)]\n  property ignored_field\n\n  # Enforce a type in the schema and disregard the crystal type.\n  @[OpenAPI::Field(type: String)]\n  property str_field : Int32\n\n  # Add an example that will appear in swagger for instance.\n  @[OpenAPI::Field(example: \"an example value\")]\n  property some_field : String\n\n  # Will not appear in POST / PUT/ PATCH requests body.\n  @[OpenAPI::Field(read_only: true)]\n  property read_only_field : String\n\n  # Will only appear in POST / PUT / PATCH requests body.\n  @[OpenAPI::Field(write_only: true)]\n  property write_only_field : String\nend\n```\n\n## Inference (Optional)\n\n`openapi-generator` can infer some schema properties from the code, removing the need to declare it with yaml.\n\n**Can be inferred:**\n- Request body\n- Response body\n- Query parameters\n\n**Supported Frameworks:**\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eAmber\u003c/strong\u003e\u003c/summary\u003e\n\n```crystal\nrequire \"openapi-generator/helpers/amber\"\n\n# …declare routes and operations… #\n\n# Before calling .generate you need to bootstrap the amber inference:\nOpenAPI::Generator::Helpers::Amber.bootstrap\n```\n\n#### Example\n\n```crystal\nrequire \"openapi-generator/helpers/amber\"\n\nclass Coordinates\n  include JSON::Serializable\n  extend OpenAPI::Generator::Serializable\n\n  def initialize(@x, @y); end\n\n  property x  : Int32\n  property y  : Int32\nend\n\nclass CoordinatesController \u003c Amber::Controller::Base\n  include ::OpenAPI::Generator::Controller\n  include ::OpenAPI::Generator::Helpers::Amber\n\n  @[OpenAPI(\n    \u003c\u003c-YAML\n      summary: Adds up a Coordinate object and a number.\n    YAML\n  )]\n  def add\n    # Infer query parameter.\n    add = query_params(\"add\", description: \"Add this number to the coordinates.\").to_i32\n    # Infer body as a Coordinate json payload.\n    coordinates = body_as(::Coordinates, description: \"Some coordinates\").not_nil!\n    coordinates.x += add\n    coordinates.y += add\n\n    # Infer responses.\n    respond_with 200, description: \"Returns a Coordinate object with the number added up.\" do\n      json coordinates, type: ::Coordinates\n      xml %(\u003ccoordinate x=\"#{coordinates.x}\" y=\"#{coordinates.y}\"\u003e\u003c/coordinate\u003e), type: String\n      text \"Coordinates (#{coordinates.x}, #{coordinates.y})\", type: String\n    end\n  end\nend\n```\n\n#### API\n\n`openapi-generator` overload existing or adds similar methods and macros to intercept calls and infer schema properties.\n\n*Query parameters*\n\n- `macro query_params(name, description, multiple = false, schema = nil, **args)`\n- `macro query_params?(name, description, multiple = false, schema = nil, **args)`\n\n*Body*\n\n- `macro body_as(type, description = nil, content_type = \"application/json\", constructor = :from_json)`\n\n*Responses*\n\n- `macro respond_with(code = 200, description = nil, headers = nil, links = nil, \u0026)`\n\n- `macro json(body, type = nil, schema = nil)`\n- `macro xml(body, type = nil, schema = nil)`\n- `macro txt(body, type = nil, schema = nil)`\n- `macro text(body, type = nil, schema = nil)`\n- `macro html(body, type = nil, schema = nil)`\n- `macro js(body, type = nil, schema = nil)`\n\n\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eLucky\u003c/strong\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```crystal\nrequire \"openapi-generator/helpers/lucky\"\n\n# …declare routes and operations… #\n\n# Before calling .generate you need to bootstrap the lucky inference:\nOpenAPI::Generator::Helpers::Lucky.bootstrap\n```\n\n**Important:** In your Actions, use `include OpenAPI::Generator::Helpers::Lucky` instead of `include OpenAPI::Generator::Controller`.\n\n#### Example\n\n```crystal\nrequire \"openapi-generator/helpers/lucky\"\n\nclass Coordinates\n  include JSON::Serializable\n  extend OpenAPI::Generator::Serializable\n\n  def initialize(@x, @y); end\n\n  property x  : Int32\n  property y  : Int32\nend\n\nclass Api::Coordinates::Create \u003c Lucky::Action\n  # `OpenAPI::Generator::Controller` is included alongside `OpenAPI::Generator::Helpers::Lucky`.\n  include OpenAPI::Generator::Helpers::Lucky\n\n  disable_cookies\n  default_format :json\n\n  # Infer query parameter.\n  param add : Int32, description: \"Add this number to the coordinates.\"\n\n  def action\n    # Infer body as a Coordinate json payload.\n    coordinates = body_as! ::Coordinates, description: \"Some coordinates\"\n    coordinates.x += add\n    coordinates.y += add\n\n    # Infer responses.\n    if json?\n      json coordinates, type: ::Coordinates\n    elsif  xml?\n      xml %(\u003ccoordinate x=\"#{coordinates.x}\" y=\"#{coordinates.y}\"\u003e\u003c/coordinate\u003e), schema: OpenAPI::Schema.new(type: \"string\")\n    elsif plain_text?\n      plain_text \"Coordinates (#{coordinates.x}, #{coordinates.y})\"\n    else\n      head 406\n    end\n  end\n\n  route { action }\nend\n```\n\n#### API\n\n`openapi-generator` overload existing or adds similar methods and macros to intercept calls and infer schema properties.\n\n*Query parameters*\n\n- `macro param(declaration, description = nil, schema = nil, **args)`\n\n*Body*\n\n- `macro body_as(type, description = nil, content_type = \"application/json\", constructor = :from_json)`\n- `macro body_as!(type, description = nil, content_type = \"application/json\", constructor = :from_json)`\n\n*Responses*\n\n- `macro json(body, status = 200, description = nil, type = nil, schema = nil, headers = nil, links = nil)`\n- `macro head(status, description = nil, headers = nil, links = nil)`\n- `macro xml(body, status = 200, description = nil, type = String, schema = nil, headers = nil, links = nil)`\n- `macro plain_text(body, status = 200, description = nil, type = String, schema = nil, headers = nil, links = nil)`\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eSpider-gazelle\u003c/strong\u003e\u003c/summary\u003e\n\n```crystal\nrequire \"openapi-generator/helpers/action-controller\"\n\n# …declare routes and operations… #\n\n# Before calling .generate you need to bootstrap the spider-gazelle inference:\nOpenAPI::Generator::Helpers::ActionController.bootstrap\n```\n\n#### Example\n\n```crystal\nrequire \"openapi-generator/helpers/action-controller\"\n\nclass Coordinates\n  include JSON::Serializable\n  extend OpenAPI::Generator::Serializable\n\n  def initialize(@x, @y); end\n\n  property x  : Int32\n  property y  : Int32\nend\n\nclass CoordinatesController \u003c ActionController::Controller::Base\n  include ::OpenAPI::Generator::Controller\n  include ::OpenAPI::Generator::Helpers::ActionController\n\n  @[OpenAPI(\n    \u003c\u003c-YAML\n      summary: Adds up a Coordinate object and a number.\n    YAML\n  )]\n  def add\n    # Infer query parameter.\n    add = param add : Int32, description: \"Add this number to the coordinates.\"\n    # Infer body as a Coordinate json payload.\n    coordinates = body_as(::Coordinates, description: \"Some coordinates\").not_nil!\n    coordinates.x += add\n    coordinates.y += add\n\n    # Infer responses.\n    respond_with 200, description: \"Returns a Coordinate object with the number added up.\" do\n      json coordinates, type: ::Coordinates\n      xml %(\u003ccoordinate x=\"#{coordinates.x}\" y=\"#{coordinates.y}\"\u003e\u003c/coordinate\u003e), type: String\n      text \"Coordinates (#{coordinates.x}, #{coordinates.y})\", type: String\n    end\n  end\nend\n```\n\n#### API\n\n`openapi-generator` overload existing or adds similar methods and macros to intercept calls and infer schema properties.\n\n*Query parameters*\n\n- `macro param(declaration, description, multiple = false, schema = nil, **args)`\n\n*Body*\n\n- `macro body_as(type, description = nil, content_type = \"application/json\", constructor = :from_json)`\n\n*Responses*\n\n- `macro respond_with(code = 200, description = nil, headers = nil, links = nil, \u0026)`\n  - `macro json(body, type = nil, schema = nil)`\n  - `macro xml(body, type = nil, schema = nil)`\n  - `macro txt(body, type = nil, schema = nil)`\n  - `macro text(body, type = nil, schema = nil)`\n  - `macro html(body, type = nil, schema = nil)`\n  - `macro js(body, type = nil, schema = nil)`\n\n-  `macro render(status_code = :ok, head = Nop, json = Nop, yaml = Nop, xml = Nop, html = Nop, text = Nop, binary = Nop, template = Nop, partial = Nop, layout = nil, description = nil, headers = nil, links = nil, type = nil, schema = nil)`\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n## Swagger UI\n\nThe method to serve a Swagger UI instance depends on which framework you are using.\n\n1. Setup a static file handler. (ex: [Lucky](https://luckyframework.org/guides/http-and-routing/http-handlers#built-in-handlers), [Amber](https://docs.amberframework.org/amber/guides/routing/pipelines))\n2. Download [the latest release archive](https://github.com/swagger-api/swagger-ui/releases)\n3. Move the `/dist` folder to your static file directory.\n4. Edit the `index.html` file and change the assets and `openapi.yaml` paths.\n\n## Contributing\n\n1. Fork it (\u003chttps://github.com/your-github-user/openapi-generator/fork\u003e)\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create a new Pull Request\n\n### Specs\n\nDo **not** run `crystal specs` without arguments. It will not compile due to global cookies and session class overrides issues between Amber \u0026 Lucky.\n\nTo test the project, have a look at the `.travis.yml` file which contains the right command to use:\n\n```sh\ncrystal spec ./spec/core \u0026\u0026 \\\ncrystal spec ./spec/amber \u0026\u0026 \\\ncrystal spec ./spec/lucky \u0026\u0026 \\\ncrystal spec ./spec/spider-gazelle\n```\n\n## Contributors\n\n- [elbywan](https://github.com/elbywan) - creator and maintainer\n- [dukeraphaelng](https://github.com/dukeraphaelng)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felbywan%2Fopenapi-generator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felbywan%2Fopenapi-generator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felbywan%2Fopenapi-generator/lists"}