Papupata Documentation

Guide: accessing metadata

Overview

Papupata allows you to declare, call and implement APIs. Sometimes you need to do something slightly different though and need access to information about the API. This guide helps you with that.

Table of contents

To begin with

It might be helpful fairly solid understanding of what papupata API declarations look like.

In the examples presented in this guide, the following API declaration is assumed to be in the scope:

Older styles are still supported in later versions, just not preferred.
const complexAPI = API.declarePostAPI('/update/:id', routeOptions)
  .params({id: String})
  .query({author: String, notifyWatchers: Boolean}})
  .optionalQuery({timestamp: String})
  .body<{ name: string}>()
  .response<{status: string }>()

URLs and methods

The most basic things, path and method as specified when declared the API can be accessed directly from the api object.

const {method, path} = complexAPI
// method: post
// path: /update/:id

The path might not be quite what you need though. Perhaps you want a full URL, with path and possibly query parameters already in place. This can be done with the getURL method. Do note that the method requires baseURL to be configured.

Older styles are still supported in later versions, just not preferred.
API.updateConfig({
  baseURL: 'https://www.example.com'
})
console.log(complexAPI.getURL({id: '123'}))
// https://www.example.com/update/123

console.log(complexAPI.getURL({id: '123', author: 'Bob'}))
// https://www.example.com/update/123?author=Bob

Path and query parameters

The names and types of path and query parameters are accessible from the apiUrlParameters property of the api.

const {(params, query, optionalQuery, boolQuery)} = api.apiUrlParameters
The are tuples in nature, but can be treated as arrays of strings.

Types

This is where things get a little bit more interesting. You can't just export types from and object in typescript, but that's what an API is. Papupata uses a workaround for this problem which looks odd at first, but you get used to it quickly enough. That is, the api exports values that as far as typescript is concerned match the various types used by papupata, allowing the use of typeof operator to access the actual type.

Response

Let's start with the type of the response.

const ApiResponseType = typeof complexApi.ResponseType

In situations where the type of the response returned by the implementation is different from the one observed by the client, ServerResponseType indicates the type the server is expected to return. If unspecified by the declaration, this is the same as responseType.

type ApiResponseTypeOnClient = typeof complexApi.ResponseType
type ApiResponseTypeOnServer = typeof complexApi.ServerResponseType
Body

The body for the request follows the same pattern in the opposite direction, with BodyType being the one observed by the server and CallBodyType being the one used for API calls.

type BodyTypeOnClient = typeof complexApi.CallBodyType
type BodyTypeOnServer = typeof complexApi.BodyType
Request

The papupata request is an express request, possibly modified with your own fields as provided on the API declaration, but more importantly it has explicit types for params, query and body. You can access the request type for a specific API using its RequestType property.

type RequestType = typeof complexApi.RequestType

This can be especially useful when you want to use a named function as the implementation for an API.

Implementation

You can get access to the current implementation and its middleware from the API. The primary use for this is for unit testing, but a clever individual can undoubtedly come up with other uses as well.

const {implementation, implementationMiddleware} = complexApi