API Maker

The backend engine for the AI era

Database APIs

Multi-Tenant

One set of APIs for all your customers, each with a database of its own.

Mark an instance as a multi-tenant structure and point it to a tenants table. Each request names its tenant, and API Maker runs the same APIs, schemas, hooks and permissions on that tenant's database, whose connection string it reads from the tenants table. Customers share the servers and the APIs, not the databases.

See it live

Step through it, slow it down, or open the full canvas.

api-maker/features/multi-tenantLive
  • Request
  • Tenant lookup
  • Tenant data
Active tenants
2in the table
Pools open
0one per tenant
Tenant lookups
0rows read
Last status
–HTTP

The request names its tenant. crm::acme in the path: the instance crm, the tenant acme. The same API serves every customer.

How it works

  1. The request names its tenant.

    crm::acme in the path: the instance crm, the tenant acme. The same API serves every customer.

  2. API Maker reads the row of the tenant.

    It finds acme in the tenants table, with the find of the secret entry, and decrypts its connection string.

  3. The database of the tenant answers.

    A pool opens for crm::acme and the query runs on the database of Acme. Only the customers of Acme come back.

  4. Same API, another customer.

    globex comes in a header. Its row gives another connection string, another pool and another database.

  5. The next requests reuse the pool.

    Acme asks again. Its pool is open, so the query goes straight to its database, without reading the tenants table.

What you get

Isolation by design

Each customer has its own database, so there is no tenant_id filter to add to every query, or to forget.

One product to maintain

Schemas, hooks, settings, permissions and custom code are defined once and apply to every tenant.

Move a tenant any time

Copy its database, update its row, and call the multi-tenant-instance-updated system API: every server drops the pool of that tenant and clears the cache of the instance.

An example

A B2B SaaS

A CRM sold to companies keeps each company in its own PostgreSQL database. Small customers share a database server, a large one gets its own, and a regulated one keeps its database in its own data center. The product has one set of APIs, and onboarding a customer is creating its database and adding one row to the tenants table.

In the default secret: where the tenants aresecret.ts
import * as T from 'types';let Secret: T.ISecretType | any = {    // … common and your other keys    multiTenant: {        crm: <T.IMultiTenantSecretObj>{            instanceName: 'catalog',            databaseName: 'public',            collectionName: 'tenants',            usernameColumn: 'username',            connectionStringColumn: 'connection_string',            find: { active: true },        },    },};module.exports = Secret;

Then choose multiTenant.crm as "Connection String Multi Tenant" on the instance crm. For Oracle, add the columns of the username and password of each tenant, and of its privilege when it connects with one.

The same API, the database of each customerrequest
GET /api/gen/admin/crm::acme/crm/customersx-am-authorization: <API user token>GET /api/gen/admin/crm/crm/customersx-am-authorization: <API user token>x-am-tenant-username: globex

The first request runs on the database of Acme, the second on the database of Globex. The instance finds the tenant in its own tenants table, so the request names the tenant only.

Watch it

On the real admin panel, with real data.

Good to know

  • A user token made for a tenant is refused on every other tenant and on the structure database. Tokens from a users table outside the multi-tenant instance are not tied to a tenant: to keep a caller to its own tenant, compare g.req.params.tenantUsername with the caller in a pre hook.
  • A schema change has to run on every tenant database: plan your migrations for all of them.
  • Each API Maker server keeps a pool per active tenant. Size the connection limits of your database servers for it.

Questions

How do I set it up?

Keep your tenants in a table that has a schema in API Maker, with a username column and a connection string column. Add an entry for that table to the default secret. Then check "Is Multi Tenant Structure Instance" on the instance and choose that entry in "Connection String Multi Tenant".

How does a user get a token for its tenant?

Call the token API with the tenant header and the name of a DB token generator on the users table of the multi-tenant instance. The user is read from the database of that tenant, and the token works for that tenant only, also after a refresh.

How are new tenants picked up?

The first request of a new tenant reads its row and opens its pool. No restart and no deployment.