Skip to content

Backend overview

Welcome to the backend section of the Quinck Dev Wiki! ⚡️ This section is dedicated to all things backend. Here you will find tips, tools, best practices and patterns for backend development.

API design

The API design is a crucial part of the backend development process. It’s the interface that the frontend and other services will use to interact with the backend. A well-designed API can make the difference between a smooth and a painful development process.

The most used standard for API design is the REST (Representational State Transfer) architecture. Read more about REST here.

Fundamental principles of API design:

  • Consistency: The API should be consistent in its design and naming conventions.
  • Predictability: The API should be predictable and easy to understand.
  • Flexibility: The API should be flexible and easy to extend.

We exclusively use the OpenAPI standard for API design. OpenAPI is a standard for defining RESTful APIs, and it’s widely used in the industry.

The workflow for backend development is always the following:

Define OpenAPI specification ➡️ Generate/Define models in code based on OpenAPI schemas ➡️ Implement the API ➡️ Deploy ➡️ Repeat

Guidelines

Rest APIs are about resources defined by paths and verbs.

  • Use paths to define on what resource to inreact

    • Each path in REST is a resource and must be named accordingly
    • Use noun instead of verbs or actions
    • The paths should only indicate the resource
    • Use single words as much as possible for each path part
      • Do not write: /organizations/:id/organizationMembers
      • Instead write: /organizations/:id/members
    • Avoid long names
    • Avoid over structured paths
    • Avoid repetitions
      • do not define different paths for different interaction modes
      • instead define one path and apply different verbs
  • Use verbs to define how to interact with a resource

    • Common verbs: POST to create, GET to retrieve, PATCH to update, PUT to replace, DELETE to remove/delete
    • i.e.
      • Having defined the resource path /pets the interaction could be defined with
        • POST to create a new pet
        • GET to retrieve/search the pets
      • Having defined the resource path /pets/:id (referring to a pet with id :id) the interaction could be defined with
        • GET to retrieve the pet
        • PUT to replace the pet information
        • PATCH to partially update the pet information
        • DELETE to delete the pet

Schemas

  • Never define inline schemas but instead define named schemas in components

    • do not

      paths:
      /users:
      get:
      summary: Get Users
      operationId: getUsers
      responses:
      "200":
      description: Successful response with users
      content:
      application/json:
      schema:
      type: array
      items:
      type: object
      properties:
      firstName:
      type: string
      example: "Mario"
      lastName:
      type: string
      example: "Rossi"
      email:
      type: string
      example: "example@example.com"
    • instead do

      paths:
      /users:
      get:
      summary: Get Users
      operationId: getUsers
      responses:
      "200":
      description: Successful response with users
      content:
      application/json:
      schema:
      type: array
      items:
      $ref: "#/components/schemas/User"
      components:
      schemas:
      User:
      type: object
      properties:
      firstName:
      type: string
      example: "Mario"
      lastName:
      type: string
      example: "Rossi"
      email:
      type: string
      example: "example@example.com"
  • Inline schemas are only allowed in case of paramaters used once

paths:
/users:
get:
summary: Get Users
operationId: getUsers
parameters:
- in: query
name: firstName
schema:
type: string
required: false
responses:
"200":
description: Successful response with users
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/User"
components:
schemas:
User:
type: object
properties:
firstName:
type: string
example: "Mario"
lastName:
type: string
example: "Rossi"
email:
type: string
example: "example@example.com"

Database design

The database design is another crucial part of the backend development process. It’s the storage that the backend will use to store and retrieve data. A well-designed database can help development process, performance and scalability.

There are two main types of databases: SQL and NoSQL. Read more about the differences here.

SQL vs NoSQL

We mostly use the following databases:

  • PostgreSQL (SQL)
  • MongoDB (NoSQL)

When to use SQL:

  • When you need to store structured data
  • When you need to perform complex queries or aggregations
  • Performance is a serious concern

When to use NoSQL:

  • When you need to store unstructured data (like JSON)
  • You can’t predict the structure of the data

Languages and frameworks

Unlike the frontend, the backend has a wide variety of languages and frameworks to choose from. This is because the code runs on the server, and the server can be any machine or environment.

The following are our languages of choice:

  • TypeScript: used for general purpose API development
  • Go: used for high-performance and concurrent services or APIs
  • Rust: special cases where performance and security is a serious concern

We developed our internal templates and framework for the three languages, to make the development process faster and more consistent.