{"id":13879758,"url":"https://github.com/machinio/solrb","last_synced_at":"2026-04-01T21:49:09.337Z","repository":{"id":32949751,"uuid":"142298728","full_name":"machinio/solrb","owner":"machinio","description":"Solr + Ruby + OOP + ❤️ = Solrb","archived":false,"fork":false,"pushed_at":"2025-06-11T07:52:26.000Z","size":316,"stargazers_count":39,"open_issues_count":1,"forks_count":1,"subscribers_count":7,"default_branch":"master","last_synced_at":"2026-03-28T00:22:53.413Z","etag":null,"topics":["object-oriented","oop","ruby","solr","solr-client"],"latest_commit_sha":null,"homepage":"","language":"Ruby","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/machinio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2018-07-25T12:44:49.000Z","updated_at":"2026-01-03T17:27:47.000Z","dependencies_parsed_at":"2022-08-07T18:30:29.246Z","dependency_job_id":"12240195-fde2-4186-ad82-af612b6348e6","html_url":"https://github.com/machinio/solrb","commit_stats":{"total_commits":170,"total_committers":9,"mean_commits":18.88888888888889,"dds":0.6588235294117647,"last_synced_commit":"bcfd564d3d466cb80079418c594218922d52918c"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/machinio/solrb","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/machinio%2Fsolrb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/machinio%2Fsolrb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/machinio%2Fsolrb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/machinio%2Fsolrb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/machinio","download_url":"https://codeload.github.com/machinio/solrb/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/machinio%2Fsolrb/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31292549,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T21:15:39.731Z","status":"ssl_error","status_checked_at":"2026-04-01T21:15:34.046Z","response_time":53,"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":["object-oriented","oop","ruby","solr","solr-client"],"created_at":"2024-08-06T08:02:31.827Z","updated_at":"2026-04-01T21:49:09.313Z","avatar_url":"https://github.com/machinio.png","language":"Ruby","readme":"[![CircleCI](https://circleci.com/gh/machinio/solrb/tree/master.svg?style=svg)](https://circleci.com/gh/machinio/solrb/tree/master)\n[![Maintainability](https://api.codeclimate.com/v1/badges/81e84c1c42f10f9da801/maintainability)](https://codeclimate.com/github/machinio/solrb/maintainability)\n[![Gem Version](https://badge.fury.io/rb/solrb.svg)](https://badge.fury.io/rb/solrb)\n\nSolrb\n======\n\nObject-Oriented approach to Solr in Ruby.\n\n## Table of contents\n\n* [Installation](#installation)\n* [Configuration](#configuration)\n  * [Setting Solr URL via environment variable](#setting-solr-url-via-environment-variable)\n  * [Single core configuration](#single-core-configuration)\n  * [Multiple core configuration](#multiple-core-configuration)\n  * [Solr Cloud](#solr-cloud)\n  * [Master-slave](#master-slave)\n    * [Gray list](#gray-list)\n  * [Basic Authentication](#basic-authentication)\n* [Indexing](#indexing)\n* [Querying](#querying)\n  * [Simple Query](#simple-query)\n  * [Querying multiple cores](#querying-multiple-cores)\n  * [Query with field boost](#query-with-field-boost)\n  * [Query with filtering](#query-with-filtering)\n  * [Query with sorting](#query-with-sorting)\n  * [Query with grouping](#query-with-grouping)\n  * [Query with facets](#query-with-facets)\n  * [Query with boosting functions](#query-with-boosting-functions)\n    * [Dictionary boosting function](#dictionary-boosting-function)\n  * [Field list](#field-list)\n* [Deleting documents](#deleting-documents)\n* [Active Support instrumentation](#active-support-instrumentation)\n* [Testing](#running-specs)\n* [Running specs](#running-specs)\n\n\n# Installation\n\nAdd `solrb` to your Gemfile:\n\n```ruby\ngem 'solrb'\n```\n\nIf you are going to use solrb with solr cloud:\n\n```ruby\ngem 'zk' # required for solrb solr-cloud integration\ngem 'solrb'\n```\n\n# Configuration\n\n## Setting Solr URL via environment variable\n\nThe simplest way to use Solrb is `SORL_URL` environment variable (that has a core name in it):\n\n```bash\n  ENV['SOLR_URL'] = 'http://localhost:8983/solr/demo'\n```\n\n\nYou can also use `Solr.configure` to specify the solr URL explicitly:\n\n```ruby\nSolr.configure do |config|\n  config.url = 'http://localhost:8983/solr/demo'\nend\n```\n\nIt's important to note that those fields that are not configured, will be passed as-is to solr.\n*So you only need to specify fields in configuration if you want Solrb to modify them at runtime*.\n\n## Single core configuration\n\nUse `Solr.configure` for an additional configuration:\n\n```ruby\nSolr.configure do |config|\n  config.url = 'http://localhost:8983/solr/demo'\n\n  # This gem uses faraday to make requests to Solr. You can specify additional faraday\n  # options here.\n  config.faraday_options = {}\n\n  # Core's URL is 'http://localhost:8983/solr/demo'\n  # Adding fields to work with\n  config.define_core do |f|\n    f.field :title, dynamic_field: :text\n    f.dynamic_field :text, solr_name: '*_text'\n  end\nend\n```\n\n## Multiple core configuration\n\n```ruby\nSolr.configure do |config|\n  config.url = 'http://localhost:8983/solr'\n\n  # Define a core with fields that will be used with Solr.\n  # Core URL is 'http://localhost:8983/solr/listings'\n  config.define_core(name: :listings) do |f|\n    # When a dynamic_field is present, the field name will be mapped to match the dynamic field.\n    # Here, \"title\" will be mapped to \"title_text\"\n    # You must define a dynamic field to be able to use the dynamic_field option\n    f.field :title, dynamic_field: :text\n\n    # When solr_name is present, the field name will be mapped to the solr_name at runtime\n    f.field :tags, solr_name: :tags_array\n\n    # define a dynamic field\n    f.dynamic_field :text, solr_name: '*_text'\n  end\n\n  # Pass `default: true` to use one core as a default.\n  # Core's URL is 'http://localhost:8983/solr/cars'\n  config.define_core(name: :cars, default: true) do |f|\n    f.field :manufacturer, solr_name: :manuf_s\n    f.field :model, solr_name: :model_s\n  end\nend\n```\n\nWarning: Solrb doesn't support fields with the same name. If you have two fields with the same name mapping\nto a single solr field,  you'll have to rename one of the fields.\n\n```ruby\n...\nconfig.define_core do |f|\n  ...\n  # Not allowed: Two fields with same name 'title'\n  f.field :title, solr_name: :article_title\n  f.field :title, solr_name: :page_title\nend\n...\n```\n\n## Solr Cloud\n\nTo enable solr cloud mode you must define a zookeeper url on solr config block.\nIn solr cloud mode you don't need to provide a solr url (`config.url` or `ENV['SOLR_URL']`).\nSolrb will watch the zookeeper state to receive up-to-date information about active solr nodes including the solr urls.\n\n\nYou can also specify the ACL credentials for Zookeeper. [More Information](https://lucene.apache.org/solr/guide/7_6/zookeeper-access-control.html#ZooKeeperAccessControl-AboutZooKeeperACLs)\n\n\n```ruby\nSolr.configure do |config|\n  config.zookeeper_urls = ['localhost:2181', 'localhost:2182', 'localhost:2183']\n  config.zookeeper_auth_user = 'zk_acl_user'\n  config.zookeeper_auth_password = 'zk_acl_password'\nend\n```\n\nIf you are using puma web server in clustered mode you must call `enable_solr_cloud!` on `on_worker_boot`\ncallback to make each puma worker connect with zookeeper.\n\n\n```ruby\non_worker_boot do\n  Solr.enable_solr_cloud!\nend\n```\n\n## Master-slave\n\nTo enable master-slave mode you must define a master url and slave url on solr config block.\nIn solr master-slave mode you don't need to provide a solr url (`config.url` or `ENV['SOLR_URL']`).\n\n```ruby\nSolr.configure do |config|\n  config.master_url = 'localhost:8983'\n  config.slave_url = 'localhost:8984'\n  # Disable select queries from master:\n  config.disable_read_from_master = true\n  # Specify Gray-list service\n  config.nodes_gray_list = Solr::MasterSlave::NodesGrayList::InMemory.new\nend\n```\n\nIf you are using puma web server in clustered mode you must call `enable_master_slave!` on `on_worker_boot`\ncallback to make each puma worker connect with zookeeper.\n\n\n```ruby\non_worker_boot do\n  Solr.enable_master_slave!\nend\n```\n\n### Gray list\n\nSolrb provides two built-in services:\n- `Solr::MasterSlave::NodesGrayList::Disabled` — Disabled service (default). Just does nothing.\n- `Solr::MasterSlave::NodesGrayList::InMemory` — In memory service. It stores failed URLs in an instance variable, so it's not shared across threads/servers. URLs will be marked as \"gray\" for 5 minutes, but if all URLs are gray, the policy will try to send requests to these URLs earlier.\n\nYou are able to implement your own services with corresponding API.\n\n## Force node URL\n\nYou can force solrb to use a specific node URL with the `with_node_url` method:\n\n```ruby\nSolr.with_node_url('http://localhost:9000') do\n  Solr::Query::Request.new(search_term: 'example', query_fields: query_fields).run\nend\n```\n\n\n## Basic Authentication\n\nBasic authentication is supported by solrb. You can enable it by providing `auth_user` and `auth_password`\non the config block.\n\n```ruby\nSolr.configure do |config|\n  config.auth_user = 'user'\n  config.auth_password = 'password'\nend\n```\n\n# Indexing\n\n```ruby\n# creates a single document and commits it to index\ndoc = Solr::Update::Commands::Add.new\ndoc.add_field(:id, 1)\ndoc.add_field(:name, 'Solrb!!!')\n\ncommit = Solr::Update::Commands::Commit.new\n\nrequest = Solr::Update::Request.new([doc, commit])\nrequest.run\n```\n\nYou can also create indexing document directly from attributes:\n\n```ruby\ndoc = Solr::Update::Commands::Add.new(doc: { id: 5, name: 'John' })\n```\n\n# Querying\n\n## Simple Query\n\n```ruby\n  query_field = Solr::Query::Request::QueryField.new(field: :name)\n\n  request = Solr::Query::Request.new(search_term: 'term', query_fields: [query_field])\n  request.run(page: 1, page_size: 10)\n```\n## Querying multiple cores\n\nFor multi-core configuration use `Solr.with_core` block:\n\n```ruby\nSolr.with_core(:models) do\n  Solr.delete_by_id(3242343)\n  Solr::Query::Request.new(search_term: 'term', query_fields: query_fields)\n  Solr::Update::Request.new([doc])\nend\n```\n\n## Query with field boost\n\n```ruby\n  query_fields = [\n    # Use boost_magnitude argument to apply boost to a specific field that you query\n    Solr::Query::Request::QueryField.new(field: :name, boost_magnitude: 16),\n    Solr::Query::Request::QueryField.new(field: :title)\n  ]\n  request = Solr::Query::Request.new(search_term: 'term', query_fields: query_fields)\n  request.run(page: 1, page_size: 10)\n```\n\n## Query with filtering\n\n```ruby\n  query_fields = [\n    Solr::Query::Request::QueryField.new(field: :name),\n    Solr::Query::Request::QueryField.new(field: :title)\n  ]\n  filters = [Solr::Query::Request::Filter.new(type: :equal, field: :title, value: 'A title')]\n  request = Solr::Query::Request.new(search_term: 'term', query_fields: query_fields, filters: filters)\n  request.run(page: 1, page_size: 10)\n```\n\n### AND and OR filters\n\n```ruby\n  usa_filter =\n    Solr::Query::Request::AndFilter.new(\n      Solr::Query::Request::Filter.new(type: :equal, field: :contry, value: 'USA'),\n      Solr::Query::Request::Filter.new(type: :equal, field: :region, value: 'Idaho')\n    )\n  canada_filter =\n    Solr::Query::Request::AndFilter.new(\n      Solr::Query::Request::Filter.new(type: :equal, field: :contry, value: 'Canada'),\n      Solr::Query::Request::Filter.new(type: :equal, field: :region, value: 'Alberta')\n    )\n\n  location_filters = Solr::Query::Request::OrFilter.new(usa_filter, canada_filter)\n  request = Solr::Query::Request.new(search_term: 'term', filters: location_filters)\n  request.run(page: 1, page_size: 10)\n```\n\n### Filtering by a Geofilt\n\n```ruby\n  spatial_point = Solr::SpatialPoint.new(lat: 40.0, lon: -120.0)\n\n  filters = [\n    Solr::Query::Request::Geofilt.new(field: :location, spatial_point: spatial_point, spatial_radius: 100)\n  ]\n\n  request = Solr::Query::Request.new(search_term: 'term', filters: filters)\n  request.run(page: 1, page_size: 10)\n```\n\n### Filtering by an Arbitrary Rectangle\n\n```ruby\n  spatial_rectangle = Solr::SpatialRectangle.new(\n    top_left: Solr::SpatialPoint.new(lat: 40.0, lon: -120.0),\n    bottom_right: Solr::SpatialPoint.new(lat: 30.0, lon: -110.0)\n  )\n\n  filters = [\n    Solr::Query::Request::Filter.new(type: :equal, field: :location, value: spatial_rectangle)\n  ]\n\n  request = Solr::Query::Request.new(search_term: 'term', filters: filters)\n  request.run(page: 1, page_size: 10)\n```\n\n## Query with sorting\n\n```ruby\n  query_fields = [\n    Solr::Query::Request::QueryField.new(field: :name),\n    Solr::Query::Request::QueryField.new(field: :title)\n  ]\n  sort_fields = [Solr::Query::Request::Sorting::Field.new(name: :name, direction: :asc)]\n  request = Solr::Query::Request.new(search_term: 'term', query_fields: query_fields)\n  request.sorting = Solr::Query::Request::Sorting.new(fields: sort_fields)\n  request.run(page: 1, page_size: 10)\n```\n\nDefault sorting logic is following: nulls last, not-nulls first.\n\n```ruby\n  query_fields = [\n    Solr::Query::Request::QueryField.new(field: :name)\n  ]\n  sort_fields = [\n    Solr::Query::Request::Sorting::Field.new(name: :is_featured, direction: :desc),\n    Solr::Query::Request::Sorting::Function.new(function: \"score desc\")\n  ]\n  request = Solr::Query::Request.new(search_term: 'term', query_fields: query_fields)\n  request.sorting = Solr::Query::Request::Sorting.new(fields: sort_fields)\n  request.run(page: 1, page_size: 10)\n```\n\n## Query with grouping\n\n```ruby\n  query_fields = [\n    Solr::Query::Request::QueryField.new(field: :name),\n    Solr::Query::Request::QueryField.new(field: :category)\n  ]\n  request = Solr::Query::Request.new(search_term: 'term', query_fields: query_fields)\n  request.grouping = Solr::Query::Request::Grouping.new(field: :category, limit: 10)\n  request.run(page: 1, page_size: 10)\n```\n\n## Query with facets\n\n```ruby\n  query_fields = [\n    Solr::Query::Request::QueryField.new(field: :name),\n    Solr::Query::Request::QueryField.new(field: :category)\n  ]\n  request = Solr::Query::Request.new(search_term: 'term', query_fields: query_fields)\n  request.facets = [Solr::Query::Request::Facet.new(type: :terms, field: :category, options: { limit: 10 })]\n  request.run(page: 1, page_size: 10)\n```\n\n## Query with boosting functions\n\n```ruby\n  query_fields = [\n    Solr::Query::Request::QueryField.new(field: :name),\n    Solr::Query::Request::QueryField.new(field: :category)\n  ]\n  request = Solr::Query::Request.new(search_term: 'term', query_fields: query_fields)\n  request.boosting = Solr::Query::Request::Boosting.new(\n    multiplicative_boost_functions: [Solr::Query::Request::Boosting::RankingFieldBoostFunction.new(field: :name)],\n    phrase_boosts: [Solr::Query::Request::Boosting::PhraseProximityBoost.new(field: :category, boost_magnitude: 4)]\n  )\n  request.run(page: 1, page_size: 10)\n```\n\n### Dictionary boosting function\n\nSometimes you want to do a dictionary-style boosting\nexample: given a hash (dictionary)\n\n```ruby\n{3025 =\u003e 2.0, 3024 =\u003e 1.5, 3023 =\u003e 1.2}\n```\n\nand a field of `category_id`\nthe resulting boosting function will be:\n```\nif(eq(category_id_it, 3025), 2.0, if(eq(category_id_it, 3024), 1.5, if(eq(category_id_it, 3023), 1.2, 1)))\n```\nnote that I added spaces for readability, real Solr query functions must always be w/out spaces\n\nExample of usage:\n\n```ruby\n  category_id_boosts = {3025 =\u003e 2.0, 3024 =\u003e 1.5, 3023 =\u003e 1.2}\n  request.boosting = Solr::Query::Request::Boosting.new(\n    multiplicative_boost_functions: [\n      Solr::Query::Request::Boosting::DictionaryBoostFunction.new(field: :category_id,\n        dictionary: category_id_boosts)\n    ]\n  )\n```\n\n## Query with shards.preference\n\n```ruby\n  shards_preference = Solr::Query::Request::ShardsPreference.new(\n    properties: [\n      Solr::Query::Request::ShardsPreferences::Property.new(name: 'replica.type', value: 'PULL')\n    ]\n  )\n  request = Solr::Query::Request.new(search_term: 'term', shards_preference: shards_preference)\n  request.run(page: 1, page_size: 10)\n```\n\n## Field list\n\n```ruby\n  query_fields = [\n    Solr::Query::Request::QueryField.new(field: :name),\n    Solr::Query::Request::QueryField.new(field: :category)\n  ]\n  request = Solr::Query::Request.new(search_term: 'term', query_fields: query_fields)\n  # Solr::Query::Request will return only :id field by default.\n  # Specify additional return fields (fl param) by setting the request field_list\n  request.field_list = [:name, :category]\n  request.run(page: 1, page_size: 10)\n```\n\n# Deleting documents\n\n```ruby\n# Delete by document ID\nSolr.delete_by_id(3242343)\nSolr.delete_by_id(3242343, commit: true)\n\n# Delete by query\nSolr.delete_by_query('*:*')\nSolr.delete_by_query('*:*', commit: true)\n\n# Delete by filters\nfilters = [Solr::Query::Request::Filter.new(type: :equal, field: :contry, value: 'Canada')]\ncommands = [Solr::Update::Commands::Delete.new(filters: filters)]\ncommands \u003c\u003c Solr::Update::Commands::Commit.new if commit?\nrequest = Solr::Update::Request.new(commands)\nrequest.run\n\n```\n\n# Active Support instrumentation\n\nThis gem publishes events via [Active Support Instrumentation](https://edgeguides.rubyonrails.org/active_support_instrumentation.html)\n\nTo subscribe to solrb events, you can add this code to initializer:\n\n```ruby\nActiveSupport::Notifications.subscribe('request.solrb')  do |*args|\n  event = ActiveSupport::Notifications::Event.new(*args)\n  if Logger::INFO == Rails.logger.level\n    Rails.logger.info(\"Solrb #{event.duration.round(1)}ms\")\n  elsif Logger::DEBUG == Rails.logger.level \u0026\u0026 Rails.env.development?\n    Pry::ColorPrinter.pp(event.payload)\n  end\nend\n```\n\n# Testing\n\nIt's possible to inspect the parameters for each solr query request done using Solrb by requiring\n`solr/testing` file in your test suite. The query parameters will be accessible by reading\n`Solr::Testing.last_solr_request` after each request.\n\n```ruby\nrequire 'solr/testing'\n\nRSpec.describe MyTest do\n  let(:query) { Solr::Query::Request.new(search_term: 'Solrb') }\n  it 'returns the last solr request params' do\n    query.run(page: 1, page_size: 10)\n    expect(Solr::Testing.last_solr_request.body[:params]).to eq({ ... })\n  end\nend\n```\n\n\n\n# Running specs\n\nThis project is setup to use CI to run all specs agains a real solr.\n\nIf you want to run it locally, you have several options:\n\n1. Use [CircleCI CLI](https://circleci.com/docs/2.0/local-cli/)\n2. Use Docker Compose (recommended)\n3. Manual setup with Docker commands\n\n## Running with Docker Compose\n\n### Single Node Solr\n\n```sh\n# Start Solr\ndocker-compose -f docker-compose.single.yml up -d\n\n# Wait for Solr to be healthy\ndocker-compose -f docker-compose.single.yml ps\n\n# Create test core\n# First copy the default configset to the correct location\ndocker exec -u 0 solrb-solr-1 sh -c \"mkdir -p /var/solr/data/configsets \u0026\u0026 cp -R /opt/solr/server/solr/configsets/_default /var/solr/data/configsets/ \u0026\u0026 chown -R solr:solr /var/solr/data/configsets\"\n\n# Then create the core\ncurl 'http://localhost:8983/solr/admin/cores?action=CREATE\u0026name=test-core\u0026configSet=_default'\n\n# Disable field guessing\ncurl http://localhost:8983/solr/test-core/config -d '{\"set-user-property\": {\"update.autoCreateFields\":\"false\"}}'\n\n# Run specs\nSOLR_URL=http://localhost:8983/solr/test-core rspec\n\n# Clean up\ndocker-compose -f docker-compose.single.yml down -v\n```\n\n## Manual Setup with Docker Commands\n\nIf you prefer more control or need to debug the setup, you can use the manual Docker commands:\n\n### Single Node Setup\n\n```sh\n# Start Solr\ndocker run -it --name test-solr -p 8983:8983/tcp -t solr:9.7.0-slim\n\n# Copy default configset to the correct location\ndocker exec -u 0 test-solr sh -c \"mkdir -p /var/solr/data/configsets \u0026\u0026 cp -R /opt/solr/server/solr/configsets/_default /var/solr/data/configsets/ \u0026\u0026 chown -R solr:solr /var/solr/data/configsets\"\n\n# Create a core\ncurl 'http://localhost:8983/solr/admin/cores?action=CREATE\u0026name=test-core\u0026configSet=_default'\n\n# Disable field guessing\ncurl http://localhost:8983/solr/test-core/config -d '{\"set-user-property\": {\"update.autoCreateFields\":\"false\"}}'\n\n# Run specs\nSOLR_URL=http://localhost:8983/solr/test-core rspec\n```\n","funding_links":[],"categories":["Ruby"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmachinio%2Fsolrb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmachinio%2Fsolrb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmachinio%2Fsolrb/lists"}