d-velop / dvelop-sdk-node

Official SDK to build Apps for d.velop cloud
Apache License 2.0
10 stars 14 forks source link

dvelop-sdk-node

GitHub

Apps

npm (scoped) npm (scoped) npm (scoped) npm (scoped) npm (scoped)

Utilities

npm (scoped) npm (scoped)

Explore the docs » Explore on npm »


About

This is the official SDK to build apps for d.velop cloud using node.js and typescript.

Getting started

This SDK is diveded into apps. Install individual packages per d-velop app you want to use.

npm i @dvelop-sdk/dms
import { Repository, getRepository } from "@dvelop-sdk/dms";

(async function main() {

  const repo: Repository = await getRepository({
    systemBaseUri: "https://steamwheedle-cartel.d-velop.cloud",
    authSessionId: "dQw4w9WgXcQ"
  }, {
    repositoryId: "qnydFmqHuVo",
  });

  console.log(repo.name); // Booty Bay Documents
})();
npm i @dvelop-sdk/task
import { createTask } from "@dvelop-sdk/task";

(async function main() {

  const taskLocation = await createTask({
    systemBaseUri: "https://umbrella-corp.d-velop.cloud",
    authSessionId: "dQw4w9WgXcQ"
  }, {
    subject: "Cover up lab accident",
    assignees: ["XiFkyR35v2Y"]
  });

  console.log(taskLocation); // some/task/location
})();

You can also run them in ES6 javascript without typescript:

npm i @dvelop-sdk/dms
//package.json
{
  "type":"module"
}
//main.js

import { Repository, getRepository } from "@dvelop-sdk/dms";

async function main() {

  const repo = await getRepository({
    systemBaseUri: "https://steamwheedle-cartel.d-velop.cloud",
    authSessionId: "dQw4w9WgXcQ"
  }, {
    repositoryId: "qnydFmqHuVo",
  });

  console.log(repo.name); // Booty Bay Documents
}

await main();
Explore the docs »


Build a d.velop app in no time with express

This SDK was designed framework agnostic but with express in mind.

Install dependencies:

npm i express cookie-parser @dvelop-sdk/express-utils
npm i typescript @types/express @types/cookie-parser -D

Be sure to set the esModuleInterop-flag for typescript:

//tsconfig.json

{
  "compilerOptions": {
    "esModuleInterop": true,
    // ...
  }
}

Set up your app:


import express, { Application, NextFunction, Request, Response } from "express"
import cookieParser from "cookie-parser";
import { authenticationMiddleware, contextMiddleware, validateSignatureMiddlewareFactory, InvalidRequestSignatureError, UnauthorizedError, redirectToLoginPage } from "@dvelop-sdk/express-utils";

const app: Application = express();
const appName: string = "acme-myapp";
const appPort: number = 5000;

app.use(cookieParser());
app.use(contextMiddleware); // Make the req.dvelopContext-property available
app.use(validateSignatureMiddlewareFactory(process.env.APP_SECRET)); // Check the d.velop signature.

app.get(`/${appName}/me`, authenticationMiddleware, (req: Request, res: Response) => {
  res.status(200).send(`<h1>Hello ${req.dvelopContext.user.displayName}</h1>`);
});

app.get(`/${appName}`, (req: Request, res: Response) => {
  res.status(200).send(`<h1>Hello Tenant ${req.dvelopContext.systemBaseUri} (${req.dvelopContext.tenantId})</h1>`);
});

app.use((err: any, req: Request, res: Response, _: NextFunction) => {
  if (err instanceof InvalidRequestSignatureError) {
    res.status(403).send("Forbidden"); // Indicates a problem with the App-Secret
  } else if (err instanceof UnauthorizedError) {
    redirectToLoginPage(req, res); // Not authenticated => send to IDP login-page
  } else {
    console.log(err);
    res.status(500).send("Internal Server Error");
  }
});

app.listen(appPort, () => {
  console.log(`D.velop app listening on port ${appPort} ...`);
});

Don't forget to set your APP_SECRET and then start your app:

npx tsc && node src/main.js

The req.dvelopContext-property can now be used for other SDK-functions.

Explore the docs »


Advanced Topics

Under the hood this SDK uses a functional programming approach. Generally all top-level SDK methods are created by factory-methods. This allows to inject default implementations and at the same time give consumers next-to-full control over steps taken.

SDK-functions usually have at two seperate steps:

Let's look at the getRepository-factoryFunction:

export function getRepositoryFactory<T>(
  httpRequestFunction: (context: DvelopContext, config: HttpConfig) => Promise<HttpResponse>,
  transformFunction: (response: HttpResponse, context: DvelopContext, params: GetRepositoryParams) => T,
): (context: DvelopContext, params: GetRepositoryParams) => Promise<T> {
  return async (context: DvelopContext, params: GetRepositoryParams) => {
    const response: HttpResponse = await httpRequestFunction(context, {
      method: "GET",
      url: "/dms",
      follows: ["repo"],
      templates: { "repositoryid": params.repositoryId }
    });
    return transformFunction(response, context, params);
  };
}

export async function getRepository(context: DvelopContext, params: GetRepositoryParams): Promise<Repository> {
  return getRepositoryFactory(defaultHttpRequestFunction, getRepositoryDefaultTransformFunction)(context, params);
}

The getRepository-function itself is a function in the form of

(context: DvelopContext, params: GetRepositoryParams) => Promise<Repository>

The getRepository-factoryFunction is a function that returns this function. As input it requires two functions itself that are used:

The exported getRepository-function itself is created by this factory with default implementations. This gives you control over the individual tasks done by the method.

All DvelopHttp-stuff is provided by the @dvelop-sdk/core package. At the moment it mostly wraps axios as its main http-framework.

Contributing

This project is maintained by d-velop but is looking for contributers. If you consider contributing to this project please read CONTRIBUTING for details on how to get started.

License

Please read LICENSE for licensing information.

Acknowledgments

Thanks to the following projects for inspiration