I'm using Hono to build an API that fetches data from a Supabase database. My API is defined using an OpenAPI specification that includes response schemas that are defined using Zod.
The schemas are defined using Zod and then exported as a type. For example:
export const SampleSchema = z.object({
id: z.string().uuid(),
sampleName: z.string(),
otherProperty: z.string()
});
export type Sample = z.infer<typeof SampleSchema>;
In the OpenAPI definition, I use these schemas to define the response that will be sent:
export const getSampleRoute = createRoute({
method: 'get',
path: '/',
request: {
params: z.object({
id: z.string().uuid()
})
},
responses: {
200: {
content: {
'application/json': {
schema: SampleSchema
},
}
}
}
});
And finally, in the route's handler, I retrieve data from Supabase and re-map it to the type defined by the Sample Zod schema by matching each property line by line. I'm doing this because Supabase returns snake_case keys in the data object while I want the API to return camelCase keys. My question is, is this the most efficient way to re-map this data and change the key names? Is there a cleaner way to map data to the type, or am I fundamentally on the wrong track?
import { SampleSchema } from '@schemas/sample.schema';
app.openapi(getSampleRoute, async (c) => {
const { id:sampleId } = c.req.valid('param');
const supabase = getSupabase(c);
const dbQuery = supabase.from("samples").select('*').eq('id', sampleId).limit(1).single();
const { data, error } = await dbQuery;
if (error) {
throw error;
}
const sampleData:Sample = {
id: data.id,
sampleName: data.sample_name,
otherProperty: data.other_property
}
return c.json(sampleData, 200);
});
Edit: This question is not asking how to convert the object keys from snake_case to camelCase, as is described in How to convert snake_case to camelCase?. I'm looking to understand the most appropriate way to map data between the API data model and database schemas in this scenario. I.e., is it to simply rename the keys, or is there more to consider than just key names?
After discussing, we decided to continue using the hand-written mapping method and not write a function to automatically convert keys from snake case to camel case. We decided this because there were scenarios where we did not want to map API responses 1:1 with the database object. Manually mapping the data gives us better control in the response.