npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@apparts/api

v4.1.0

Published

A unified API package for @apparts

Downloads

44

Readme

#+TITLE: @apparts/api #+DATE: [2019-02-07 Thu] #+AUTHOR: Philipp Uhl

  • Setup

To tell the =@apparts/api= package, how to work with your API, you have to overload the =Request= class. If you are using tokens for users to be authenticated (e.g. when using =@apparts/login-server=) you also need to overload the =Token= class and tell the =Request= class to use the =Token= class in a custom authentication method (compare =authUser= below).

Finally, give your new =Request= class to =useApi= and export the functions that you recieve.

#+BEGIN_SRC js import {useApi, Token, Request} from "@apparts/api";

const APIVERSION = 1; const URL = DEV // eslint-disable-line no-undef ? "https://devendpoint/v/" : "https://prodendpoint/v/";

const logout = () => { // Log out user on 401 HTTP-Error window.location.href = "/login?force=true"; };

class MyToken extends Token { constructor(user) { super(user);

  // Tell Token where to find the users api token, should you
  // already have one
  this._apiToken = user.apiToken;
}

async renewAPIToken(user) {
  // Tell Token how to renew the API Token
  const apiToken = await get("user/apiToken").authPW(
    user.email,
    user.loginToken
  );
  return apiToken;
}

static getUserKey(user) {
  // Tell Token how to identify users
  return user.email;
}

}

class MyRequest extends Request { getURL(apiVersion) { // Tell Request what the URL prefix is return URL + apiVersion; } getAPIVersion() { // Tell Request what the default APIVersion is return APIVERSION; }

online() {
  // Will be called, when a network-call succeded
}

authUser(user) {
  // Define a method for authenticating with a user token.
  // This will be called by you, when you want to authenticate with a user
  this._auth = MyToken.getAPIToken(user);
  return this;
}

async middleware() {
  // Tell Request what to do on recieving not-yet caught errors, that should be
  // handled globally.

  this.on(410, () => alert("Your website is out of date, please reload it."));
  this.on({ status: 401, error: "Token invalid" }, () => { throw "Invalid token"; });
  this.on(401, logout);
  this.on(0, () => alert("We could not reach the server. Are you online?"));
}

}

const { get, put, patch, post, del } = useApi(MyRequest); export { get, put, patch, post, del }; #+END_SRC

  • Usage

The functions =get=, =put=, =patch=, =post=, =del= have this signature (exemplary for =get=):

  • =get(url: , urlParams: <+array>): Request= :: The url can be parameterized with =$1=, =$2=, ... Each =$=-prefixed number will be replaced with the corresponding element from the array: =$1= will be replaced with =urlParams[0]=, =$2= with =urlParams[1]=, and so on. A parameter can be used multiple times in the =url=-string. If not all or too many parameters are used, an error will be thrown.

The functions =get=, =put=, =patch=, =post=, =del= return a =Request=. Requests have the following methods:

  • =query(params: ): Request= :: Set query params as key value pairs. : r.query({ filter: "4", a: "b" }) // will be https://yourendpoint/path/to/endpoint?filter=4&a=b
  • =data(data: ): Request= :: Set the body data
  • =settings(settings: ): Request= :: Set =axios= settings
  • =v(v: int): Request= :: Overwrite APIVersion, used for this request
  • =auth(auth: ): Request= :: Set the =axios=-auth param
  • =authPW(username: , password: ): Request= :: Use basic auth
  • =authAPIKey(token: ): Request= :: Use bearer auth
  • =on(status: <int | object>, next: ): Request= :: Attach an error handler:
    • Status parameter:
      • If used with =status= as an integer, matches all HTTP-Errors with that status.
      • If used with =status= as an object of the form ={ status: , error: }=, matches all HTTP-Errors with that status and an object with a matching error-key in the body.
    • When such an error occurs, =next(errorJson, error)= will be called with =errorJson= being the parsed error and =error= the raw =axios= error.
    • Multiple error catchers can be appended. The first one to match (in order of attaching) will be executed.
    • When error has been caught, =catch= will be called, but receives =false= as an error.
  • =then(): Promise= :: Then
  • =catch(): Promise= :: Catch
  • =finally(): Promise= :: Finally

Example:

#+BEGIN_SRC js try { const resp = await put("users/$1/name") .data({ name: "John" }) .userAuth(user) .on({ status: 400, error: "Too short" }, () => { alert("Please choose a longer username."); }) .on({ status: 400, error: "Is taken" }, () => { alert("This username is taken, already. Please choose a different username."); }); } catch (e) { // If e is not false, then, no error-catcher caught the error and // you might want to take care of it e && alert(e);

// Do, what you have to do on an error. Catch will be called, even
// when the error was caught by an error catcher. If you have some
// error-unspecific cleanup to do, this would be a good place:

/* setLoading(false); */

} #+END_SRC

  • Generate API SDK

=@apparts/api= supports generating a fully typed TypeScript SDK to access an API that is defined through an API description as generated by =@apparts/prep=.

You might want to install =prettier= (=npm i -D prettier=) to improve the output.

To generate the SDK, run the following:

#+BEGIN_SRC js import * as prettier from "prettier"; const prettify = (src) => prettier.format(src, { parser: "typescript" });

// The API definition as output by the getApi function from @apparts/prep import { testApi } from "./api-description.json"; import { genFile, EndpointDefinition } from "@apparts/api";

// Pipe to file or write to fs from here console.log(prettify(genFile(testApi.routes as EndpointDefinition[]))); #+END_SRC

The resulting API SDK code exports the function =createApi= which expects one parameter: the api as exported from =useApi(MyRequest)= as setup above.

In your application:

#+BEGIN_SRC js import { createApi } from "./"

// setup MyRequest, etc. const apiRaw = useApi(MyRequest); export const api = createApi(apiRaw); #+END_SRC

The resulting api object contains all API endpoints in the following manner:

An endpoint =GET /v/1/user/:userId/info= with the returns

  • code 200, ==
  • code 404, ={ error: "User not found" }=
  • code 404, ={ error: "User info not found" }=

Can be accessed like this:

#+BEGIN_SRC js try { const res = await api.user.info.get({ params: { userId }, /* data, query /}) // Optional error catchers. Matching checked in order of function // usage. So in this example, first the catcher for { status: 404, // error: "user not found" } is checked, then { status: 404, error: // "user info not found" }, at last all status 404 responses. .on404UserNotFound(/ catcher fn /) .on404UserInfoNotFound(/ catcher fn /) .on404(/ catcher fn */) // catch all for code 404

// a Request object is returned, just with the normal
// get/put/post/etc functions from this package. Hence, you can call
// all helper functinos as wanted. E.g.:
      .auth(user);

} catch (e) { // If e is not false, then, no error-catcher caught the error and // you might want to take care of it e && alert(e); } #+END_SRC