# WAPPI documentation (full) > WAPPI is a TypeScript microservice API framework for building functional, versioned APIs that run serverless or as a monolith, with testing, logging, Prisma support and frontend type syncing (wappi-fe) built in. npm package: `wappi` (https://www.npmjs.com/package/wappi). Source: https://gitlab.com/wappi-repo/wappi. Source: https://www.wappi.dev/ (index: https://www.wappi.dev/llms.txt) --- URL: https://www.wappi.dev/getting-started Markdown: https://www.wappi.dev/getting-started.md # Create a full API in 2 minutes ## 1. Create Your First Project ```bash npx wappi init ``` Follow the prompts ## 2. Start Development Server ```bash npx wappi run ``` Will output something like this: ```typescript ⨁ WAPPI 2.0.13 ✓ Compiled 27 endpoints in 263ms ✓ Ready in 2.3s ✓ Watching all changes in the API folder ... -.- .. .--. ✓ Compiled and Ready ... -.- .. .--. Environment : localhost Show Logs : true Auth Cron : 1 day Auth Start : Fri Jun 27 2025 11:53:40 GMT+1000 (Australian Eastern Standard Time) WAPPI : http://localhost:3030 .-- .- .--. .--. .. ↻ Compiling changes ✓ Compiled changes in 461ms ✓ Types compiled and synced to: ["/Users/Sites/my_app/src/API"] ``` Your API will be available at the port you specified in the setup [http://localhost:3030](http://localhost:3030/healthcheck) ## 3. Create Your First Endpoint ```bash npx wappi create ``` This creates a new endpoint template. ## 4. Test Your Endpoint ```bash npx wappi test Core_Login_1_0_0 ``` This will run a test on the code in the Core Login endpoint. Change the name of the endpoint to test another endpoint. --- URL: https://www.wappi.dev/cli-commands Markdown: https://www.wappi.dev/cli-commands.md # CLI Commands Creates a new functional endpoint using all the correct templates. #### Command ```bash wappi create ``` #### Shorthand Command ```bash wappi c ``` #### Example ```bash wappi c ``` Creates the build for running locally and testing the build #### Command ```bash wappi build ``` #### Shorthand Command ```bash wappi b ``` #### Example ```bash wappi b ``` Deletes a current functional endpoint version and namespace #### Command ```bash wappi delete ``` #### Shorthand Command ```bash wappi d ``` #### Example ```bash wappi d ``` Show the cli commands menu #### Command ```bash wappi help ``` #### Shorthand Command ```bash wappi h ``` #### Example ```bash wappi h ``` Initializes WAPPI (required for all the other commands to work) #### Command ```bash wappi init ``` #### Shorthand Command ```bash wappi i ``` #### Example ```bash wappi i ``` Runs eslint over code. Based off the .eslintrc.json #### Command ```bash wappi lint ``` #### Shorthand Command ```bash wappi l ``` #### Example ```bash wappi l ``` Run wappi locally. Runs on the port set in config (wappi.json) #### Command ```bash wappi run ``` #### Shorthand Command ```bash wappi r ``` #### Example ```bash wappi r ``` Run the tests locally on your code. Add a function name to test a specific function #### Command ```bash wappi test ``` #### Shorthand Command ```bash wappi t ``` #### Example ```bash wappi t Core_Login_1_0_0 ``` Update all your node modules to use the latest versions #### Command ```bash wappi update ``` #### Shorthand Command ```bash wappi u ``` #### Example ```bash wappi u ``` Watches the API folder for changes, works with `wappi run` #### Command ```bash wappi watch ``` #### Shorthand Command ```bash wappi w ``` #### Example ```bash wappi w ``` --- URL: https://www.wappi.dev/about Markdown: https://www.wappi.dev/about.md # Getting Started with Wappi Wappi is a framework that allows a functional API to be run serverless or as a monolith. It is designed to make creating an API backend, simple and organized. So even junior developers can pick it up in no time. ## What is Wappi? Wappi incorporates testing, documentation, and simple local development in it's core. This way your code will be clean, documented and tested as a standard. Wappi will run locally with ease. It has templates for each endpoint out of the box. ### Key Features **Serverless or Monolith** - Run your API in any environment **TypeScript First** - Written in TypeScript with full type support **Built-in Testing** - Jest testing framework included out of the box **Auto Documentation** - Automatic API documentation generation **Prisma Integration** - Built-in Prisma support for database operations **Frontend Integration** - Seamless integration with [wappi-fe](https://www.npmjs.com/package/wappi-fe) ### Why Wappi is awesome? - Simple and organized structure - Perfect for junior developers - Clean, documented, and tested code as standard - Local development made easy - Template-driven endpoint creation --- URL: https://www.wappi.dev/ai Markdown: https://www.wappi.dev/ai.md # WAPPI AI Quick Reference A compact summary of WAPPI conventions for AI coding agents (Cursor, Claude Code, Copilot and others). Each item links to its full page. For the complete docs as one markdown file, read [https://www.wappi.dev/llms-full.txt](https://www.wappi.dev/llms-full.txt). The index is at [https://www.wappi.dev/llms.txt](https://www.wappi.dev/llms.txt) and every page is available as markdown by adding `.md` to its URL. ## Endpoint naming Endpoints are named `Namespace_EndpointName_Major_Minor_Patch`, for example `User_UpdateDetails_2_3_4`. The namespace works like a microservice (e.g. `User`), the endpoint name describes what it does, and the version has three numbers. The request Body type is named `Namespace_EndpointName_Major_Minor_Patch__Body`, e.g. `User_GetUserData_1_0_0__Body`. [Namespaces](https://www.wappi.dev/namespaces) ## Folder layout Each endpoint lives at `API////index.ts`, with an `index.spec.ts` test from the template. Shared helpers live in `API/CoreHelpers/` (e.g. `types.ts`, `logging.ts`). Always create endpoints and versions with the CLI, not by hand. [Namespaces](https://www.wappi.dev/namespaces) ```text API/ Core/Login/1.0.0/index.ts // Core_Login_1_0_0 User/GetUserData/1.0.0/index.ts // User_GetUserData_1_0_0 CoreHelpers/types.ts CoreHelpers/logging.ts ``` ## Registering endpoints Endpoints are registered in `API/index.ts` under `exports.Endpoints`, which also has `LoginRequired` and `PublicApiEndpoint` lists. A webhook goes in `exports.Endpoints` only, not in `LoginRequired` or `PublicApiEndpoint`, because the sender can't log in or send an API key. [Webhooks](https://www.wappi.dev/webhooks) ```typescript // API/index.ts exports.Endpoints = { ... Webhook_StripeCheckout_1_0_0: true, // NewEndpointGoesHere } ``` ## Webhooks Put webhooks in the `Webhook` namespace, so names start with `Webhook_` (e.g. `API/Webhook/StripeCheckout/1.0.0/index.ts` is `Webhook_StripeCheckout_1_0_0`). The sender POSTs its own JSON to `https:///Webhook_StripeCheckout_1_0_0`, with no `query`/`data` wrapper. The Body holds the parsed JSON plus the default body data, `body.headers` (request headers) and `body.raw` (the raw request body as a string). Always verify signatures against `body.raw`. The returned `statusCode` is the HTTP status the sender gets: return 200 when a retry can't help, 4xx/5xx only when a retry could succeed, and make handlers safe to run twice. [Webhooks](https://www.wappi.dev/webhooks) ## Calling an endpoint (wappi-fe) A request names the endpoint in `query` and sends its Body in `data`. Optional `results` include or exclude fields on the server (WAPPI Query Language). [Request](https://www.wappi.dev/frontend-integration/request), [Query Language](https://www.wappi.dev/query-language) ```typescript import { request } from 'wappi-fe' const response = await request(WAPPI_CONFIG, { name: 'Get user info', // label shown in the network tab query: 'NameSpace_FunctionName_1_0_0', // endpoint name data: {}, // typed as NameSpace_FunctionName_1_0_0__Body results: { name: 'user', include: [{ name: 'userName', key: 'name' }] }, // optional authRequired: true, // optional, depends on the endpoint }) ``` ## Default Body data Every endpoint function receives a Body parameter that includes `correlationId`, `headers` and `env` (`localhost | dev | stage | prod`). Authenticated endpoints also get `auth`, the data returned by your `Core_Login` endpoint. [Body Data](https://www.wappi.dev/body-data), [Auth Keys](https://www.wappi.dev/security/auth-keys) ## Versioning Every endpoint version is self-contained. Create a new version with `npx wappi c` and pick the endpoint; you can copy it and choose a major, minor or patch bump. Major = breaking, minor = recommended update, patch = fix. Keep old versions working until logs show they are unused. [Versioning](https://www.wappi.dev/versioning) ## CLI commands Run with `npx wappi `. [CLI Commands](https://www.wappi.dev/cli-commands) ```bash wappi init (i) # initialise WAPPI, required for other commands wappi run (r) # run locally on the port in wappi.json wappi create (c) # new endpoint or new version from templates wappi delete (d) # delete an endpoint version and namespace wappi build (b) # build for running locally and testing wappi test (t) # run tests, optionally for one endpoint: wappi t Core_Login_1_0_0 wappi lint (l) # eslint, based on .eslintrc.json wappi watch (w) # watch the API folder, works with wappi run wappi update (u) # update node modules to latest wappi help (h) # show the commands menu ``` ## Testing Jest is set up out of the box. Every endpoint has an `index.spec.ts`; extend it when you add code. Run `npx wappi t` for everything or `npx wappi t Test_Something_1_0_0` for one endpoint. [Testing](https://www.wappi.dev/testing) ## API documentation `wappi run` writes `-Internal-openAPI-spec.json` (all endpoints) and `-Public-openAPI-spec.json` (endpoints in `exports.PublicApiEndpoint`) to the project root, using each endpoint's `README.md`, `types.ts` and optional `docExample` in `_data/successData.ts`. [API Documentation](https://www.wappi.dev/api-documentation) ## Logging Every endpoint runs inside a `try / catch` and errors are logged automatically, so always throw errors. Customise log output in `/API/CoreHelpers/logging.ts`. Set `SHOW_LOGS=false` in production. [Logging](https://www.wappi.dev/logging) ## Config and environment Project settings are in `wappi.json` (apiKey, authRotation, domains, private, port, prisma, ...). Environment variables go in `.env`, kept in sync with `.env.example` (ENVIRONMENT, SHOW_LOGS, AUTH_KEY_CURRENT, AUTH_KEY_PREVIOUS, FRONTEND_PROJECT_PATHS). A health check is built in at `/healthcheck`. [Configuration](https://www.wappi.dev/configuration), [Environment Variables](https://www.wappi.dev/environment-variables), [Health Checks](https://www.wappi.dev/health-checks) ## Rules-file snippets Copy one of these into your project so your coding agent uses the WAPPI docs. ### AGENTS.md / CLAUDE.md ```markdown ## WAPPI This project uses the WAPPI API framework (npm: wappi). Before writing or changing WAPPI code, read https://www.wappi.dev/llms-full.txt (index: https://www.wappi.dev/llms.txt, quick reference: https://www.wappi.dev/ai.md). - Endpoints: API////index.ts, named Namespace_EndpointName_X_Y_Z - Create endpoints and versions with `npx wappi c`, never by hand - Run tests with `npx wappi t ` ``` ### .cursor/rules/wappi.mdc ```markdown --- description: WAPPI API framework conventions globs: API/**/*.ts alwaysApply: false --- This project uses WAPPI. Read https://www.wappi.dev/llms-full.txt for the full docs (quick reference: https://www.wappi.dev/ai.md). Follow the Namespace_EndpointName_X_Y_Z naming and API//// layout. Use `npx wappi c` to create endpoints or versions and `npx wappi t` to test. ``` ### .github/copilot-instructions.md ```markdown This project uses the WAPPI API framework. Use https://www.wappi.dev/llms-full.txt as the reference for endpoint naming, folder layout, CLI commands, versioning and testing. ``` --- URL: https://www.wappi.dev/configuration Markdown: https://www.wappi.dev/configuration.md # Configuration ## Project Configuration Wappi uses a `wappi.json` file for project configuration. #### API Key This is the key that Wappi has generated for the API key. This key is used in the authKey. If your API is ever compromised, change this API key immediately. *Rebuild when you change this* ```json "apiKey": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4687121gj2hg3hj12g", ``` #### Auth Rotation Wappi will automatically rotate the auth key, based on this timing. You should set this to a time that you want to force logout the user. For high security apps, 10 mins, but for less security needs, you can set it up to 6 months. 30 days is the max recommended time. Follow the CRON timing: | Minute | Hour | Day of Month | Month | Day of Week | | --- | --- | --- | --- | --- | | 0-59 | 0-23 | 1-31 | 1-12 | 0-6 (Sun=0) | ```json "authRotation": "*/30 * * * *", ``` #### Deployment Deployment is used as a flag for a future feature, to help streamline the deployment process. Still a work in progress. ```json "deployment": "scalingAwsEC2", ``` #### Whitelist Domains Wappi will automatically lock your API calls to domains in this string list. It will automatically check the `request.headers.from` value for a match. If your API is public and you want all types of domains hitting it, leave this as an empty string. ```json "domains": "mydomain.com, mydomain.org, www.mydomain.com, www.mydomain.org", ``` #### Private or Public API If your API is a private API, you can set this to true. This will make it unaccessible to calls that are not from your "domains". This will mean that only the domains listed will have access. If there are no domains listed, it will not work. ```json "private": false, ``` #### Port This is the port that wappi will run on. Allows you to change it if you have other APIs or projects with conflicting ports running locally. ```json "port": 3030, ``` #### Prisma If you are using [Prisma ORM](https://www.prisma.io/), then the prisma object build will be intergrated with your API and be available on each endpoint as part of the DB object. ```json "prisma": true, ``` #### CI/CD Currently we only support gitlab as a CI/CD pipeline. When setting up your API, if you use gitlab, it will add in the CI/CD basic setup. So you can easily deploy to AWS. ```json "repository": "gitlab", ``` #### Routing Currently we only have default routing. This means that it will auto route every call through auth (if required) and figure out the routing automatically. ```json "routing": "default", ``` #### Name & Description This is the name and description for the app, that also gets added to the package.json on init. ```json "serviceName": "My Simple API", "serviceDescription": "API for my awesome App", ``` #### MySQL If you are using SQL, the connection data object will be added to the `db: DB` object that is passed into each endpoint. Allowing you to have access to it. ***If you are using sql or mongo, we recommend that you use Prisma.*** ```json "sql": false, ``` #### Server Provider Wappi has built in functions for Amazon Web Services (AWS) **Auth Key Secrets**: Wappi has a built in function to read a secret that is stored in your AWS Secrets Manager. See *Security - Auth Keys* for more details. ```json "serverProvider": "AWS", ``` #### Full Example ```json { "apiKey": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4687121gj2hg3hj12g", "authRotation": "*/30 * * * *", "deployment": "scalingAwsEC2", "domains": "mydomain.com, mydomain.org, www.mydomain.com, www.mydomain.org", "port": 3030, "prisma": false, "private": false, "repository": "gitlab", "routing": "default", "serviceDescription": "API for my awesome App", "serviceName": "API", "sql": false, "serverProvider": "AWS" } ``` --- URL: https://www.wappi.dev/environment-variables Markdown: https://www.wappi.dev/environment-variables.md # Environment Variables You need a `.env` file in your project root. Your `.env` is built from the `.env.example`. You need to keep the keys in the `.env.example` up to date at all times. If it's not kept up to date, it may fail on deployment or fail to run locally. #### ENVIRONMENT Either: `localhost` | `dev` | `stage` | `prod` This allows you to run your local code as if it's running on production to find performance issues. *Rebuild when you change this* ```bash ENVIRONMENT='localhost' ``` #### SHOW_LOGS Show Logs is for development or bug fixing. Recommended: localhost = true; prod = false. Showing logs will display the body data. So it's a security risk to show on production ```bash SHOW_LOGS=true ``` #### AUTH_KEY_CURRENT, AUTH_KEY_PREVIOUS Default FallBack - You should set these to rotate using AWS Secrets Manager. See[Security > Auth Keys](https://www.wappi.dev/security/auth-keys)for more information. ```bash AUTH_KEY_CURRENT='asdf' AUTH_KEY_PREVIOUS='asdf' ``` #### Auto sync `types.ts` files to frontend instantly Internal Frontend Project Paths. This is the path that the built types files will be automatically copied over to when you run wappi locally. Allowing the types files to always stay in sync. *Only for Local Environment* ```bash FRONTEND_PROJECT_PATHS=[''] ``` Example ```bash FRONTEND_PROJECT_PATHS=["/Path/To/My/Website/src/API", "/Path/To/My/adminWebsite/src/API"] ``` --- URL: https://www.wappi.dev/namespaces Markdown: https://www.wappi.dev/namespaces.md # Namespaces Wappi has a very Strict folder structure. If you try and add files and folders everywhere like a cowboy, then you will probably break your API and also create your future self more problems. Example Endpoint: **User**_**UpdateDetails**_**2_3_4** | Namespace | Function | Version | | --- | --- | --- | | User | UpdateDetails | 2.3.4 | ## NameSpace folder The initial folder is the namespace. Think of this folder like a micro-service, just without the *-service* at the end. So in a micro-service architecture, to have an endpoint that updates all the details of a user, you might store that code in a service like: **User-Service**. In wappi, just make the namespace folder **User** Then all your **User** endpoints will be nested under here. Clean and simple. ## Endpoint Name The second folder is the endpoint name. This is the descriptive name of the function/endpoint. This can be anything you like, that describes the purpose of the endpoint for the API user. In your User service your endpoint name would be: **UpdateDetails** ## Versions The last part of the folder structure is made up of 3 numbers: `2.3.4` These are the versions of endpoint. Think of this like: Every microservice endpoint will have it's own version that is immutable. Thats what this last folder structure is. | Major Version | Minor Version | Patch Version | | --- | --- | --- | | 2 | 3 | 4 | ## Best Practices #### NameSpace Name Make your namespace names be specific for a purpose. So it is easy to find where new endpoints should live. Good examples: User || Products Bad examples: Services || AWS If you make it too broad, or if you name it based on something like AWS. It will be confusing to new developers on what should go in this, or why a function is in there. #### Endpoint Names Make your function name descriptive to what it does. This will make it easier for the future YOU, to work out what it does, as well as all the other API users trying to find the right endpoint. Good examples: UpdateDetails or UpdateCartAddressDetails Bad examples: Update or Get If you make it really generic, you will eventually find that you have too much logic in 1 endpoint. Which makes it complicated. And things that are complicated, tend to have more tech debt, and break more often. So keep it simple. ## It's that simple --- URL: https://www.wappi.dev/versioning Markdown: https://www.wappi.dev/versioning.md # Versioning Every endpoint has a version. So you don't have to break APIs when you deploy a new fix. When you deploy a wappi API, you won't break your frontend or existing code, because the version is a self-contained micro-service. Not worrying about anything outside of itself. ## How versioning works Every endpoint has a strict folder nesting, to keep things clean and tidy. See [Structure > NameSpaces](https://www.wappi.dev/security/auth-keys) The version is the last folder where your endpoint code lives. This keeps different changes separate and clean. ## Create a new version Every time you create a new endpoint or a new version. You must use the wappi CLI so that everything that is supposed to happen, happens. *Saves you forgetting to do one thing, then wondering why nothing works.* Simply run the following CLI command to create a new version. (**c** is short for **create**) ```bash npx wappi c ``` Then when prompted, select the current endpoint you want to version. This will give you the option to copy the current endpoint or start again. It will also allow you to create a major, minor and fix version. ## Version numbers A version is made up of 3 numbers: `2.3.4` | Major Version | Minor Version | Patch Version | | --- | --- | --- | | 2 | 3 | 4 | | Breaks Version 1 | Recommended Update | Patching the current version, But can have side effects | ## Best Practices If you change a major version **2**.3.4 Make sure that old versions are still compatible and document the breaking change properly. No developer wants to use your API and then one day it all breaks, because they didn't know the version of the API they were using was deleted. ## Version Cleanup After an API has been used for years, you may find you have hundreds of versions of endpoints. Use the logging, to find out which versions are still being used. Then delete the versions that are extinct. ## It's that simple --- URL: https://www.wappi.dev/body-data Markdown: https://www.wappi.dev/body-data.md # Body Data Wappi will pass through specific data into each endpoint function by default. This data is to allow observability and other middleware that you can add. ## Default Body Data Types ```typescript // CoreHelpers/types.ts type Env = 'localhost' | 'dev' | 'stage' | 'prod' interface WappiBaseNoAuthBody { correlationId: string headers: any env: Env } interface WappiBaseAuthenticatedBody extends WappiBaseNoAuthBody { auth: SuccessResponse } ... ``` Inside the endpoint, you will receive all the data inside the **Body** parameter. --- URL: https://www.wappi.dev/webhooks Markdown: https://www.wappi.dev/webhooks.md # Webhooks Webhooks let third parties such as Stripe call your API directly. A normal Wappi request is a POST with a `{ query, data }` body. A third party sends its own JSON, so Wappi gives webhooks their own path. ## Naming Put every webhook in the **Webhook** namespace, so its function name starts with `Webhook_`. Versioning works the same as for any other endpoint. ```typescript API/Webhook/StripeCheckout/1.0.0/index.ts -> Webhook_StripeCheckout_1_0_0 ``` ## Registering the endpoint Add the webhook to `exports.Endpoints` in `API/index.ts`. Don't add it to `LoginRequired` or `PublicApiEndpoint`. The sender can't log in or send an API key, so the endpoint has to check the sender's signature itself. ```typescript // API/index.ts exports.Endpoints = { ... Webhook_StripeCheckout_1_0_0: true, // NewEndpointGoesHere } ``` ## Calling it The sender POSTs to your API URL with the function name as the path. The body is whatever the sender sends, with no `query`/`data` wrapper. ```http POST https:///Webhook_StripeCheckout_1_0_0 ``` ## What the endpoint receives Wappi passes `/Webhook_*` POSTs through unchanged. The endpoint's **Body** holds the parsed JSON plus the default body data, the request headers, and the raw request body as a string. ```typescript // API/Webhook/StripeCheckout/1.0.0/types.ts export interface Body extends WappiBaseNoAuthBody { headers?: Record raw?: string [key: string]: any } ``` Always verify signatures against `body.raw`. Re-serialising the parsed JSON changes the bytes, so the signature check would fail. ## Example: Stripe ```typescript import Stripe from 'stripe' import { DB } from '../../../CoreHelpers/types' import { Body, Response } from './types' export async function Webhook_StripeCheckout_1_0_0( body: Body, { prisma }: DB, ): Promise { try { const signature = body.headers?.['stripe-signature'] as string const event = stripe.webhooks.constructEvent(body.raw, signature, process.env.STRIPE_WEBHOOK_SECRET) if (event.type !== 'payment_intent.succeeded') { return { success: true, statusCode: 200, action: 'ignored' } } // ...handle the event return { success: true, statusCode: 200, action: 'processed' } } catch (err: any) { return { success: false, statusCode: 400 } } } ``` ## Status codes The `statusCode` you return is the HTTP status the sender gets. Most senders, including Stripe, retry anything that isn't a 2xx. Return 200 when a retry can't help (the event is processed, a duplicate, ignored, or permanently invalid, such as a bad signature). Return 4xx or 5xx only when a retry could succeed. Senders can deliver the same event more than once, so make the handler safe to run twice. ## Troubleshooting If you get this error, the request went through the normal query router instead of the webhook path. Check that the URL ends in `/Webhook_Name_1_0_0` with the exact casing, and that the deployed build includes the endpoint. ```json { "statusCode": 500, "message": "Fail.. Query does not exist. Check the name and version", "error": "Query does not exist", "devMessages": [ "Cannot Parse the body.data obj into JSON. Check the object structure in the data obj: { 'data': {} }", "Check the query name in the body JSON is correct. { 'query': 'Function_Name' }", "CORE ONLY:: There are no other functions" ] } ``` --- URL: https://www.wappi.dev/query-language Markdown: https://www.wappi.dev/query-language.md # WAPPI Query Language Simlar to the GraphQL concept of only returning what is required. Wappi allows you to include or exclude fields that will be normally returned by the endpoint. WAPPI does this filtering on the backed, so it's securly hidden on your server. To *include* or *exlcude* data, it has to be send through in the body data. #### Latency problem Latency is the slowest part of an API, especially if your server is not in the same country as the users device. Reducing the size of data packets to be only what you need will dramatically speed up the response time. #### Packet Size Example Lets say that you have a endpoint (GetAllProductData) that returns all the data for a product, including sub products, sizes, all the price data, history, reviews, etc.. Lets say the full response is 1MB of data. However on the front end, you only want to show the product name, price and availability. With WAPPI, you can *include* only these 3 fields. Making the response only 4KB. This reduction would remove 99% of the data size and make the API call around 200X faster. #### Excluding data You can also Exclude data that you don't want your backend to send through to the frontend. As an example: you have a private API that only connect your backend to your frontend (Meaning no external person has access to your API). You have a generic endpoint, that returns all the product data, even your profit margin. You use this endpoint for internal admin features, but also for your public frontend. But you don't want users to see the profit margin. Just exclude this data from the response and your profit margin will never be returned. This saves you from doubling up on endpoints, and allows you to only show data you want to show. #### INCLUDE Structure: ```json { ... results: { // Default is "result" name: "customResultsName", include: [ { name: "camelCaseCustomName", key: "keyNameToInclude" } ], }, } ``` **Example:** ```json { ... result: { name: "basicProductData", include: [ { name: "productName", key: "name" }, { name: "productPrice", key: "price" }, { name: "productAvailable", key: "availablity" } ], }, } ``` This would return: ```json { basicProductData: { productName: "Awesome Product Name", productPrice: 123.32, productAvailable: true, }, } ``` #### EXCLUDE Structure: ```json { ... results: { // Default is "result" name: "customResultsName", exclude: [ { key: "keyNameToExclude" } ] }, } ``` **Example:** ```json { ... result: { name: "publicProductData", exclude: [ { key: "profitMargin" }, ], }, } ``` This would return: ```json { publicProductData: { id: '1kjh132', price: 123.45. name: "Awesome Product Name" ... // All product data. Execpt: profitMargin }, } ``` --- URL: https://www.wappi.dev/testing Markdown: https://www.wappi.dev/testing.md # Testing Wappi includes built-in testing capabilities to ensure your API is reliable and well-tested. Wappi follows the Test Driven Development (TDD for you acronym folk) methodology. Every endpoint has a `index.spec.ts` as part of the template. The basic tests are already set up. So when you add more code, you just have to add to the tests to reach the test coverage you deem appropriate. ## Test a single endpoint Use the CLI to run the test like below. (**t** is short for **test**) Enter your endpoint function name, that is located in your `index.ts` file. Here is an example, if you have an endpoint in the folder: `Test/Something/1.0.0` ```bash npx wappi t Test_Something_1_0_0 ``` ## Test everything! Super simple, just use the CLI command. (**t** is short for **test**) ```bash npx wappi t ``` ### Jest Wappi uses **jest** out of the box. So it's all set up for you. No config needed. The types are all available for you. It's literally that simple! ## It's that simple! --- URL: https://www.wappi.dev/api-documentation Markdown: https://www.wappi.dev/api-documentation.md # API Documentation (OpenAPI and Postman) Wappi generates OpenAPI documentation for your API automatically. Every time you start the dev server it writes two OpenAPI 3.0 spec files: an **Internal** spec with every endpoint and a **Public** spec with only the endpoints you mark as public. You can import either file into Postman, or view it in the Wappi OpenAPI documentation app. ## When the docs are generated The docs are generated by `wappi run`. After the server is built, Wappi creates the Internal spec, then the Public spec, then starts the dev server. There is no separate command for it. ```bash npx wappi run ``` You will see these lines in the output: ```typescript Internal OpenAPI Documentation Complete Public OpenAPI Documentation Complete ``` The specs are created once when `wappi run` starts. Code changes picked up while it is running don't regenerate them, so restart `wappi run` to refresh the docs. ## Output files Both files are written to your project root (the folder you run wappi from). The file name starts with the `name` in your `package.json`: ```typescript -Internal-openAPI-spec.json -Public-openAPI-spec.json ``` For example, a project named `connect_api` gets `connect_api-Internal-openAPI-spec.json` and `connect_api-Public-openAPI-spec.json`. The spec's `info.title` is the level plus the `serviceDescription` from `wappi.json` (e.g. *Internal API for my awesome App*). `info.description` and `info.version` come from `package.json`. ## Public vs Internal (private) docs Which spec an endpoint appears in depends on `API/index.ts`: | Spec | Includes | | --- | --- | | Internal | Every endpoint version folder under API/// | | Public | Only endpoints set to true in exports.PublicApiEndpoint | ```typescript // API/index.ts exports.PublicApiEndpoint = { Core_TestNoAuthentication_1_0_0: true, // NewPublicApiEndpointGoesHere } ``` When you create an endpoint with `npx wappi c`, Wappi asks *"Will this endpoint be in the public OpenAPI documentation?"*. Answer yes and it adds the endpoint to `exports.PublicApiEndpoint` for you. To change it later, add or remove the endpoint's line in that object. `LoginRequired` doesn't decide which spec an endpoint is in. Keep the `// New...GoesHere` comments, because the CLI uses them to insert new endpoints. A health check entry (`GET /healthcheck`) is added to both specs. ## Where each endpoint's docs come from Every endpoint created with the CLI already has the files the generator reads: ```text API/User/GetUserData/1.0.0/ README.md // endpoint description types.ts // EndPointBody, SuccessResponse, ErrorResponse _data/successData.ts // optional docExample for the request data ``` | Source | Used for | | --- | --- | | README.md | The endpoint's description, used as written | | types.ts: EndPointBody | The schema for the request data | | types.ts: SuccessResponse | The 200 Success response schema | | types.ts: ErrorResponse | The 400 Error response schema | | _data/successData.ts: docExample | The example request data, also used as schema defaults | Every interface in `types.ts` is converted to a JSON schema. Optional properties (`?`) are not required, and references to other interfaces in the same file are linked. If `types.ts` uses `WappiBaseAuthenticatedBody`, the request gets an `auth` field set to `{{AuthKey}}`. ### Adding an example The template's `_data/successData.ts` has a commented-out `docExample`. Uncomment it and fill it in with literal values (strings, numbers, booleans, null, objects and arrays): ```typescript // docExample will be added to the openAPI generated documentation as - data: {...docExample} const docExample = { userId: 'abc123', } ``` Without a `docExample`, Wappi builds the example from the schema with empty values (`''`, `0`, `false`). ## What the request looks like in the spec Each endpoint version is listed as a POST at `///`. Its example request body uses the Wappi request format: ```json { "name": "User GetUserData", "version": "1.0.0", "query": "User_GetUserData", "data": { ...docExample }, "results": { "name": "results" }, "auth": "{{AuthKey}}" // only for endpoints that require auth } ``` The server URL is `{{baseUrl}}`, described in the spec as the main API server where the `query` field decides which endpoint is called. ## Import into Postman In Postman, choose **Import** and select one of the generated `-openAPI-spec.json` files. The spec uses `{{baseUrl}}` and `{{AuthKey}}` placeholders, so set `baseUrl` (for example `http://localhost:3030` locally) and `AuthKey` as Postman variables. Share the Public spec with external API users and keep the Internal spec for your own team. ## View the docs in a website The Wappi OpenAPI documentation app is a Next.js site that renders a spec as browsable API docs, with endpoint details, search and code snippets. It reads the spec from `public/openapi-spec.json` and serves it to the pages through `/api/openapi-spec`. To use it, copy the spec you want to publish (usually the Public one) into `public/openapi-spec.json`, then run or deploy the app: ```typescript cp connect_api-Public-openAPI-spec.json /public/openapi-spec.json cd pnpm dev # runs on port 3011 ``` ## Related See [Namespaces](https://www.wappi.dev/namespaces) for the folder structure, [CLI Commands](https://www.wappi.dev/cli-commands) for `wappi run`, and [Auth Keys](https://www.wappi.dev/security/auth-keys) for logging in. --- URL: https://www.wappi.dev/deployment Markdown: https://www.wappi.dev/deployment.md # Deployment Wappi applications can be deployed to various platforms, both as serverless functions and traditional servers. ## Serverless Deployment ### Vercel ```bash # Install Vercel CLI npm i -g vercel # Deploy vercel ``` Create `vercel.json`: ```json { "version": 2, "builds": [ { "src": "src/index.ts", "use": "@vercel/node" } ], "routes": [ { "src": "/(.*)", "dest": "src/index.ts" } ] } ``` ### AWS Lambda ```bash # Build for production npm run build # Deploy with Serverless Framework serverless deploy ``` ## Traditional Server Deployment ### Docker Create `Dockerfile`: ```dockerfile FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . RUN npm run build EXPOSE 3000 CMD ["npm", "start"] ``` ### PM2 ```bash # Install PM2 npm install -g pm2 # Start application pm2 start ecosystem.config.js # Monitor pm2 monit ``` Create `ecosystem.config.js`: ```typescript module.exports = { apps: [{ name: 'wappi-api', script: 'dist/index.js', instances: 'max', exec_mode: 'cluster', env: { NODE_ENV: 'production', PORT: 3000 } }] } ``` ## Environment Setup ### Production Environment Variables ```bash NODE_ENV=production DATABASE_URL=your-production-database-url JWT_SECRET=your-production-secret PORT=3000 ``` ### Health Checks Wappi includes built-in health check endpoints: - `GET /health` - Basic health check - `GET /health/detailed` - Detailed system status --- URL: https://www.wappi.dev/deployment/aws-ec2-autoscaling Markdown: https://www.wappi.dev/deployment/aws-ec2-autoscaling.md # AWS EC2 - Autoscaling Template Code coming soon --- URL: https://www.wappi.dev/deployment/aws-lambda-serverless Markdown: https://www.wappi.dev/deployment/aws-lambda-serverless.md # AWS Lambda - Serverless Coming Soon. --- URL: https://www.wappi.dev/logging Markdown: https://www.wappi.dev/logging.md # Built in Observability Wappi includes comprehensive logging capabilities to help you monitor, debug, and maintain your API. Logging is essential for understanding how your API is performing and identifying issues in production. Wappi's goal with observability is to be able to find any issue within 2 minutes, with verbose observability. ## Built-in Logging Wappi automatically logs all incoming requests and error responses, including: - Request headers and body - Body - Auth Details - From the Login Auth Token - Error details and stack traces ## Make Logging Simple All endpoints are between a `try / catch`. Any errors will be caught in the catch and logged to your place of choice. ## Default Logs All the logs will be logged to the console by default. So when you deploy wappi, they will be in the success and error.logs files on the server. ## Custom Logs By default all logs will pass through the folder path: **/API/CoreHelpers/logging.ts** Customize your logs, by adding your own code into this file. Some implementations have been sending every log to DataDog, Splunk and CloudWatch. ## Best Practices Observability is really important when programming. Make sure that you always throw ALL errors, so they are caught in the catch. Send all your logs to an observability platform, so you have instant access to errors and warnings. On Production, make sure your "SHOW_LOGS" environment variable is set to false. So that you are not showing sensitive production data, and to conserve space on your log files. ```bash SHOW_LOGS=false ``` --- URL: https://www.wappi.dev/health-checks Markdown: https://www.wappi.dev/health-checks.md # Health Checks Wappi includes a built-in health check endpoint to monitor the status and health of your API. This endpoint is essential for monitoring, to ensure your API is running correctly. ## Built-in Health Check Endpoints Wappi automatically provides the health check endpoint that you can use without any additional configuration: ### To do a health check, simply hit the URL: All http methods will return a 200 response. ```http GET /healthcheck ``` Response Object: ```json { "complete": true, "statusCode": 200, "message": "Healthy", "success": true } ``` ### Try it locally After running wappi run > then go to the url: ```bash npx wappi run ``` Go to: [http://localhost:3030/healthcheck](http://localhost:3030/healthcheck) *{DOMAIN_URL}/healthcheck* --- URL: https://www.wappi.dev/security Markdown: https://www.wappi.dev/security.md # Security Wappi provides comprehensive security features to protect your API and ensure secure communication between your frontend and backend applications. ## Security Overview Security in Wappi is built around multiple layers of protection: - **API Key Authentication** - Secure your API endpoints with API keys - **JWT Authentication** - Token-based authentication for user sessions - **Domain Whitelisting** - Restrict API access to specific domains - **Request Validation** - Validate all incoming requests and data - **Rate Limiting** - Protect against abuse and DDoS attacks - **HTTPS Enforcement** - Secure communication over encrypted connections ## Built-in Security Features ### Automatic Request Validation Wappi automatically validates all incoming requests against your defined types and schemas: ```typescript // Automatic validation based on endpoint types interface User_CreateUser_1_0_0__Body { name: string email: string password: string } // Wappi automatically validates the request body // Invalid requests are rejected before reaching your endpoint ``` ### Domain Whitelisting Configure allowed domains in your `wappi.json` configuration: ```json { "domains": "yourdomain.com, api.yourdomain.com, www.yourdomain.com", "private": false } ``` ### Environment-based Security Different security settings for different environments: ```bash # Development ENVIRONMENT=localhost SHOW_LOGS=true # Production ENVIRONMENT=prod SHOW_LOGS=false AUTH_KEY_CURRENT=your-production-key AUTH_KEY_PREVIOUS=your-previous-key ``` ## Security Best Practices - Always use HTTPS in production environments - Regularly rotate your API keys and JWT secrets - Implement proper input validation and sanitization - Use environment variables for sensitive configuration - Enable logging for security events and monitoring - Implement rate limiting to prevent abuse - Keep your dependencies up to date - Use strong, unique passwords and secrets ## Security Headers Wappi automatically sets important security headers: ```typescript // Automatically set by Wappi { "X-Content-Type-Options": "nosniff", "X-Frame-Options": "DENY", "X-XSS-Protection": "1; mode=block", "Strict-Transport-Security": "max-age=31536000; includeSubDomains", "Content-Security-Policy": "default-src 'self'" } ``` ## Error Handling Secure error handling prevents information leakage: ```typescript // Production error response (no sensitive information) { "success": false, "message": "Authentication failed", "statusCode": 401 } // Development error response (detailed for debugging) { "success": false, "message": "JWT token expired at 2024-01-15T10:30:00Z", "statusCode": 401, "stack": "Error: JWT expired..." } ``` ## Next Steps Explore the specific security features: - [API Keys](https://www.wappi.dev/security/api-keys) - Learn about API key authentication - [JWT Authentication](https://www.wappi.dev/security/jwt-authentication) - Implement JWT-based user authentication --- URL: https://www.wappi.dev/security/auth-keys Markdown: https://www.wappi.dev/security/auth-keys.md # Authenticated Users / API Keys Auth Keys in Wappi provide secure authentication token management for user sessions and API access. These keys are automatically rotated and managed by Wappi to ensure maximum security for your application. ## How Auth Keys Work Auth Keys are generated when users successfully authenticate through the Core_Login endpoint. These keys serve as session tokens that validate user identity and permissions for subsequent API requests. - Generated automatically upon successful login - Stored securely in the clients localStorage - Automatically included in authenticated requests - Rotated based on your configured schedule - Validated on every protected endpoint ## Auth Key Configuration ### Environment Variables ```bash # Current and previous auth keys for rotation AUTH_KEY_CURRENT=your-current-auth-key-here AUTH_KEY_PREVIOUS=your-previous-auth-key-here # Environment setting affects key generation ENVIRONMENT=prod ``` ### wappi.json Configuration ```json { "authRotation": "0 2 * * *", // Daily rotation at 2 AM "apiKey": "your-api-key", "domains": "yourdomain.com, app.yourdomain.com" } ``` ## Auth Key Generation Auth Keys are automatically generated when users log in through your Core_Login endpoint: ```typescript // API/Core/Login/1.0.0/index.ts export async function Core_Login_1_0_0( body: Body, ): Promise { try { if (!body) throw new Error('No Body') // ⌄⌄⌄⌄⌄ ADD CUSTOM LOGIN LOGIC HERE ⌄⌄⌄⌄⌄ // ^^^^^ ADD CUSTOM LOGIN LOGIC HERE ^^^^^ return {} // eslint-disable-next-line no-unreachable } catch (err) { console.error(err) return { error: err, message: err.message, devMessage: 'Fatal error in Core_Login_1_0_0. Investigate.', success: false, } } } ``` ## Automatic Key Rotation Wappi automatically rotates auth keys based on your configured schedule to enhance security: ### Rotation Schedule ```json { "authRotation": "*/30 * * * *", // Every 30 minutes (high security) "authRotation": "0 */6 * * *", // Every 6 hours (balanced) "authRotation": "0 0 * * *", // Daily (standard) "authRotation": "0 0 * * 0", // Weekly (low security) "authRotation": "0 0 1 * *", // Monthly (low security) "authRotation": "0 0 1 */3 *", // Every 3 months (low security) "authRotation": "0 0 1 */6 *", // Every 6 months (low security) "authRotation": "0 0 1 1 *", // Yearly (Jan 1) (low security) } ``` ### Rotation Process 1. 1. New auth key is generated automatically 2. 2. Current key moves to AUTH_KEY_PREVIOUS 3. 3. New key becomes AUTH_KEY_CURRENT 4. 4. Both keys remain valid during transition 5. 5. Previous key expires after next rotation 6. 6. Users are required to re-authenticated ## Using Auth Keys with wappi-fe If you are using your API on a frontend application. Auth Keys are automatically managed by wappi-fe. Auth keys will be stored in a localStorage object See [Frontend Integration > Authentication](https://www.wappi.dev/security/auth-keys) ## Auth Key Validation Wappi automatically validates auth keys on protected endpoints. Every endpoint will pass through the auth data that your **Core_Login_***** has returned. This means that your auth key can contain any custom data you need for all endpoints. For example. You have a API where a lot of endpoints require the validation of a "CompanyId". You can return this companyID in the auth token and it will be passed into every endpoint. Saving you an extra DB call. Best practices: Don't pass through all user data in the auth key, it will make the auth key bloated. Just keep it simple and only include the fundamentals. ## AWS Secrets Manager Integration For production environments, rotate auth keys with AWS Secrets Manager. In your wappiConfig.json file. If you're using AWS. You can add: ```json "serverProvider": "AWS", ``` If serverProvider is set to AWS. It will query your AWS secrets manager for your auth keys secret. To customize your secret name and AWS region. Set the following Environment variables in your .env.example and .env files in production. ```bash AWS_AUTH_KEY_SECRET_NAME="authKeys" # Default === "authKeys" AWS_AUTH_KEY_SECRET_REGION="ap-southeast-2" # Default === "ap-southeast-2" ``` If you are using this method, it's recommended that you rotate your AWS keys at the same rate as your auth rotation setting in your wappiConfig.json file. Use a lambda to rotate your secrets. ## Security Best Practices - **Regular Rotation:** Set appropriate rotation intervals based on security requirements - **Secure Storage:** Use AWS Secrets Manager - **HTTPS Only:** Never transmit auth keys over unencrypted connections - **Graceful Rotation:** Ensure smooth user experience during key rotation - **Fallback Key:** Always maintain previous key for seamless transitions - **Audit Logging:** Log all authentication events for security monitoring --- URL: https://www.wappi.dev/security/api-keys Markdown: https://www.wappi.dev/security/api-keys.md # API Keys API keys in Wappi provide a secure way to authenticate and authorize access to your API endpoints. They serve as a unique identifier for your application and help protect against unauthorized access. ## Configuration API keys are configured in your `wappi.json` file and environment variables: ### wappi.json Configuration ```json { "apiKey": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4687121gj2hg3hj12g", "private": false, "domains": "yourdomain.com, api.yourdomain.com" } ``` ### Environment Variables ```bash # Current and previous API keys for rotation AUTH_KEY_CURRENT=your-current-api-key AUTH_KEY_PREVIOUS=your-previous-api-key # Environment setting ENVIRONMENT=prod ``` ## How API Keys Work Wappi uses API keys to: - Identify and authenticate API requests - Control access to specific endpoints - Track usage and implement rate limiting - Provide audit trails for security monitoring ### Request Authentication API keys are included in request headers: ```typescript // Frontend request with API key fetch('https://api.yourdomain.com/users', { method: 'GET', headers: { 'Authorization': 'Bearer your-api-key', 'Content-Type': 'application/json' } }) ``` ## API Key Generation When you initialize a new Wappi project, an API key is automatically generated: ```bash npx wappi init # During initialization, Wappi generates: # - A unique API key for your project # - Configuration files with security settings # - Environment variable templates ``` ### Manual API Key Generation You can generate new API keys manually for key rotation: ```typescript // Generate a secure API key const crypto = require('crypto') const apiKey = crypto.randomBytes(32).toString('hex') console.log('New API Key:', apiKey) ``` ## API Key Rotation Wappi supports automatic API key rotation for enhanced security: ### Rotation Configuration ```json { "authRotation": "0 0 * * 0", // Weekly rotation (every Sunday at midnight) "apiKey": "current-key", "domains": "yourdomain.com" } ``` ### Rotation Process 1. 1. Generate a new API key 2. 2. Update AUTH_KEY_CURRENT with the new key 3. 3. Move the old key to AUTH_KEY_PREVIOUS 4. 4. Both keys remain valid during transition period 5. 5. Old key expires after the next rotation cycle ## Using API Keys with wappi-fe Configure API keys in your frontend application: ```typescript // wappiConfig.ts import { WappiConfig } from 'wappi-fe/types' export const WAPPI_CONFIG: WappiConfig = { apiUrl: 'https://api.yourdomain.com', apiKey: process.env.NEXT_PUBLIC_WAPPI_API_KEY, authRedirectPath: '/login' } ``` ### Making Authenticated Requests ```typescript import { request } from 'wappi-fe' import { WAPPI_CONFIG } from './wappiConfig' const response = await request(WAPPI_CONFIG, { name: 'Get User Data', query: 'User_GetUserData_1_0_0', data: { userId: '123' }, authRequired: true // Uses API key authentication }) ``` ## Endpoint Protection Protect specific endpoints with API key requirements: ```typescript // API/User/GetUserData/1.0.0/index.ts export default async function GetUserData(body: User_GetUserData_1_0_0__Body) { // API key validation is handled automatically by Wappi // This endpoint is only accessible with valid API key try { const userData = await getUserById(body.userId) return { success: true, data: userData } } catch (error) { throw new Error('Failed to retrieve user data') } } ``` ## Security Best Practices - **Store API keys securely:** Use environment variables, never hardcode in source code - **Rotate keys regularly:** Implement automatic rotation for enhanced security - **Use HTTPS only:** Never transmit API keys over unencrypted connections - **Implement rate limiting:** Prevent abuse and protect against attacks - **Monitor usage:** Track API key usage for security auditing - **Restrict domains:** Limit API access to specific domains - **Log security events:** Monitor failed authentication attempts ## Troubleshooting ### Common Issues **Invalid API Key Error:** ```json { "success": false, "message": "Invalid API key", "statusCode": 401 } ``` **Solutions:** - Verify the API key is correctly set in environment variables - Check that the key hasn't expired due to rotation - Ensure the request includes the Authorization header - Confirm the domain is whitelisted in wappi.json ### Testing API Keys ```typescript // Test API key validation curl -X GET https://api.yourdomain.com/health \ -H "Authorization: Bearer your-api-key" \ -H "Content-Type: application/json" ``` ## AWS Secrets Manager Integration For production environments, integrate with AWS Secrets Manager for secure key storage: ```typescript // Store API keys in AWS Secrets Manager aws secretsmanager create-secret \ --name "wappi/api-keys" \ --description "Wappi API Keys" \ --secret-string '{ "current": "your-current-api-key", "previous": "your-previous-api-key" }' ``` ```typescript // Retrieve keys in your application const AWS = require('aws-sdk') const secretsManager = new AWS.SecretsManager() async function getApiKeys() { const secret = await secretsManager.getSecretValue({ SecretId: 'wappi/api-keys' }).promise() return JSON.parse(secret.SecretString) } ``` --- URL: https://www.wappi.dev/security/jwt-authentication Markdown: https://www.wappi.dev/security/jwt-authentication.md # JWT Authentication JSON Web Tokens (JWT) provide a secure way to handle user authentication and session management in Wappi applications. JWTs are stateless, scalable, and perfect for modern API architectures. ## How JWT Works in Wappi Wappi uses JWT tokens for user authentication through a dedicated login endpoint: 1. 1. User provides credentials to the login endpoint 2. 2. Wappi validates credentials and generates a JWT token 3. 3. Token is returned to the client and stored (usually in localStorage) 4. 4. Subsequent requests include the JWT token for authentication 5. 5. Wappi validates the token on each protected endpoint ## Login Endpoint Implementation Create a login endpoint that generates JWT tokens: ```typescript // API/Core/Login/1.0.0/index.ts import jwt from 'jsonwebtoken' import bcrypt from 'bcrypt' interface Core_Login_1_0_0__Body { email: string password: string } export default async function CoreLogin(body: Core_Login_1_0_0__Body) { try { // Validate user credentials const user = await validateUser(body.email, body.password) if (!user) { throw new Error('Invalid credentials') } // Generate JWT token const token = jwt.sign( { userId: user.id, email: user.email, role: user.role }, process.env.JWT_SECRET, { expiresIn: '24h', issuer: 'wappi-api', audience: 'wappi-client' } ) return { success: true, data: { user: { id: user.id, email: user.email, name: user.name, role: user.role }, token, expiresIn: '24h' } } } catch (error) { throw new Error('Authentication failed') } } async function validateUser(email: string, password: string) { // Implement your user validation logic const user = await getUserByEmail(email) if (!user || !await bcrypt.compare(password, user.hashedPassword)) { return null } return user } ``` ## JWT Configuration ### Environment Variables ```bash # JWT Secret for token signing JWT_SECRET=your-super-secret-jwt-key-here # Token expiration settings JWT_EXPIRES_IN=24h JWT_REFRESH_EXPIRES_IN=7d # JWT issuer and audience JWT_ISSUER=wappi-api JWT_AUDIENCE=wappi-client ``` ### wappi.json Configuration ```json { "authRotation": "0 0 * * *", // Daily token rotation "apiKey": "your-api-key", "domains": "yourdomain.com, app.yourdomain.com" } ``` ## Protected Endpoints Protect endpoints by requiring JWT authentication: ```typescript // API/User/GetProfile/1.0.0/index.ts interface User_GetProfile_1_0_0__Body { // JWT auth data is automatically added to authenticated requests auth: { userId: string email: string role: string } } export default async function GetUserProfile(body: User_GetProfile_1_0_0__Body) { try { // Access authenticated user data from body.auth const userId = body.auth.userId const userProfile = await getUserProfile(userId) return { success: true, data: userProfile } } catch (error) { throw new Error('Failed to get user profile') } } ``` ## Frontend Integration ### Login Implementation ```typescript import { request } from 'wappi-fe' import { WAPPI_CONFIG } from './wappiConfig' // Login function export const login = async (email: string, password: string) => { const response = await request(WAPPI_CONFIG, { name: 'User Login', query: 'Core_Login_1_0_0', data: { email, password }, authRequired: false, // Login doesn't require existing auth successCallback: (data) => { // Store JWT token in localStorage localStorage.setItem('wappiAuthToken', data.token) localStorage.setItem('wappiUser', JSON.stringify(data.user)) }, errorCallback: (error) => { console.error('Login failed:', error) } }) return response } ``` ### Authenticated Requests ```typescript // Making authenticated requests export const getUserProfile = async () => { return await request(WAPPI_CONFIG, { name: 'Get User Profile', query: 'User_GetProfile_1_0_0', data: {}, authRequired: true, // Automatically includes JWT token errorCallback: (error) => { if (error.statusCode === 401) { // Token expired or invalid - redirect to login localStorage.removeItem('wappiAuthToken') window.location.href = '/login' } } }) } ``` ## Token Refresh Implement token refresh for seamless user experience: ```typescript // API/Core/RefreshToken/1.0.0/index.ts interface Core_RefreshToken_1_0_0__Body { refreshToken: string } export default async function RefreshToken(body: Core_RefreshToken_1_0_0__Body) { try { // Validate refresh token const decoded = jwt.verify(body.refreshToken, process.env.JWT_REFRESH_SECRET) // Generate new access token const newToken = jwt.sign( { userId: decoded.userId, email: decoded.email, role: decoded.role }, process.env.JWT_SECRET, { expiresIn: '24h' } ) return { success: true, data: { token: newToken, expiresIn: '24h' } } } catch (error) { throw new Error('Invalid refresh token') } } ``` ## JWT Middleware Wappi automatically handles JWT validation for protected endpoints: ```typescript // Automatic JWT validation middleware (built into Wappi) function validateJWT(token: string) { try { const decoded = jwt.verify(token, process.env.JWT_SECRET) // Check token expiration if (decoded.exp < Date.now() / 1000) { throw new Error('Token expired') } return { success: true, user: decoded } } catch (error) { return { success: false, error: error.message } } } ``` ## Security Best Practices - **Use strong JWT secrets:** Generate cryptographically secure secrets - **Set appropriate expiration:** Balance security and user experience - **Implement token refresh:** Allow seamless token renewal - **Validate token claims:** Check issuer, audience, and custom claims - **Use HTTPS only:** Never transmit tokens over unencrypted connections - **Store tokens securely:** Use httpOnly cookies or secure storage - **Implement logout:** Provide token invalidation mechanism - **Monitor token usage:** Track authentication events for security ## Logout Implementation ```typescript // Frontend logout function export const logout = () => { // Remove tokens from storage localStorage.removeItem('wappiAuthToken') localStorage.removeItem('wappiRefreshToken') localStorage.removeItem('wappiUser') // Redirect to login page window.location.href = '/login' } // Optional: Server-side token blacklisting // API/Core/Logout/1.0.0/index.ts export default async function Logout(body: Core_Logout_1_0_0__Body) { try { // Add token to blacklist (optional) await blacklistToken(body.auth.token) return { success: true, message: 'Logged out successfully' } } catch (error) { throw new Error('Logout failed') } } ``` ## Error Handling Handle JWT-related errors gracefully: ```typescript // Common JWT error responses { "success": false, "message": "Token expired", "statusCode": 401, "code": "TOKEN_EXPIRED" } { "success": false, "message": "Invalid token", "statusCode": 401, "code": "INVALID_TOKEN" } { "success": false, "message": "Token required", "statusCode": 401, "code": "TOKEN_REQUIRED" } ``` ## Testing JWT Authentication ```typescript // Test JWT authentication curl -X POST https://api.yourdomain.com/Core/Login/1.0.0 \ -H "Content-Type: application/json" \ -d '{ "email": "user@example.com", "password": "password123" }' // Use returned token for authenticated requests curl -X GET https://api.yourdomain.com/User/GetProfile/1.0.0 \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Content-Type: application/json" ``` ## Advanced Features ### Role-Based Access Control ```typescript // Implement role-based access in endpoints export default async function AdminOnlyEndpoint(body: Admin_ManageUsers_1_0_0__Body) { // Check user role from JWT token if (body.auth.role !== 'admin') { throw new Error('Insufficient permissions') } // Admin-only logic here return { success: true, data: await getAdminData() } } ``` ### Custom Claims ```typescript // Add custom claims to JWT tokens const token = jwt.sign( { userId: user.id, email: user.email, role: user.role, permissions: user.permissions, organizationId: user.organizationId, lastLogin: new Date().toISOString() }, process.env.JWT_SECRET, { expiresIn: '24h' } ) ``` --- URL: https://www.wappi.dev/frontend-integration Markdown: https://www.wappi.dev/frontend-integration.md # Frontend Integration Wappi pairs with [wappi-fe](https://www.npmjs.com/package/wappi-fe) to provide seamless integration between your backend API and frontend applications. ## Installation ```bash npm install wappi-fe ``` ## Basic Setup ### React Integration ```typescript import { WappiClient } from 'wappi-fe' const client = new WappiClient({ baseURL: 'http://localhost:3000', timeout: 5000 }) // In your React component function UsersList() { const [users, setUsers] = useState([]) useEffect(() => { client.get('/users') .then(response => setUsers(response.data.users)) .catch(error => console.error(error)) }, []) return (
{users.map(user => (
{user.name}
))}
) } ``` ### Vue.js Integration ```typescript import { WappiClient } from 'wappi-fe' const client = new WappiClient({ baseURL: process.env.VUE_APP_API_URL }) export default { data() { return { users: [] } }, async mounted() { try { const response = await client.get('/users') this.users = response.data.users } catch (error) { console.error(error) } } } ``` ## Advanced Features ### Type Safety ```typescript interface User { id: string name: string email: string } interface ApiResponse { data: T message: string } const response = await client.get>('/users') // response.data is fully typed ``` ### Request Interceptors ```typescript client.interceptors.request.use((config) => { const token = localStorage.getItem('token') if (token) { config.headers.Authorization = `Bearer ${token}` } return config }) ``` ### Response Interceptors ```typescript client.interceptors.response.use( (response) => response, (error) => { if (error.response?.status === 401) { // Handle unauthorized access window.location.href = '/login' } return Promise.reject(error) } ) ``` ## Real-time Features ### WebSocket Integration ```typescript import { WappiSocket } from 'wappi-fe' const socket = new WappiSocket('ws://localhost:3000') socket.on('user:created', (user) => { console.log('New user created:', user) }) socket.emit('join:room', { roomId: 'users' }) ``` --- URL: https://www.wappi.dev/frontend-integration/getting-started Markdown: https://www.wappi.dev/frontend-integration/getting-started.md # Getting Started Get up and running with wappi-fe in minutes. This guide will walk you through the basic setup and your first API call. ### 1. Install wappi-fe [Follow the instructions found in the installation seciton](https://www.wappi.dev/frontend-integration/installation) ### 2. Set up the Config for you API [Follow the instructions found in the configuration seciton](https://www.wappi.dev/frontend-integration/configuration) ### 3. Make your first request [Follow the instructions in the request section](https://www.wappi.dev/frontend-integration/request) --- URL: https://www.wappi.dev/frontend-integration/installation Markdown: https://www.wappi.dev/frontend-integration/installation.md # Setup ### 1. Install wappi-fe using your preferred package manager ```bash npm install wappi-fe ``` ```bash yarn add wappi-fe ``` ```bash pnpm add wappi-fe ``` ### 2. Set your types files import location **Problem:** Your frontend doesn't know the types of your backend API. So matching types means manually copying over files. **Solution:** Every time you run wappi, it will transfer the compiled API types from the API to your frontend repo. Allowing you to always have them in sync. This is the path that you are importing your wappiTypes to from your local wappi .env file. FRONTEND_PROJECT_PATHS=["/absolute/path/to/frontend/wappiTypes.ts"] # Example: FRONTEND_PROJECT_PATHS=["/Users/Smithy/ProjectAlpha/src/wappiTypes.ts"] Update your tsconfig.json file ```json { "compilerOptions": { "paths": { "@wappiTypes": [ "./src/wappiTypes.ts" ] } } } ``` ### 3. Create a reusable CONFIG file Somewhere in your frontend code base. Create a reusable config file with your wappi information. wappiConfig.ts ```typescript import { WappiConfig } from 'wappi-fe/types'; export const WAPPI_CONFIG: WappiConfig = { apiUrl: 'https://api.domain.com', // your base API domain authRedirectPath: '/login', // The path you want the user to be redirected to if they don't have an auth token }; ``` Use the config in the request ```typescript const response = async () => (request(WAPPI_CONFIG, { name: 'Get Some Information', query: 'NameSpace_FunctionName_1_0_0', data: {}, })) ``` --- URL: https://www.wappi.dev/frontend-integration/configuration Markdown: https://www.wappi.dev/frontend-integration/configuration.md # Configuration ### 1. Set your types files import location **Problem:** Your frontend doesn't know the types of your backend API. So matching types means manually copying over files. **Solution:** Every time you run wappi, it will transfer the compiled API types from the API to your frontend repo. Allowing you to always have them in sync. This is the path that you are importing your wappiTypes to from your local wappi .env file. FRONTEND_PROJECT_PATHS=["/absolute/path/to/frontend/wappiTypes.ts"] # Example: FRONTEND_PROJECT_PATHS=["/Users/Smithy/ProjectAlpha/src/wappiTypes.ts"] Update your tsconfig.json file ```json { "compilerOptions": { "paths": { "@wappiTypes": [ "./src/wappiTypes.ts" ] } } } ``` ### 2. Create a reusable CONFIG file Somewhere in your frontend code base. Create a reusable config file with your wappi information. wappiConfig.ts ```typescript import { WappiConfig } from 'wappi-fe/types'; export const WAPPI_CONFIG: WappiConfig = { apiUrl: 'https://api.domain.com', // your base API domain authRedirectPath: '/login', // The path you want the user to be redirected to if they don't have an auth token }; ``` Use the config in the request ```typescript const response = async () => (request(WAPPI_CONFIG, { name: 'Get Some Information', query: 'NameSpace_FunctionName_1_0_0', data: {}, })) ``` --- URL: https://www.wappi.dev/frontend-integration/request Markdown: https://www.wappi.dev/frontend-integration/request.md # Request Get up and running with wappi-fe in minutes. This guide will walk you through the basic setup and your first API call. ### 1. Import request from wappi-fe ```typescript import { request } from 'wappi-fe' ``` ### 2. Call your API ```typescript const response = async () => (request(WAPPI_CONFIG, { name: 'Get User1234 Information', // This will create a url in your network tab of: GetUser1234Information query: 'NameSpace_FunctionName_1_0_0', data: { // ... body object specific to the query endpoint type }, authRequired: true, })) ``` ## Structure ```typescript interface request { name: string, query: string // The endpoint name. data: any // Strict type of endpoint body results?: { name: string; include?: Array<{ name: string; key: string }> exclude?: Array<{ key: string }> } authRequired?: boolean resultsOnly?: boolean errorCallback?: (x: any) => void successCallback?: (x: any) => void logResults?: boolean logFullResponse?: boolean } ``` #### name: string required This is the specific name of the information you want returned. As multiple requests can be made, this breaks them up. tip: Add a dynamic ID into the name for easy observability Example: `Get info for ${user.name}` #### authRequired: boolean optionally required - depends on query type If true, it will get the auth token that is automatically set. See the Authentication section. #### authRequired: boolean optionally required - depends on query type If true, it will get the auth token that is automatically set. See the Authentication section. #### query: string required This is the name of the function on the server. This function will be the one called. #### data: any optionally required - inherits query Body type An object of the all the data required for the endpoints Body type This data is specific to the function and should be typed in the **NameSpace_FunctionName_1_0_0__Body** type. Typescript should show an error of missing or mis-typed types. #### results: any optional This determines what results you receive. If you leave it as a blank obj or don't include it, it will return everything the function returns. Otherwise you can specify what to include or exclude. ##### name: string optional The name you want the results to return as. Default = results ##### include: object array optional An array of objects, with ##### name: string required The name that you want it to be called. So you can rename it to match your frontend app. ##### key: string required The backend key of the object that you want to include ##### exclude: object array optional An array of objects, with ##### key: string required This is the backend key of the object that you want to exclude from the results. This allows the returned object to be clean to what you need, to help with clarity. Logic for including and excluding is as follows: If nothing is defined in **include**, then everything will be included. If nothing is defined in **exclude**, then nothing will be excluded. If Nothing is defined in **include**, but something is defined in **exclude**, everything defined in **exclude** will be removed. If a key is defined in **include** and in **exclude**, then it will be included Why include and exclude? Usually the processing of the endpoint is faster than the Latency of sending and receiving the data. So you might have an endpoint that can return a lot of data, but you only want 1 piece of it. So instead of creating a new backend function, you can just define what you want returned and get the same result. #### successCallback: function optional On success this will be called with the response object passed in ```typescript successCallback: (response) => { // Logic to do something with the response. console.log('response', response) } ``` #### errorCallback: function optional On error this will be called with the error response ```typescript errorCallback: (errorResponse) => { // Logic to do something with the error. console.error('errorResponse', errorResponse) } ``` #### logResults: boolean optional This will console.log out the results or the name of the results you requested. Handy if you want to inspec the results object. #### logFullResponse: boolean optional This will console.log out the full wappi server response from the endpoint. Handy if you want to check your wappi server response. --- URL: https://www.wappi.dev/frontend-integration/authentication Markdown: https://www.wappi.dev/frontend-integration/authentication.md # Authentication Wappi-fe provides built-in authentication handling to seamlessly manage user sessions and secure API calls. ## How Authentication Works To generate authentication with wappi, you need to add code to your wappi server endpoint called **Core_Login_1_0_0** or any subsequent versions. When this endpoint is called, wappi-fe will set a auth token to localStorage of the browser / device called: wappiAuthToken. This Auth Token will be used as an encrypted authentication between your frontend and backend. If the token is expired, or incorrect. Then endpoint will return: ```typescript success: false ``` ## Using Authentication in the Request When calling request. You only need to pass in the flag #### authRequired: boolean optionally required - depends on query type If true, it will get the auth token that is automatically set. See the Authentication section. ```typescript const response = async () => (request(WAPPI_CONFIG, { name: 'Request', query: 'NameSpace_FunctionName_1_0_0', data: { // ... body object specific to the query endpoint type }, authRequired: true, })) ``` If an endpoint doesn't require auth, then don't include it. ```typescript const response = async () => (request(WAPPI_CONFIG, { name: 'Request', query: 'NameSpace_FunctionName_1_0_0', data: { // ... body object specific to the query endpoint type }, })) ``` --- URL: https://www.wappi.dev/frontend-integration/examples Markdown: https://www.wappi.dev/frontend-integration/examples.md # Examples Real-world examples of using wappi-fe in different scenarios and frameworks. ### Directly in React ```typescript useEffect(() => { if (!user) return; // Wait until the user object is available const authenticateUser = async () => { try { await request(WAPPI_CONFIG, { name: 'Core Login', query: 'Core_Login_2_0_0', data: { userAuth0Sub: user.sub }, successCallback: (x) => { localStorage.removeItem('loginRedirectUrl') reduxDispatch(saveUserAndEnterDashboard(x as UserState)); router.push(forwardToPath); }, errorCallback: () => { toast({ title: 'Error', description: 'We had trouble logging you in. Try again.', status: 'error', duration: 9000, isClosable: true, }); }, }); } catch (error) { console.error(error); } }; authenticateUser(); }, [user, reduxDispatch, toast]); ``` ## In a stand alone file This allows you to create a /API folder and have a lot of reusable calls to your backend. ```typescript import { request } from 'wappi-fe'; import { WAPPI_CONFIG } from './wappiConfig'; export const getAllProducts = async () => request(WAPPI_CONFIG, { name: 'Get Products', query: 'Products_GetAllProducts_3_2_12', data: {}, authRequired: false, errorCallback: (e) => console.error(e.message), }); ``` ```typescript import { request } from 'wappi-fe'; import { WAPPI_CONFIG } from './wappiConfig'; import { User_UpdateUserDetails_2_4_9__Body } from './wappiTypes'; export const updateUserDetails = async ( body: User_UpdateUserDetails_2_4_9__Body ) => request(WAPPI_CONFIG, { name: `Update ${body.userID} Details`, query: 'User_UpdateUserDetails_2_4_9', data: body, authRequired: true, errorCallback: (e) => console.error(e.message), }); export const getUserDetails = async ( reason: string ) => request(WAPPI_CONFIG, { // Uniqueness helps with observability. Ex: Showing user 456 for client 123 on listPage name: reason, query: 'User_GetUserDetails_1_0_0', data: {}, authRequired: true, errorCallback: (e) => console.error(e.message), }); ``` --- URL: https://www.wappi.dev/examples Markdown: https://www.wappi.dev/examples.md # Examples ### Endpoints