KEPLIN Docs

The API builder

Creating app APIs as pipelines of steps — SQL, HTTP calls and scripts — with arguments, built-in testing and generated documentation.

Every Keplin API is a GraphQL operation of the app: a query that reads data or a mutation that writes it. The app's own screens, the reports, the workflows and the external systems all call the same APIs — what you define here is the application's only way in and out for data.

An API can have one of two natures:

Nature What it is Where it is covered
Pipeline A sequence of steps (SQL query, HTTP call, Script) that runs in order; the result of the last step is the response. This page
Table A single block bound to a table of the data model, which generates the read and write operations (get/add/update/delete) for you. The GraphQL API of the model

This page covers the builder itself: creating the API, defining arguments, assembling the pipeline, testing without saving and publishing.

Where APIs live

Inside an app, open the Code panel in the sidebar. The APIs section lists the existing APIs — you can organize them into folders with New folder — and each one opens as a workspace tab. The app also has an overview page with the complete list, the type and the state of each API, and the address they are served at.

The Code panel with the APIs section, and the app overview with the endpoint address.
The Code panel with the APIs section, and the app overview with the endpoint address.

Nota

At the top of the list you see the app's address: every operation is served at a single GraphQL endpoint, along the lines of /api/graphql/gestao-clientes. There is no URL per API — there is one GraphQL field per API.

Creating an API

  1. In the Code panel, on the APIs row, click the + button (New API). The New API button on the overview page takes you to the same place: the app workspace.
  2. Give it a Name. The name is the GraphQL field the clients will call, so follow the rule: letters, numbers and underscore, not starting with a number — for example getOportunidadesPorConta.
  3. Click Create API. The API is born as a draft and the builder opens next — that is where you decide the nature (SQL, HTTP, script blocks or table).

The New API dialog — just the name; the nature is defined later, in the builder.
The New API dialog — just the name; the nature is defined later, in the builder.

Dica

If the API is going to be a Table one, do not use prefixes like get or add in the name: the name is the BASE of the operations. On a table API called contas, getContas, addContas, updateContas and deleteContas are generated — according to the actions you enable.

The builder at a glance

The builder's header shows the name, a badge with the type (query, mutation or table) and the state (published or draft). On the right sit the commands that apply to the whole API:

Command What it does
Published Turns publishing on/off. A draft API is only visible to whoever builds; external clients do not see it.
Public (no session) Makes the API reachable without a session or API key — for the app's public screens. See Public APIs.
Save Saves the API as it is. Saving is always possible with a valid name and arguments — half-done work saves just the same.

Underneath, the work splits into three tabs:

Tab What for
Build Identification, arguments and the pipeline of steps.
Test Running the draft pipeline and trying the API out as a client.
Docs Ready-to-copy examples for calling the API from outside.

The builder of a pipeline API, on the Build tab.
The builder of a pipeline API, on the Build tab.

Identification

In the Identification section you define:

  • OperationQuery — reads data or Mutation — writes data. The choice is semantic and practical: mutations ask for confirmation before each test run, because they write for real.
  • Name — the GraphQL field. If the name is invalid, the builder warns: "Simple camelCase: letters, numbers and underscore, not starting with a number."

On a Table API there is no operation choice — the operations derive from the CRUD actions you enable on the Table block.

Arguments

The Arguments section declares the parameters that clients pass to the API. Each argument has:

Column What it is
Name The argument's identifier (letters, numbers, underscore; does not start with a number).
Type One of: String, Int, Float, Boolean, ID, JSON, Upload.
Req. Whether the client is required to send the argument.
Default Value used when the client sends nothing.
Test value Only for the Run button of the Test tab — it does not affect clients.

Inside the pipeline, arguments are available as :nome in the SQL and HTTP steps, and as input["args"]["nome"] in the Script step.

The Arguments section, with one argument declared and the test value filled in.
The Arguments section, with one argument declared and the test value filled in.

Dica

Write the pipeline first if you prefer: when you use :umNome in a step without having declared it, the banner "Used in the pipeline but not declared yet:" appears with one button per name — one click and the argument is created.

Files as an argument (Upload type)

An argument of type Upload receives a file. In that case the Default column gives way to the choice of storage: App default uses the default storage; alternatively pick one of the storages configured in the app settings (Storage section). That way, an API that receives invoices and another that receives photographs do not have to keep the files in the same place.

What happens when the API is called with a file:

  1. The file is saved in the chosen storage.
  2. In the pipeline, the argument stops being the raw file and becomes a reference with filename, mimeType, size and a token — that is what a Script step receives in input["args"]["nomeDoArg"].
  3. The app keeps the file's record, like any other file uploaded by the users.

For testing, the test value column turns into a file picker — choose one from your computer and click Run.

Atenção

If the app has several storages and none marked as default, a call with an Upload and no storage chosen is refused — the platform does not pick one for you.

From the outside, the file is sent as a multipart variable of the GraphQL request (the standard GraphQL upload format); inside the platform, the screens handle that for you.

The pipeline

The Pipeline section is where the API takes shape. The rules are simple:

  • The steps run in order; the result of the last one is the API's response.
  • Each step (from the second on) can receive the previous one's result — the "receives the result of step N" badge reminds you.
  • In the SQL and HTTP steps, the previous result sits in :prev, and it accepts paths: :prev.id, :prev.0.id.
  • You add steps with the SQL query, HTTP call and Script buttons; the Table button converts the API to the table nature (and does not combine with the other blocks).

While there are no blocks, the section suggests the path: the default is a Table of the model; alternatively, a pipeline is built with the steps described next.

SQL query step

  1. Choose the Datasource — one of the databases registered in the app. With no datasources, the step shows the shortcut to create the first.
  2. Write the query in the editor. Type : to autocomplete arguments; the editor knows the tables and columns of the chosen datasource and suggests them as you type.
  3. If the query returns a single row by nature (a total, one record per key), switch on Return only the first row — the response goes from list to object.

The values of :argumento and :prev always go parameterized to the database — never concatenated into the query text. That protects you from SQL injection with no effort at all.

A SQL query step with the datasource chosen and the query editor.
A SQL query step with the datasource chosen and the query editor.

Dica

From the second step on, :prev also shows up in the autocomplete — after a test run, the suggestions include the real paths of the previous result (e.g. :prev.0.id). To transform large lists between steps, put a code step in the middle.

HTTP call step

For talking to external services:

  1. Choose the Method (GET, POST, PUT, PATCH or DELETE) and fill in the URL — e.g. https://api.exemplo.pt/clientes/:clienteId.
  2. Add Headers with Add header — for example Authorization with the value Bearer :token.
  3. On the methods with a body, fill in the Body; switch on Send as JSON for the body to go with the correct content type.

:nomeDoArg and :prev are substituted in the URL, headers and body.

Script step

The Script step runs a script of the app — the same logic you can run by hand or on a schedule, now as part of an API:

  1. Choose the Script from the list (the list shows each one's name and language; only active scripts appear). With no scripts, the step shows the shortcut to create the first.
  2. Decide whether the step Receives the result of the previous step — on the first step of the pipeline this switch does not apply.

The contract with the script is clear: the API's arguments arrive in input["args"], the previous step's result in input["prev"], and the value returned by the main(input) function moves on to the next step (or is the response, if it is the last step).

Atenção

If the chosen script has a high time limit, the builder warns you — the API's clients wait that long in the worst case. Pipelines with an interactive response deserve fast scripts.

Reordering and removing steps

Each step card has arrows to Move up / Move down and a bin to Remove step. Changing the pipeline invalidates the last test's result — hit Run again to see fresh results.

Testing without saving

The Test tab has two tools. The first, Test the pipeline (draft), runs the pipeline EXACTLY AS IT IS in the builder, without saving:

  1. Fill in the arguments' test values (in the Arguments section).
  2. Click Run. On a mutation, the builder asks for confirmation — "Run the mutation now?" — because the test runs for real against the datasources and a mutation makes true writes.
  3. Read the result: the Success/Error badge with the duration, the full Response (very large responses appear truncated), and with more than one step, the Result per step — each step with an ok/erro badge, so you see exactly where the pipeline broke.
  4. If the steps wrote logs (a script that prints, for example), they appear in the Logs block.

The Test the pipeline (draft) panel, with the Run button — no runs in this session yet.
The Test the pipeline (draft) panel, with the Run button — no runs in this session yet.

The return type

The return type is the shape of the response in the GraphQL schema — it is what tells clients which fields they can select. The builder infers it from the real result: after each run see the Return type (inferred) block. If it differs from what is stored, the warning "This return type is not saved yet" appears with the Save return type button — and an amber dot on the Save button reminds you of the same.

Nota

With no run at all, the tab shows the Current return type (the stored one). Run the pipeline to infer the return type from the real result — especially after changing the SQL or the script.

Trying it out as a client

The second tool of the Test tab is an interactive GraphQL environment pointed at the app's endpoint — you write operations, get schema autocomplete and see the responses. As you are authenticated, drafts show up too. The Open in window button opens the same environment in a browser tab. The details sit in the next chapter, in The GraphQL API of the model.

Publishing

The Published switch controls who sees the API:

  • Draft — only whoever builds sees it (in authenticated sessions, the operations appear marked as draft). External clients and app users do not see it, not even by listing the schema.
  • Published — it enters the schema for every client with access.

To save as published, the API has to be complete. The builder shows the blockers next to the header — for example "Step 2: the SQL is empty." or, on a table API, "To save as published, choose the table and at least one CRUD action." These warnings never prevent Save as a draft: they only prevent publishing.

Nota

Deleting a published API takes the operation out of the schema immediately — the clients that called it start receiving errors. The platform warns you first: the deletion is permanent.

The generated documentation (Docs tab)

The Docs tab answers the question "how do I call this from outside?". It is generated from the saved version — save the API first — and shows:

  • The endpoint (POST /api/graphql/gestao-clientes), with a copy button.
  • The authentication note: the x-api-key header is required for external clients — keys are generated in API Keys. On the Test tab (internal session) it is not needed.
  • One entry per operation of the API with four ready-to-copy blocks: GraphQL query, Variables, curl and JavaScript (fetch). On a table API, every active operation appears (get, count, add, update, delete).

The Docs tab, with the endpoint and the ready-to-copy examples of the getContactos operation.
The Docs tab, with the endpoint and the ready-to-copy examples of the getContactos operation.

Why doesn't…?

  • Why can't I publish? The pipeline is not complete yet — read the blockers next to the header: each missing step is listed with the number and the reason.
  • Why does Run ask me for confirmation? The API is a mutation: the test makes true writes. Make sure you are pointing at test data.
  • Why don't I see my new API in the GraphQL test environment? Save first — the environment answers about the saved version. Saved drafts appear (you are authenticated); for external clients, only when you publish.
  • Why can't I add a SQL step to a Table API? A Table API does not combine with other blocks — remove the Table block first (or the steps, the other way around).