My experience with Squid

QuantumSoft
7 min readJan 31, 2024

By Oleg Tarasov, JS Full Stack Developer at QuantumSoft

I recently had an opportunity to dive into the Squid.cloud. In this article, I would like to tell about my journey with Squid, from my initial impressions through the process and up to successful integration with a ChatRoom project. Additionally, I will share my thoughts about pros and cons of Squid and highlight the projects where it shines the brightest.

By leveraging my experience and expertise, combined with the power of Squid, I aim to provide valuable insights and recommendations for developers looking to optimize their backend development workflow. So, let’s get started!

About me and my background

Before we delve into Squid, let me introduce myself — I am a JS Full Stack developer. With over 5 years of commercial experience, I have worked on a wide range of projects, specializing in Node.js with Typescript and the Nest.js framework on the backend, and React, Angular, and Vue on the frontend. I was excited to explore Squid and see how it could enhance my development process and simplify backend tasks.

What is Squid

As a programmer, you’re likely familiar with the challenges of setting up and managing backend infrastructure for your applications. This is where Squid comes in and makes your life easier. Squid is a serverless middle-tier platform designed to simplify backend development and accelerate the delivery of projects.

At its core, Squid aims to replace the traditional backend setup by providing a unified platform that handles the complexities of connecting databases, APIs, and backend services to any frontend in a secure and scalable manner. With Squid, you can focus on building the frontend and delivering a seamless user experience, without getting bogged down by backend infrastructure management.

One of the key advantages of Squid is its ability to eliminate the need for complex backend configurations. It offers out-of-the-box integrations with popular databases like MongoDB, MySQL, CockroachDB, and PostgreSQL

Squid also provides seamless integration with Auth0, a widely-used authentication and authorization service. This makes it easy to implement robust user authentication and access control mechanisms, ensuring the security of your application without having to reinvent the wheel.

Another powerful feature of Squid is its support of server-side executables. With Squid, you can execute server-side functions that require access to secrets, perform queries not authorized for the current user. This gives you the flexibility to implement business logic, without compromising security or scalability.

Squid offers robust security. It provides access control, allowing you to define security rules that control access to different entities such as databases, backend functions, and APIs.

In the following sections, I will tell about my experience with Squid, discussing its implementation in a ChatRoom application and highlighting strengths and weaknesses of using Squid in different project scenarios.

What I was going to build

I decided to build a ChatRoom application. Here are the key features and requirements:

• Real-time messaging

• User authentication and authorization

• User, Rooms create/read/update/delete

• Scalability

If I were to develop a backend without relying on Squid, I would opt for combination of Nest.js, WebSockets, Docker, Nginx and a reliable database. However, with Squid, all these additional components become unnecessary.

Squid implementation

Here’s an overview of how Squid was integrated into the project:

1. Squid setup: The first step was to set up Squid by creating a Squid Cloud account. This provided access to the Squid dashboard, where I could configure the necessary resources and settings for the application.

2. Database integration: Squid offers seamless integration with popular databases like MongoDB, MySQL, CockroachDB, and PostgreSQL. I preferred to stay with default DB. I created five schemas and defined schema fields with types.

Schemas: Users, Rooms, UserRoom, Messages, Presence.
Here’s an example of my Users schema:

You can access db queries in React directly, I connected Squid to React.

export function SquidProvider({ children }: { children: React.ReactNode }): JSX.Element {
return (
<SquidContextProvider
options={{
appId: process.env.NEXT_PUBLIC_SQUID_APP_ID,
region: (process.env.NEXT_PUBLIC_SQUID_REGION,
environmentId: process.env.NEXT_PUBLIC_SQUID_ENVIRONMENT_ID
}}
>
{children}
</SquidContextProvider>
);
}

And subscribe to get Users

const usersQuerySubscription = collection('Users').query()
.sortBy('firstName')
.sortBy('lastName')
.snapshots()
.subscribe(usersDocuments => {
const users = usersDocuments.map(({ data }) => userDocumentToChatUser(data));
setUsers(users);
});

Or complex query to get messages with joined user in room in real-time!

const currentUserRoomQuery = collection('UserRoom')
.joinQuery('userRoom').eq('userId', currentUser.id);
const messagesQuery = collection('Messages').query().limit(50);
const userQuery = collection('Users').query();

const currentUserRoomMessagesUserQueryBuilder = currentUserRoomQuery
.join(messagesQuery, 'message', {
left: 'roomId',
right: 'roomId'
})
.join(userQuery, 'user', {
left: 'postedByUserId',
right: '__id'
})
.grouped()
.dereference();

Auth0 Integration

I configured necessary settings in Squid to authenticate users using Auth0, ensuring that only authorized users could access the chatroom, and read messages only in rooms where they are exist.[ММ1]

On the frontend, the top-level Auth0 initialization code looks like this.

We added SquidInitializer

<SquidContextProvider
options={{
appId: process.env.NEXT_PUBLIC_SQUID_APP_ID,
region: process.env.NEXT_PUBLIC_SQUID_REGION,
environmentId: process.env.NEXT_PUBLIC_SQUID_ENVIRONMENT_ID,
}}
>
<SquidInitializer>
{children}
</SquidInitializer>
</SquidContextProvider>




export function SquidInitializer({ children }) {
const { idToken } = useAuth();
const { setAuthIdToken } = useSquid();
useEffect(() => {
setAuthIdToken(idToken || undefined, process.env.NEXT_PUBLIC_SQUID_AUTH_INTEGRATION_ID);
}, [idToken, setAuthIdToken]);

return <Fragment>{children}</Fragment>;
}

The set AuthIdToken function is called [ММ2] with the idToken. This associates the authentication token with the Squid integration, allowing Squid to handle authentication and authorization for the whole application.

And you can check that user is authenticated:

return this.isAuthenticated();

Or get current user:

const auth = this.getUserAuth();
const collection = this.squid.collection('Users')
const user = await collection.doc(auth?.userId).snapshot()

Executables

Squid server-side executables provided a convenient way to options as create user, create room, update profile, add user to chat room. I will give you an example of the simplest one and the most complex one below.

@executable()
async createRoom({ name, icon }) {
const userId = this.getUserAuth()?.userId;

if (userId) {
const roomsCollection = this.squid.collection('Rooms')

const doc = await roomsCollection.doc()

await doc.insert({
created: new Date(),
name: name,
icon: icon,
ownerId: userId,
type: 'breakout'
})
return doc.data
}
}


@executable()
async addUsersToChatRoom({ userIds, roomId }): Promise<void> {
if (userIds?.length > 0 && roomId) {

const currentUserId = this.getUserAuth()?.userId
const room = await this.squid.collection<Room>('Rooms').doc(roomId).snapshot()

if (currentUserId && room && room.data.ownerId === currentUserId) {

const userRooms = await this.squid
.collection("userRoom")
.query()
.eq("roomId", roomId)
.in("userId", userIds)
.snapshot();

if (userRooms?.length === 0) {
const userRoomCollection = this.squid.collection('UserRoom')

await Promise.all(userIds.map((userId) => {
return userRoomCollection.doc().insert({
userId,
roomId
})
}))
}
}
}
}

const createRoomResult = await executeFunction('createRoom', {
name,
icon,
});

Security rules

Squid security rules feature played a crucial role in enforcing access restrictions within the application. I utilized Squid’s security rules to define granular access controls for the database collections and specific data within them.

For example:

  • Restricting access to the Rooms collection to allow read access to the Rooms collection only for authenticated users. This ensured that only users who were logged in and authenticated could view the list of available chat rooms
 
@secureCollection('Rooms', 'read')
secureRoomsRead(): boolean {
return this.isAuthenticated();

• To provide more complex access control, I leveraged Squid security rules to allow read access to specific messages only to users who were members of the chat room. This ensured that users could only access and view messages that were relevant to the chat rooms they were part of.

 
@secureCollection('Messages', 'read')
async secureMessageRead(context): Promise<boolean> {
const userId = this.getUserAuth()?.userId

if (userId) {
const roomIdConditions = context.getConditionsForField('roomId');
const inRoomIdCondition = roomIdConditions.find((c) => c.operator === "in");
const roomIds = inRoomIdCondition?.value;

if (!roomIds?.length) {
return false;
}
const userRooms = await this.squid
.collection("UserRoom")
.query()
.in("roomId", roomIds)
.eq("userId", userId)
.snapshot();
return userRooms.length === roomIds.length;
}
return false
}

Overview. Pros and cons

After working with Squid and implementing it in my ChatRoom project, I can confidently say that Squid is a powerful and efficient tool for backend development. Here are the key results and my observations:

Pros of Squid:

• Simplified Backend Development: Squid eliminates the need for complex backend setups and configurations. Developers can easily connect databases, APIs, and backend services to any frontend in a secure and scalable way.

• Rapid Development: Squid significantly speeds up the development process by providing ready-to-use integrations like database and authentication. This allows to focus more on building the core features of the application rather than spending time on infrastructure setup.

• Scalability and Security: Squid offers scalability and security tools such as Auth0, and security rules.

• Deployment in Squid is designed to be straightforward and out-of-the-box. Squid provides a serverless middle-tier platform that handles the deployment and scaling of your application’s backend resources automatically. This means that you don’t need to worry about provisioning and managing servers or configuring scaling settings.

Cons of Squid:

• Learning Curve: While Squid simplifies backend development, there is still a learning curve involved in understanding its concepts and how to use its features most efficiently. Developers who are new to Squid may need some time to familiarize themselves with its documentation and best practices.

  • Limited Customization: Squid provides a set of predefined integrations and functionalities, which may limit the level of customization you can achieve. If your project requires highly specific or unique backend requirements, Squid may not be the best fit.

Projects where Squid shines the brightest:

• Rapid Prototyping: Squid is an excellent choice for rapid prototyping or MVP development.

• Small to Medium-sized Applications: Squid is well-suited for small to medium-sized applications where speed of development and scalability are crucial. It provides a solid foundation for building backend functionality without the need for extensive infrastructure setup.

• Real-time Applications: Squid’s support for real-time messaging and its executable functions make it a great choice for building real-time applications like chatrooms, collaborative tools, or live streaming platforms.

The text above was prepared and accomplished by Oleg Tarasov. The opinions expressed here are the author’s own and do not necessarily represent the views of QuantumSoft.

--

--