How to serialize results for API responses¶
Semolina query results come back as Row objects. This guide
shows how to convert them to dictionaries and JSON for use in API responses.
Convert a Row to a dictionary¶
Row implements the mapping protocol (__iter__ yields keys,
__getitem__ returns values), so dict() converts it directly:
from semolina import SemanticView, Metric, Dimension
class Sales(SemanticView, view="sales"):
revenue = Metric()
country = Dimension()
cursor = (
Sales.query()
.metrics(Sales.revenue)
.dimensions(Sales.country)
.execute()
)
row = cursor.fetchone_row()
data = dict(row)
# {"revenue": 1000, "country": "US"}
You can also use .items(), .keys(), and .values() for fine-grained access:
# Using row from above
row.keys() # dict_keys(["revenue", "country"])
row.values() # dict_values([1000, "US"])
row.items() # dict_items([("revenue", 1000), ("country", "US")])
Convert a Row to JSON¶
Combine dict() with json.dumps() for JSON serialization:
import json
from semolina import SemanticView, Metric, Dimension
class Sales(SemanticView, view="sales"):
revenue = Metric()
country = Dimension()
cursor = (
Sales.query()
.metrics(Sales.revenue)
.dimensions(Sales.country)
.execute()
)
row = cursor.fetchone_row()
json_str = json.dumps(dict(row))
# '{"revenue": 1000, "country": "US"}'
Serialize all rows at once¶
Use fetchall_rows() with a list comprehension:
cursor = (
Sales.query()
.metrics(Sales.revenue)
.dimensions(Sales.country)
.execute()
)
rows = cursor.fetchall_rows()
data = [dict(row) for row in rows]
# [{"revenue": 1000, "country": "US"}, {"revenue": 2000, "country": "CA"}]
This pattern works directly with web framework JSON responses – FastAPI’s
JSONResponse, for example, accepts a list of dictionaries.
Stream results in batches with fetchmany_rows¶
For large result sets, use fetchmany_rows() to
process rows in fixed-size batches without loading everything into memory:
cursor = (
Sales.query()
.metrics(Sales.revenue)
.dimensions(Sales.country)
.execute()
)
while True:
batch = cursor.fetchmany_rows(100)
if not batch:
break
chunk = [dict(row) for row in batch]
# Process or send chunk
This is useful when streaming results over HTTP (e.g. server-sent events or newline-delimited JSON) or when memory is constrained.
Select specific fields for the response¶
When you need a subset of fields in the response, use dictionary comprehension on each
Row:
rows = cursor.fetchall_rows()
data = [
{"country": row.country, "revenue": row.revenue}
for row in rows
]
Attribute access (row.country) and dict-style access (row["country"]) both work.
Use whichever fits your style – attribute access is more concise, dict-style access
allows dynamic field names.
See also¶
How to build queries – build queries and access results
How to use Semolina in a web API – use serialized results in FastAPI endpoints
How to filter queries – filter queries before serialization