Introducing Socket Firewall: Free, Proactive Protection for Your Software Supply Chain.Learn More
Socket
Book a DemoInstallSign in
Socket

@apparts/api

Package Overview
Dependencies
Maintainers
1
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@apparts/api

A unified API package for @apparts

latest
npmnpm
Version
6.2.0
Version published
Maintainers
1
Created
Source

#+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, ApiFnParams } 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 api = useApi(MyRequest);

const get = (...ps: ApiFnParams) => api.get(...ps) as unknown as MyRequest, put = (...ps: ApiFnParams) => api.put(...ps) as unknown as MyRequest, patch = (...ps: ApiFnParams) => api.patch(...ps) as unknown as MyRequest, post = (...ps: ApiFnParams) => api.post(...ps) as unknown as MyRequest, del = (...ps: ApiFnParams) => api.del(...ps) as unknown as 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[], {

    // includePaths?: string[][];
    // Can be used to only include a subset of the routes in the output
    
    // excludePaths?: string[][];
    // Can be used to exclude a subset of the routes from the output
    
    // emitNoSchema?: boolean;
    // If true, schemas will not be generated, but typescript types still will be. (default: false)
    

    }))); #+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

Keywords

apparts

FAQs

Package last updated on 23 Sep 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts