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:

Abstraction of database calls

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.

Comprises of cached functions

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.

Generic database level functionalities

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.

Do you need a new service?

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.

Steps to creating a new service

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.