Developers
  1. /SDK
  2. /Getting Started
SDK

Getting Started

A step-by-step guide to the Navigraph SDK for TypeScript/JavaScript implementations of Navigraph APIs and services.

If you don't feel like reading a guide on how to implement our SDK and would rather get hacking on your own, feel free to check out the complete example below!

Note: The demo requires that you have valid Navigraph client credentials.

Edit navigraph-sdk-demo

1. Setup projectRead the “1. Setup project” section

First, scaffold a project in your favorite flashy framework. For this guide, we'll use Vite to quickly bootstrap a React project.

New Vite AppRead the “New Vite App” section

Create a new Vite app using your package manager of choice. In this guide, we'll use yarn as package manager and we'll pick the react-ts template from the available options.

yarn create vite navigraph-sdk-tutorial --template react-ts

This will create a navigraph-sdk-tutorial directory. Switch to said directory:

cd navigraph-sdk-tutorial

2. Install the Navigraph JS SDKRead the “2. Install the Navigraph JS SDK” section

Install the navigraph package from NPM along with a library that can turn content into QR codes, such as qrcode.react.

yarn add navigraph qrcode.react

3. Set up the SDKRead the “3. Set up the SDK” section

Create an entrypoint for the Navigraph SDK in your application. This can be done by creating a lib/navigraph.ts file and filling it with the following:

src/lib/navigraph.ts
import { initializeApp, Scope, NavigraphApp } from "navigraph/app";

const config: NavigraphApp = {
  clientId: "<YOUR_NAVIGRAPH_CLIENT_ID>",
  clientSecret: "<YOUR_NAVIGRAPH_CLIENT_SECRET>",
  scopes: [Scope.OFFLINE, Scope.CHARTS],
};

initializeApp(config);

This will bootstrap the SDK with the necessary credentials and scopes needed for further interaction. However, before you can interact with any of Navigraph's APIs, you will need to sign in. The next step will be to set up the authentication module.

Configure authenticationRead the “Configure authentication” section

The authentication module can be configured by calling getAuth(), as imported from navigraph/auth. Optionally, you can pass an object containing additional implementation details:

storageRead the “storage” section

The storage solution to use. Defaults to localStorage, which might not be preferable/available in your environment.

keysRead the “keys” section

The keys to use when storing the access/refresh tokens.

src/lib/navigraph.ts
//...

export const auth = getAuth({
  storage: { // Optional
    getItem: (key) => localStorage.getItem("NG" + key),
    setItem: (key, value) => localStorage.setItem("NG" + key, value),
  },
  keys: { // Optional
    accessToken: "ACCESS_TOKEN",
    refreshToken: "REFRESH_TOKEN",
  },
});

Configure API modulesRead the “Configure API modules” section

Currently only the Charts API is exposed through the SDK. This module is very simple to set up:

src/lib/navigraph.ts
//...

export const charts = getChartsAPI();

4. Set up the UIRead the “4. Set up the UI” section

In order to start using the SDK, you'll need to let the user authenticate themselves. To do this in React, we'll set up a useNavigraphAuth hook that utilizes the authentication module from earlier.

src/hooks/useNavigraphAuth.tsx
import { User } from "navigraph/auth";
import React, { useState, useEffect, useContext, createContext } from "react";
import { auth } from "../../src/lib/navigraph";

interface NavigraphAuthContext {
  initialized: boolean;
  user: User | null;
  signIn: typeof auth.signInWithDeviceFlow;
}

const authContext = createContext<NavigraphAuthContext>({
  initialized: false,
  user: null,
  signIn: () => Promise.reject("Not initialized")
});

// Provider hook that creates auth object and handles state
function useProvideAuth() {
  const [user, setUser] = useState<User | null>(null);
  const [initialized, setinitialized] = useState(false);

  // Subscribe to user on mount
  // Because this sets state in the callback it will cause any
  // component that utilizes this hook to re-render with the latest auth object.
  useEffect(() => {
    const unsubscribe = auth.onAuthStateChanged((u) => {
      if (!initialized) setinitialized(true);
      setUser(u);
    });
    // Cleanup subscription on unmount
    return () => unsubscribe();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  return {
    user,
    initialized,
    signIn: auth.signInWithDeviceFlow
  };
}

// Provider component that wraps your app and makes auth object
// available to any child component that calls useAuth().
export function NavigraphAuthProvider({
  children
}: {
  children: React.ReactNode;
}) {
  const auth = useProvideAuth();
  return <authContext.Provider value={auth}>{children}</authContext.Provider>;
}

// Hook for child components to get the auth object
// and re-render when it changes.
export const useNavigraphAuth = () => {
  return useContext(authContext);
};

In the above example, we're using a useEffect hook to subscribe to the onAuthStateChanged callback in the authentication module. This callback fires whenever the module registers a change to the authenticated user.

When the page is first loaded, the authentication module will try to resume any previously persisted session. If it is unsuccessful, the onAuthStateChanged callback will be fired with a value of null. If instead it is successful in restoring a session, the callback will be fired with the details of the authenticated user.

The above stays true for when a sign-in process is completed using signInWithDeviceFlow().

In order to make use of this hook, we first need to wrap the application in the just created NavigraphAuthProvider component.

src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./index.css";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <NavigraphAuthProvider>
      <App />
    </NavigraphAuthProvider>
  </React.StrictMode>
);

Now we can go ahead and build a very simple UI that allows the user to sign in using the device flow.

By mounting the hook that we just created, we can now easily sign in by calling the signIn function that it returns. This function takes a single argument, which is a callback that will be called once the sign-in process is started.

In it, you will receive all necessary information to display a link or QR code that the user can interact with to complete the authorization.

src/App.tsx
import React, { useState } from "react";
import QRCode from "qrcode.react";
import { DeviceFlowParams } from "navigraph/auth";
import { useNavigraphAuth } from "./hooks/useNavigraphAuth";

function App() {
  const [params, setParams] = useState<DeviceFlowParams | null>(null);

  const { user, signIn, initialized } = useNavigraphAuth();

  const handleSignIn = () => signIn((p) => setParams(p));

  return (
    <main>
      <h2>Navigraph SDK Demo</h2>

      {!initialized && <div>Loading...</div>}

      {initialized && !params && !user && (
        <button onClick={handleSignIn}>
          Sign in
        </button>
      )}

      {params?.verification_uri_complete && !user && (
        <>
          <QRCode value={params.verification_uri_complete} size={250} />
          <a
            href={params.verification_uri_complete}
            target="_blank"
            rel="noreferrer"
          >
            Open sign in page
          </a>
        </>
      )}

      {user && (
        <h2>
          Welcome, <strong>{user.preferred_username}</strong>
        </h2>
      )}
    </main>
  );
}

export default App;

Let's break the above down a little bit. First, we have a useNavigraphAuth hook that returns the following:

  • user: The authenticated user, if any.
  • signIn: A function that starts the sign-in process.
  • initialized: A boolean that indicates whether the authentication module has fully initialized.

Then, for the presentation, we begin by rendering a Loading... text if the authentication module is not yet initialized. This should only be visible for a very short amount of time.

We then check if the authentication module has fully initialized. If it has, we check if there is an ongoing sign-in attempt by looking at the params state. If no sign-in attempt is in progress, and no user is authenticated (as indicated by the user state), we render a button that will start the sign-in process.

<>
  {initialized && !params && !user && (
    <button onClick={handleSignIn}>Sign in</button>
  )}
</>

In the next section, we handle the presentation of vital UI elements for the authentication process. This is done by checking if the params state is set and that it contains a verification_uri_complete property. If it does, the value of said key can be used to render a QR code or a direct link to the sign-in page.

<>
  {params?.verification_uri_complete && !user && (
    <>
      <QRCode value={params.verification_uri_complete} size={250} />
      <a href={params.verification_uri_complete} target="_blank">
        Open sign in page
      </a>
    </>
  )}
</>

Finally, in the last section, we conditionally show a welcome message when a user has been authenticated. As previously mentioned, this is done by verifying that the user state is set (non-null).

<>
  {user && (
    <h2>
      Welcome, <strong>{user.preferred_username}</strong>
    </h2>
  )}
</>

Next stepsRead the “Next steps” section

For a more detailed specification of the SDK, see the API reference (coming soon). Also, feel free to check out an extended example over on CodeSandbox!

Note: The demo requires that you have valid Navigraph client credentials.

Edit navigraph-sdk-demo