What is Wildcard
Wildcard is a JavaScript library to create an API between your Node.js server and your frontend.
With Wildcard, creating an API endpoint is as easy as creating a JavaScript function:
// Node.js server const endpoints = ; // We define a `hello` function on the serverendpoints { return message: 'Welcome '+name;};
// Browser ; async { // Wildcard makes our `hello` function available in the browser const message = await endpoints; console; // Prints `Welcome Alice`};
That's all Wildcard does: it makes functions, that are defined on your Node.js server, "callable" in the browser. Nothing more, nothing less.
How you retrieve/mutate data is up to you; you can use any SQL/NoSQL/ORM query:
// Node.js server const endpoints = ;const getLoggedUser = ;const Todo = ; endpoints { const user = await ; // We talk about `this` later. if !user // The user is not logged-in. // We abort. // (This is basically how you define permissions with Wildcard // which we will talk more about later.) return; // With an ORM/ODM: const newTodo = text authorId: userid; await newTodo; /* Or with SQL: const db = require('your-favorite-sql-query-builder'); const [newTodo] = await db.query( "INSERT INTO todos VALUES (:text, :authorId);", {text, authorId: user.id} ); */ return newTodo;};
Wildcard is new but already used in production at couple of projects, every release is assailed against a heavy suit of automated tests, its author is responsive, and issues are fixed within 1-2 days.
Open a ticket or
chat with us
if you have questions, feature requests, or if you just want to talk to us.
We enjoy talking with our users.
⇧ TOP ⇧
Wildcard compared to REST, GraphQL, and other RPCs
Wildcard is an RPC tool. While REST and GraphQL shine for APIs that are meant to consumed by third parties, RPC is increasingly used for internal APIs, prototypes, and apps with a frontend and backend developed hand-in-hand.
Large companies, such as Netflix and Google, are starting to replace REST/GraphQL with RPC for their internal APIs. Most notably with gRPC which is increasingly popular in the industry.
Both gRPC and Wildcard are RPC tools. While gRPC focuses on cross-platform support (Go, Python, Java, C++, etc.), Wildcard only supports the Browser - Node.js stack. This allows Wildcard to have a simple design (with a mere 1.1K-LOCs) and to be super easy to use.
Wildcard's simplicity and flexibility excel most for prototypes that quickly evolve.
If you are a full-stack JavaScript developer and your frontend is the only consumer of your backend's API, then Wildcard is, compared to REST/GraphQL, superior in virtually every way.
If you are unfamiliar with RPC, then check out RPC vs REST/GraphQL.
Open a ticket or
chat with us
if you have questions, feature requests, or if you just want to talk to us.
We enjoy talking with our users.
⇧ TOP ⇧
Getting Started
This getting started is about adding Wildcard to an exisiting app. If you don't already have an app or if you just want to try out Wildcard, you can use a Reframe starter to quickly get started.
-
Add Wildcard to your Node.js server.
With Express:
// Node.js serverconst express = ;const getApiResponse = ; // npm install wildcard-apiconst app = ;// Parse the HTTP request bodyapp;appall'/wildcard/*' async {// `getApiResponse` requires the HTTP request `url`, `method`, and `body`.const requestProps =url: requrlmethod: reqmethodbody: reqbody;// The `requestProps` object is available in your endpoint functions as `this`.// For example, you can add `req.headers` to `requestProps` to be// able to access it in your endpoint functions as `this.headers`.requestPropsheaders = reqheaders;const responseProps = await ;resstatusresponsePropsstatusCode;restyperesponsePropscontentType;res;};With Hapi
// Node.js serverconst Hapi = ;const getApiResponse = ; // npm install wildcard-apiconst server = Hapi;server;With Koa
// Node.js serverconst Koa = ;const Router = ;const bodyParser = ;const getApiResponse = ; // npm install wildcard-apiconst app = ;// Parse the HTTP request bodyapp;const router = ;routerall'/wildcard/*' async {// `getApiResponse` requires the HTTP request `url`, `method`, and `body`.const requestProps =url: ctxurlmethod: ctxmethodbody: ctxrequestbody;// The `requestProps` object is available in your endpoint functions as `this`.// For example, you can add `ctx.request.headers` to `requestProps` to be// able to access it in your endpoint functions as `this.headers`.requestPropsheaders = ctxrequestheaders;const responseProps = await ;ctxstatus = responsePropsstatusCode;ctxbody = responsePropsbody;ctxtype = responsePropscontentType;};app;With other server frameworks
Wildcard can be used with any server framework. All you have to do is to reply all HTTP requests made to
/wildcard/*
withgetApiResponse
:// Node.js server// This is generic pseudo code for how to integrate Wildcard with any server framework.const getApiResponse = ; // npm install wildcard-apiconst addRoute HttpResponse = ;// Add a new route `/wildcard/*` to your server; -
Define an endpoint function in Node.js:
// Node.js serverconst endpoints = ;endpoints {// The `this` object is the `requestProps` object we passed to `getApiResponse`. Because// the headers are set on `requestProps.headers`, we can access them over `this.headers`.// You can then, for example, use the headers for authentication.console;return msg: 'hello from my first Wildcard endpoint';; -
You can now "call" your enpdoint function from you frontend:
// Browser; // npm install wildcard-apiasync {const msg = await endpoints;console;};
Open a ticket or
chat with us
if you have questions, feature requests, or if you just want to talk to us.
We enjoy talking with our users.
⇧ TOP ⇧
Authentication
Authentication usually uses HTTP headers
such as Authorization: Bearer AbCdEf123456
or a cookie holding the user's session ID.
You can access the HTTP request headers in your endpoint functions by passing the headers
object to getApiResponse
:
// Node.js server appall'/wildcard/*' async { const requestProps = url: requrl method: reqmethod body: reqbody // We pass the `headers` object headers: reqheaders ; const responseProps = await ; resstatusresponsePropsstatusCode; restyperesponsePropscontentType; res;};
Wildcard makes requestProps
available to your endpoint function as this
:
// Node.js server const endpoints = ;const getUser = ; endpoints { // Since `this===requestProps`, `requestProps.headers` is available as `this.headers`. const user = await ; return user;};
If you do SSR, an additional step needs to be done in order to make authentication work, see SSR & Authentication.
Open a ticket or
chat with us
if you have questions, feature requests, or if you just want to talk to us.
We enjoy talking with our users.
⇧ TOP ⇧
Permissions
Permission is defined by code. For example:
// Node.js server const endpoints = ;const getLoggedUser = ;const db = ; // The following endpoint showcases how to implement permissions with Wildcard.// The endpoint only allows the author of a todo-item to modify it. endpoints { if !user // The user is not logged-in. // We abort. return; const todo = await db; if !todo // `todoId` didn't match any todo. // We abort. return; if todoauthorId !== userid // The user is not the author of the to-do item. // We abort. return; // The user is logged-in and is the author of the todo. // We commit the new to-do text. await db;};
See the to-do list app example for further permission examples.
Open a ticket or
chat with us
if you have questions, feature requests, or if you just want to talk to us.
We enjoy talking with our users.
⇧ TOP ⇧
Error Handling
Calling an endpoint throws an error when:
- The browser cannot connect to the server. (The user is offline or your server is down.)
- The endpoint function throws an uncaught error.
If you use a library that is expected to throws errors, then catch them:
// Node.js server const endpoints = ;const validatePhoneNumber = ; endpoints { // `validatePhoneNumber` throws an error if `phoneNumber` is not a phone number. let err; try ; catcherr_ err = err_ if err return validationError: phoneNumber: "Please enter a valid phone number."; /* ... */};
You should always catch expected errors: Wildcard treats any uncaught error as a bug in your code.
In particular, don't throw an error upon validation failure:
// Node.js server const endpoints = ;const isStrongPassword = ; endpoints { /* Don't do this: if( !isStrongPassword(password) ){ throw new Error("Password is too weak."); } */ // Instead, return a JavaScript value, e.g. a JavaScript object: if ! return validationError: "Password is too weak."; /* ... */};
You can use isServerError
and isNetworkError
to handle errors more precisely:
// Browser ; { let data; let err; try data = await endpoints; catcherr_ err = err_; if errisServerError // Your endpoint function throwed an uncaught error: there is a bug in your server code. ; if errisNetworkError // The browser couldn't connect to the server. // The user is offline or your server is down. ; if err return success: false; else return success: true data; }
You can also use Handli which will automatically handle errors for you:
// Browser ; // npm install handli// That's it: Wildcard will automatically use Handli.// Errors are now handled by Handli.
Open a ticket or
chat with us
if you have questions, feature requests, or if you just want to talk to us.
We enjoy talking with our users.
⇧ TOP ⇧
SSR
The Wildcard client is isomorphic (aka universal) and works in the browser as well as in Node.js.
If you don't need authentication, then SSR works out of the box.
Otherwise read SSR & Authentication.
Open a ticket or
chat with us
if you have questions, feature requests, or if you just want to talk to us.
We enjoy talking with our users.
⇧ TOP ⇧
Options
ℹ️ If you need an option that Wildcard is missing, then open a new GitHub issue. We usually implement new options within 1-2 days.
Overview of all options:
; const endpoints = // The URL of the Node.js server that serves the API serverUrl: null // Default value // Whether the endpoint arguments are always passed in the HTTP body argumentsAlwaysInHttpBody: false // Default value;
More details about each option:
serverUrl
Wildcard automatically determines the adress of the server and you
don't need to provide serverUrl
.
But if the Node.js server that serves the API is not the same server that serves your browser-side assets,
then you need to provide serverUrl
.
For example:
;// (Or `const {WildcardClient} = require('wildcard-api/client');`); const endpoints = serverUrl: 'https://api.example.com:1337'; ; { await endpoints; ; // Normally, Wildcard makes HTTP requests to the same origin: // POST https://example.com/wildcard/myEndpoint HTTP/1.1 // But because we have set `serverUrl`, Wildcard makes // the HTTP requests to `https://api.example.com:1337`: // POST https://api.example.com:1337/wildcard/myEndpoint HTTP/1.1};
argumentsAlwaysInHttpBody
argumentsAlwaysInHttpBody
is about configuring whether
arguments are always passed in the HTTP request body.
(Instead of being passed in the HTTP request URL.)
For example:
;// (Or `const {WildcardClient} = require('wildcard-api/client');`) const endpoints = argumentsAlwaysInHttpBody: true; ; { await endpoints; // Normally, Wildcard passes the arguments in the HTTP request URL: // POST /wildcard/myEndpoint/[{"some":"arguments"},"second arg"] HTTP/1.1 // But because we have set `argumentsAlwaysInHttpBody` to `true`, // Wildcard passes the arguments in the HTTP request body instead: // POST /wildcard/myEndpoint HTTP/1.1 // Request payload: [{"some":"arguments"},"second arg"]};
Open a ticket or
chat with us
if you have questions, feature requests, or if you just want to talk to us.
We enjoy talking with our users.
⇧ TOP ⇧
More Resources
This section collects further information about Wildcard.
-
SSR & Authentication
How to use Wildcard with SSR and Authentication. -
How Does It Work
Explains how Wildcard works. -
Conceptual FAQ
High level discussion about Wildcard, RPC APIs, GraphQL, and REST. -
To-do List Example
An example of a to-do list app implemented with Wildcard. -
Custom VS Generic
Goes into depth of whether you should implement a generic API (REST/GraphQL), or a custom API (Wildcard), or both. In general, the rule of thumb for deciding which one to use is simple: if third parties need to access your data, then implement a generic API, otherwise implement a custom API. But in certain cases it's not that easy and this document goes into more depth.
Open a ticket or
chat with us
if you have questions, feature requests, or if you just want to talk to us.
We enjoy talking with our users.
⇧ TOP ⇧