API Maker

The backend engine for the AI era

Foundations

One installation, many services

Each service is an admin account: its own APIs, data, languages and Git, on one shared installation, with one sign-in for all.

Split the backend by business area. Identity, Catalog, Orders and Payments each get an admin account of the same API Maker. Each one has its own API path, database, code, secrets and repository. They share the servers, so there is one installation to run, not one stack per service. People sign in once at Identity, and every service checks that same token by itself.

See it live

Every call is drawn as it travels, in the color of its service. Slow it down, pause, go step by step, or open the full canvas and zoom in.

api-maker/architectures/microservices/service-per-accountLive
  • Identity · sign-in
  • Catalog
  • Orders
  • Payments
  • Shipping
  • Deploy · management API
  • Analytics
  • HTTPS and WSS up to Caddy
Services
4accounts
Installations
1to run
Sign-ins
1per person
Capacity
~11,002req/s, shared

Every service is an admin account. Identity, Catalog, Orders and Payments are admin accounts of one installation. Each answers under its own path.

How it works

The same steps as the diagram, in more detail.

  1. Every service is an admin account.

    Each service is an admin account of the same API Maker installation. Its API path is in every URL: /api/custom-api/orders/checkout, /api/schema/catalog/…. The account holds the custom APIs, hooks, events, schedulers, schemas and settings of that service, and nothing of the others. The apps call one address for all of them.

  2. Each service owns its data.

    The connection strings of a service live in the secret of its account. The other accounts never see them, so a service never reads the tables of another one: it asks that service through its API. Each service picks the database that suits it, among the 8 types API Maker supports, and changes it without touching the others.

  3. Each service picks its languages.

    The code of an account runs in sandbox containers made for that account and that language, with the packages it added. A heavy package of one service never lands in the sandboxes of another one, and a crash of its code stays in its own sandbox. The other services keep answering.

  4. People sign in once, at Identity.

    Identity is an admin account like the others. Its auth provider "people" is a custom one: its token generator checks the email and the password against the people table, then signs a short token with the private key kept in the secret of Identity. Only Identity holds that key, so only Identity can make tokens.

  5. The same token opens every service.

    Every other service has a custom auth provider with the same name. Its token validator checks the signature and the expiry with the public key of Identity, kept in the secret of that service, and returns the claims: the person and their roles, in g.req.auth.authCustom. The groups and hooks of each service then decide what that person may do there. No call goes to Identity, so if Identity is down, people who signed in keep working: only new sign-ins wait.

  6. Each service ships on its own.

    Each account has its own Git repository and branch. A push to the repository of Orders runs its CI, which calls the deployment hook of the Orders account. API Maker pulls that branch, runs the new migration scripts of Orders, and every server serves the new version at once. Catalog and Payments are not touched.

  7. A new service from one call.

    A script, or your own platform, calls the management API of the installation: CREATE_ADMIN_USER makes the account with its API path, saves its secret, pulls its Git repository and answers its deployment hook. Shipping is served by the installation at once, next to the others.

  8. One installation to run.

    All the services share the servers, Caddy and its certificates, API Maker DB and Redis, each item stored under the account it belongs to. You run, back up and update one installation instead of one stack per service. The root user sees the traffic of every service and every server, each account sees only its own.

The services

Each one is an admin account of the same installation, with its own path, language and database.

Identity

/identity

People, passwords and sign-in. The only service that makes tokens.

Code
TypeScript
Data
PostgreSQL
  • Token API of the provider "people"
  • Token generator, with the private key in its secret
  • Custom APIs to sign up and reset a password

Catalog

/catalog

Products, prices and pictures, read by every screen of the shop.

Code
TypeScript
Data
MongoDB
  • Schema APIs of products and prices
  • Custom API "search"
  • Token validator "people", with the public key

Orders

/orders

Carts and orders, from the first click to the last status.

Code
Go
Data
PostgreSQL
  • Custom API "checkout"
  • Schema APIs of orders
  • Pre hook: a person sees only their orders

Payments

/payments

Charges and refunds with the payment provider.

Code
C#
Data
SQL Server
  • Custom APIs "charge" and "refund"
  • The secret of the provider, in its own secret
  • Pre hook: refunds need the role "support"

Shipping

/shipping

Parcels and tracking. Added later with one call of the management API.

Code
Python
Data
MySQL
  • Custom API "book-parcel"
  • Scheduler "tracking-sync"

How they talk

  • RouteApps Every servicehttps://api.example.com/api/…/<account>/…One address for every service. The API path of the account picks the service.
  • TokenApps IdentityPOST /api/system-api/identity/tokenThe person signs in once. The answer is a token signed by Identity, valid 15 minutes.
  • TokenApps Every servicex-custom-authorizationThe same token goes to every service. Each one checks it with the public key of Identity.
  • DeployCI of Orders OrdersGET /api/sites/deploy/orders/ciThe deployment hook of one account pulls its branch. The other services are not touched.
  • API callRoot user InstallationCREATE_ADMIN_USERThe management API adds a service: account, secret, Git pull and deployment hook.

Why choose this pattern

Clear borders

Each service has its own APIs, schemas, users, roles and secrets. Nothing of one account shows in another.

A database per service

Each service keeps its data in the database that suits it. Only its own secret holds the connection.

The right language for each

TypeScript for one service, Go or C# for another. Each account runs its code in sandboxes of its own.

Deploy one, not all

Each service has its own repository and deployment hook. A release of Orders never redeploys Catalog.

A team per service

Each team owns the account of its service: its code, its data and its releases, on its own schedule.

Sign in once

People type their password at Identity only. Every service checks the token with a public key: no call to Identity.

Identity is no single point

If Identity is down, people who signed in keep working. Only new sign-ins wait.

One platform to pay for

The services share the servers. Quiet ones leave room for busy ones, instead of a half idle server each.

On video

Create API Maker Accounts from Your Own Code: The Management API for SaaS

One call from your sign-up system makes an admin account of API Maker: its Git repository pulled, its secret saved and a deployment hook, with nobody in the panel. Turn the API on, make an account, change its owner and its secret, remove it, read every refusal, and keep the token safe.

Every video of API Maker

Questions

What is shared between the services, and what is not?

Shared: the servers, Caddy and its certificates, API Maker DB and Redis. Separate: the API path, databases, schemas, custom APIs, hooks, events, schedulers, secrets, auth providers, API users, groups, sandboxes and Git repository of each account.

How is this different from the multi-project architecture?

It uses the same accounts. There, each account is a separate product. Here, the accounts are the services of one product: they call each other, share a sign-in and react to each other's events.

Can I use Google, Azure AD or AWS Cognito instead of my own Identity?

Yes. Add the same provider to every account, with the same client id. The app sends the token of that provider, and each service finds the person in its own table to get their groups.

How does a service know the roles of a person?

From the claims of the token: the validator returns them, and the code of the service reads them in g.req.auth.authCustom. A pre hook can narrow every query to the rows of that person.

Can each service have its own domain?

Yes. Add a site per domain to the Caddyfile, like catalog.example.com and orders.example.com, all passed to the same servers. The API path of the account stays in the URL.

Can a team work on its service without seeing the others?

Yes. Each admin account signs in to the panel on its own and sees only its own items. The root user manages the accounts and sees the whole installation.