From bb39b4e8fad83872b2e5067588325bfc0bdfd554 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 10 Aug 2018 17:19:01 +0200 Subject: [PATCH] Add rest client --- .../framework/lib/bootstrap/TalkContext.tsx | 4 ++ .../framework/lib/bootstrap/createContext.tsx | 2 + src/core/client/framework/lib/rest.ts | 57 +++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 src/core/client/framework/lib/rest.ts diff --git a/src/core/client/framework/lib/bootstrap/TalkContext.tsx b/src/core/client/framework/lib/bootstrap/TalkContext.tsx index 75ddc974c..e25746c52 100644 --- a/src/core/client/framework/lib/bootstrap/TalkContext.tsx +++ b/src/core/client/framework/lib/bootstrap/TalkContext.tsx @@ -6,6 +6,7 @@ import { MediaQueryMatchers } from "react-responsive"; import { Formatter } from "react-timeago"; import { Environment } from "relay-runtime"; +import { RestClient } from "talk-framework/lib/rest"; import { UIContext } from "talk-ui/components"; import { ClickFarAwayRegister } from "talk-ui/components/ClickOutside"; @@ -22,6 +23,9 @@ export interface TalkContext { /** media query values for testing purposes */ mediaQueryValues?: MediaQueryMatchers; + /** Rest client */ + rest: RestClient; + /** * A way to listen for clicks that are e.g. outside of the * current frame for `ClickOutside` diff --git a/src/core/client/framework/lib/bootstrap/createContext.tsx b/src/core/client/framework/lib/bootstrap/createContext.tsx index 2e6bd2aff..75c2dcc01 100644 --- a/src/core/client/framework/lib/bootstrap/createContext.tsx +++ b/src/core/client/framework/lib/bootstrap/createContext.tsx @@ -6,6 +6,7 @@ import React from "react"; import { Formatter } from "react-timeago"; import { Environment, Network, RecordSource, Store } from "relay-runtime"; +import { RestClient } from "talk-framework/lib/rest"; import { ClickFarAwayRegister } from "talk-ui/components/ClickOutside"; import { generateMessages, LocalesData, negotiateLanguages } from "../i18n"; @@ -99,6 +100,7 @@ export default async function createContext({ pym, eventEmitter, registerClickFarAway, + rest: new RestClient("/api"), }; // Run custom initializations. diff --git a/src/core/client/framework/lib/rest.ts b/src/core/client/framework/lib/rest.ts new file mode 100644 index 000000000..b8ccdccab --- /dev/null +++ b/src/core/client/framework/lib/rest.ts @@ -0,0 +1,57 @@ +import merge from "lodash/merge"; +import { Overwrite } from "talk-framework/types"; + +const buildOptions = (inputOptions: RequestInit = {}) => { + const defaultOptions: RequestInit = { + method: "GET", + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + credentials: "same-origin", + }; + const options = merge({}, defaultOptions, inputOptions); + if (options.method!.toLowerCase() !== "get") { + options.body = JSON.stringify(options.body); + } + return options; +}; + +const handleResp = (res: Response) => { + if (res.status > 399) { + return res.json().then((err: any) => { + // TODO: sync error handling with server. + const message = err.message || res.status; + const error = new Error(message); + throw error; + }); + } else if (res.status === 204) { + return res.text(); + } else { + return res.json(); + } +}; + +type PartialRequestInit = Overwrite, { body: any }>; + +export class RestClient { + public readonly uri: string; + private tokenGetter?: () => string; + + constructor(uri: string, tokenGetter?: () => string) { + this.uri = uri; + this.tokenGetter = tokenGetter; + } + + public fetch(path: string, options: PartialRequestInit): Promise { + let opts = options; + if (this.tokenGetter) { + opts = merge({}, options, { + headers: { + Authorization: `Bearer ${this.tokenGetter()}`, + }, + }); + } + return fetch(`${this.uri}${path}`, buildOptions(opts)).then(handleResp); + } +}