In this guide, you will learn how to create a new service in Formbricks codebase. To begin let’s define what we mean when we use the word Service
A service is an abstraction of database calls related to a specific model in the database which comprises of cached functions that can perform generic database level functionalities.
Let’s break down some of the jargon in that definition:
From our guide on How we Code at Formbricks, we mention that database calls should not be made directly from components or other places other than a service. This means that if you need to make a request to the database to fetch some data, let’s say “get the surveys of the current user in the current environment”, you would need a function in the surveys service like getSurveysByEnvironmentId
. It is also worth mentioning that we use Prisma as a database abstraction layer to perform database calls.
A service consists of multiple functions that can be easily reused in server actions. The other important part of this is that the output of a function in a service MUST be cached so we don’t have make unnecessary database calls for data that hasn’t changed. We will talk more about caching in services a bit later.
By generic we mean that if in the survey
service there is a function that only gets a survey and now you want a function to get both survey and all its responses, you should not create another function specifically for that. Instead use the getSurvey
function and then a getResponsesBySurveyId
function in the response
service to get this data. The functions need to be generic so that they can be reused for cases like this where you need to combine multiple cached functions to get what you need.
Firstly you must note that you almost won’t need to create a new service unless a new model was created. If you think that you need a new service or a new function in an existing service, first double check if you can combine one or two existing functions in an existing service to achieve what you want. If you still think that it doesn’t meet your need, please discuss with Matti first with your specific use-case to get the green light to create a new service or function in a service.
This is critical to us as a project because services are a key part of our project and we want to make them as organised, minimal, easy to change and use as possible. This is important to us as a team to move quickly and still keep a good and maintainable codebase.
Below is a break down on how to create a new service, if you ned to implement a function in an existing service you can jump to Step 3:
Step 1: Create the service folder in packages/lib
For the sake of this section, let’s say we just added a new model called ApiKey
, (note this model already exists)
model ApiKey {
id String @id @unique @default(cuid())
createdAt DateTime @default(now())
lastUsedAt DateTime?
label String?
hashedKey String @unique()
environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade)
environmentId String
}
Step 1a: The first thing you need to do is go to packages/lib
and create a new folder called apiKey
, note that this is the camel cased version of the Model name.
Step 1b: We need to create the types for our service once we have the model. To do that you go to packages/types
and create a file called apiKey.ts
.