Skip to content

omnilab/rhea

Omnilab Rhea: a biochemical reaction by any of its four Rhea ids (18157, 18160) or its KEGG reaction (R00200) - its equation, status, balance, transport, sides and their participants, citations - its quartet and KEGG reaction as identifiers, its ChEBI participants, EC numbers, GO term, Reactome events and the reviewed UniProt proteins that catalyse it as related things; a search; through Rhea's SPARQL endpoint and REST search, no key.

Floor
Provider · Omnilab
Version
1.x
Conformance suite
not wired
Verified for real
Its README does not say
Licence
MIT
composer require omnilab/rhea:1.x-dev

Rhea (SIB), the expert-curated knowledgebase of biochemical reactions, through its SPARQL endpoint (https://sparql.rhea-db.org/sparql) and REST search (https://www.rhea-db.org/rhea), with UniProt's REST API for the proteins, for omnisense/omnilab: reactions by any of their four Rhea ids or their KEGG reaction - equation, status, sides and participants -, as entities, their ChEBI participants, EC numbers, GO term, Reactome events and reviewed UniProt proteins as related things; a search. No key.

Installation

composer require omnilab/rhea
use Omnilab\Rhea\RheaSourceFactory;

$rhea = (new RheaSourceFactory($httpClient))->create([
    'mailto' => 'support@glitchr.io',  // optional, asked by Rhea
    'enzymes' => 25,                   // optional: reviewed UniProt proteins entity() asks for; 0: none (one call less)
]);

Credentials

None: Rhea's SPARQL endpoint and REST search, and UniProt's REST API, take no key. Rhea asks programs to send a contact address in their User-Agent: give mailto.

Options

The factory's options, with the defaults it applies (RheaSourceFactory):

Option Type Default Required Effect
enzymes int 25 no how many reviewed UniProt proteins entity() asks for (a second call, to UniProt), kept in related('protein'); their number is the enzymes property; 0: none, and no call to UniProt
sparql_uri string https://sparql.rhea-db.org/sparql no Rhea's SPARQL endpoint, for entity()
uniprot_uri string https://rest.uniprot.org/ no UniProt's REST API, for the reviewed proteins (uniprotkb/search)
mailto ?string null no a contact address, sent in the User-Agent
user_agent ?string null no the whole User-Agent, in place of the one made from mailto
throttle float 0 no seconds left between two calls: Rhea publishes no rate
base_uri string https://www.rhea-db.org/ no Rhea's site, for the REST search (rhea?query=...)

Capabilities

capabilities() answers entity, search, cross_references; an operation it does not answer throws NotSupportedException before any call.

Capability Supported
entity yes any of a reaction's four Rhea ids (RHEA:18160, rhea:, its page) or its KEGG reaction (kegg.reaction:R00200): the master reaction answers; another base refused before any call; one SPARQL query, then one UniProt search
search yes Rhea's REST search (a name, a ChEBI id, an EC number, uniprot:P14618...), in Rhea's order, 100 a page at most, no total; a domain other than chemistry answers an empty page
series no
products no
occurrences no
datasets no
jobs no
open no
structure no
cross_references yes the three other ids of its quartet and its KEGG reaction; its ChEBI participants, EC numbers, GO term, Reactome events and proteins are related
forecast no
historical no
area no
station no
cloud_cover no

The scheme

A Rhea reaction is named in the core's rhea scheme by its number (18157, written RHEA:18157), read from RHEA:18157, rhea:18157 and its page rhea-db.org/rhea/18157. Rhea gives each reaction four ids: the master (direction undefined, =), left to right (=>), right to left, and both ways (<=>). Any of them gives the master reaction, which carries the three others as identifiers: the Merger knows the reaction by any of the four (KEGG links to the bidirectional one, 18160). A KEGG reaction (kegg.reaction:R00200) gives the Rhea reaction that names it.

Which APIs

Method Calls
entity() Rhea's SPARQL endpoint sparql.rhea-db.org/sparql, once: the master reaction (the id itself, or the master of which it is a direction; or the reaction whose quartet links the KEGG reaction), its fields, its quartet's cross-references, its sides' participants with their ChEBI accession, name and coefficient. Then UniProt's REST API rest.uniprot.org/uniprotkb/search, once (unless enzymes is 0): the reviewed proteins whose catalytic activity names any of the four ids, the first enzymes of them, and their number (X-Total-Results)
search() Rhea's REST search rhea-db.org/rhea?query=...&format=json&limit=...&offset=... - one more than the page asked, to know whether another follows (Rhea's count is the page's, not the total: no total)

The SPARQL query has no DISTINCT nor LIMIT in its sub-query: either took the endpoint over a minute on 2026-10-15, against about 3 s without. Rhea's REST "table" output (TSV) was not chosen for entity(): its text query matches other reactions too (18157 also finds RHEA:32167), and it does not give a reaction's directions.

What an entity holds

id (rhea:18157, the master), label (its equation), domain chemistry, kind reaction, url (its page: it answers a browser check to a program), and:

Key Value
status approved, preliminary, obsolete
balanced, transport booleans
left, right one per participant, in curated order: pyruvate (CHEBI:15361), 2 H(+) (CHEBI:15378); a polymer or a generic compound keeps Rhea's accession (POLYMER:..., GENERIC:...)
comment Rhea's comment, when there is one
references, pubmed how many citations; one PubMed id each
xref MetaCyc, EcoCyc, M-CSA ids (METACYC:PEPDEPHOS-RXN): bases the core has no scheme for
enzymes how many reviewed UniProt proteins catalyse it (UniProt's count; 111 for 18157)

identifiers: the three other ids of its quartet, its KEGG reaction. related: participant (ChEBI ids of both sides), enzyme (EC numbers), go (its GO molecular function), event (Reactome reactions: a species' instance, not the same thing), protein (the first enzymes reviewed UniProt accessions). The Collector follows none of the related things.

A search page's entity holds the equation, status, balance, transport, comment and the ChEBI participants of its HTML equation: entity() reads it whole.

The Collector: from KEGG into Rhea

KEGG's reaction R00200 carries rhea:18160; Rhea's 18157 carries kegg.reaction:R00200. With both configured, $collector->collect('kegg', 'R00200') follows R00200 into Rhea and merges (omnilab/kegg is not tested live: KEGG's API is for academic users). From Rhea, $collector->collect('rhea', '18157', 1, ['kegg']) follows the KEGG reaction.

Example

<?php

require __DIR__.'/vendor/autoload.php';

use Omnilab\Model\Scheme;
use Omnilab\Rhea\RheaSourceFactory;
use Omnilab\Source\Query;
use Symfony\Component\HttpClient\HttpClient;

$rhea = (new RheaSourceFactory(HttpClient::create()))->create(['mailto' => 'you@example.org', 'enzymes' => 3]);

$reaction = $rhea->entity('RHEA:18160');      // the bidirectional id: the master reaction answers
echo $reaction->id->display(), ' ', $reaction->label, "\n";
echo '  ', $reaction->value('status'), ', EC ', $reaction->related('enzyme')->value(Scheme::EC), ', KEGG ', $reaction->identifier(Scheme::KEGG_REACTION), ', ', $reaction->value('enzymes'), ' reviewed proteins: ', implode(', ', $reaction->related('protein')->values(Scheme::UNIPROT)), "\n";

foreach ($rhea->search(new Query('pyruvate kinase', limit: 3)) as $found) {
    echo '  ', $found->id->display(), '  ', $found->label, "\n";
}
RHEA:18157 pyruvate + ATP = phosphoenolpyruvate + ADP + H(+)
  approved, EC 2.7.1.40, KEGG R00200, 111 reviewed proteins: P30613, P14618, P0AD61
  RHEA:11364  pyruvate + ATP + H2O = phosphoenolpyruvate + AMP + phosphate + 2 H(+)
  RHEA:18157  pyruvate + ATP = phosphoenolpyruvate + ADP + H(+)
  RHEA:23052  L-seryl-[pyruvate dehydrogenase E1 alpha subunit] + ATP = O-phospho-L-seryl-[pyruvate dehydrogenase E1 alpha subunit] + ADP + H(+)

(as answered on 2026-10-27: three calls)

# config/packages/omnilab.yaml
omnilab:
    sources:
        rhea: { factory: rhea, options: { mailto: '%env(OMNILAB_MAILTO)%', enzymes: 25 } }

Errors

Every call goes through HttpSource: a 404 or a 410 (and a 204) is null - an empty page for a list -; a 429 is a RateLimitedException (retryAfter from Retry-After); a 5xx, a time-out or a host that does not answer an UnavailableException; any other 4xx a ProviderException with its status and what the service said; an answer that is not JSON a ProviderException, a web page answered for JSON an UnavailableException.

The three services' errors are mapped alike (the source's name rhea in each message). Before any call: an identifier of another base (NotSupportedException). An id SPARQL answers no row for is null; a text nothing matches an empty page.

Verified, and not

Against the real services on 2026-10-15: RHEA:18160 (the master 18157, its quartet, its five participants, EC 2.7.1.40, GO:0004743, R00200, R-HSA-71670, eleven citations, 111 reviewed proteins), the same reaction by R00200, an unknown id (no rows: null); the search for "pyruvate kinase" in two pages of three (six reactions), for a text nothing matches. The fixtures in Tests/Fixtures/ are those answers. Calls took 1 to 3 s (SPARQL), 0.3 to 2.3 s (UniProt), 0.3 to 1 s (search).

Again on 2026-10-27: RHEA:18160 giving the master 18157 and three of its 111 reviewed proteins, the search for "pyruvate kinase" (the example above).

Not verified: a rate limit (none published, none met); reactions with polymers, generic compounds or coefficients n (read as given); an obsolete reaction's replacement (not read).

Responsibility

This package is an independent, unofficial client: it is not affiliated with, endorsed by or sponsored by Rhea, the SIB Swiss Institute of Bioinformatics or UniProt. Rhea is under CC BY 4.0, credited and cited as its pages ask, its data for research, educational and informational purposes only (not for medical use); UniProt's answers are under CC BY 4.0 too, as the README's Terms of use says. Whoever runs the package is responsible for complying with them and for any use made of what it returns: see the README's Responsibility section.

Propose a change docs/index.md