Skip to content

Commit 8beebb7

Browse files
Add api endpoint
1 parent d0b396e commit 8beebb7

File tree

14 files changed

+74
-14
lines changed

14 files changed

+74
-14
lines changed

config/webpack.config.client.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ const { ReactLoadablePlugin } = require("react-loadable/webpack");
33

44
module.exports = {
55
// The main entry point of the application
6-
entry: {
7-
main: path.join(__dirname, "..", "source", "client")
8-
},
6+
entry: ["babel-polyfill", path.join(__dirname, "..", "source", "client")],
97

108
// Main entry point plus each dynamic import generate a bundle
119
// Ex: import(/* webpackChunkName: "hello" */"../components/hello") generate hello.js

config/webpack.config.server.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ module.exports = {
99
externals: [nodeExternals()],
1010

1111
// The main entry point of the server application
12-
entry: {
13-
main: path.join(__dirname, "..", "source", "server")
14-
},
12+
entry: ["babel-polyfill", path.join(__dirname, "..", "source", "server")],
1513

1614
// Generated bundle location
1715
output: {

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
"author": "Nicolas Hémonic",
1919
"license": "MIT",
2020
"dependencies": {
21+
"axios": "^0.18.0",
22+
"babel-polyfill": "^6.26.0",
2123
"express": "^4.16.3",
2224
"react": "^16.3.0",
2325
"react-dom": "^16.3.0",

source/client/index.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import "babel-polyfill";
2+
13
import React from "react";
24
import ReactDOM from "react-dom";
35
import Loadable from "react-loadable";

source/server/index.tsx

+15
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import "babel-polyfill";
2+
13
import express, { Request, Response } from "express";
24
import React from "react";
35
import ReactDOMServer from "react-dom/server";
@@ -6,6 +8,7 @@ import { getBundles, IReactLoadableWebpackBundle } from "react-loadable/webpack"
68
import { Provider } from "react-redux";
79
import { matchPath, StaticRouter } from "react-router";
810

11+
import { setApiUrls } from "../universal/actions";
912
import App from "../universal/app";
1013
import { IState } from "../universal/models";
1114
import { routes } from "../universal/routes";
@@ -15,12 +18,24 @@ const stats = require("./reactLoadable.json");
1518
const app = express();
1619

1720
app.use("/client", express.static("client"));
21+
22+
app.use("/api/description", function(req, res) {
23+
res.setHeader("Content-Type", "application/json");
24+
setTimeout(() => res.send(JSON.stringify({ description: "Description response" })), 1000);
25+
});
26+
1827
app.use(handleRender);
1928

2029
function handleRender(req: Request, res: Response) {
2130
const promises: Promise<any>[] = [];
2231
const store = createStore();
2332

33+
store.dispatch(
34+
setApiUrls({
35+
descriptionUrl: `${req.protocol}://${req.get("host")}/api/description`
36+
})
37+
);
38+
2439
routes.some(route => {
2540
const match = matchPath(req.path, route);
2641
if (match && route.fetchData) {

source/universal/Routes.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { fetchDescription } from "./actions";
77
import { LoadableAbout, LoadableHome } from "./loadable";
88

99
interface IRoute extends RouteProps {
10-
fetchData?: () => ThunkAction<Promise<Action>, IState, void>;
10+
fetchData?: () => ThunkAction<Promise<void>, IState, void>;
1111
}
1212

1313
export const routes: IRoute[] = [

source/universal/actions/about.ts

+11-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Action, ActionCreator } from "redux";
1+
import axios, { AxiosPromise } from "axios";
2+
import { ActionCreator, Action } from "redux";
23
import { ThunkAction } from "redux-thunk";
34

45
import { IState } from "../models";
@@ -31,11 +32,15 @@ export type FetchDescriptionRequest = ReturnType<typeof fetchDescriptionRequest>
3132
export type FetchDescriptionFailure = ReturnType<typeof fetchDescriptionFailure>;
3233
export type FetchDescriptionSuccess = ReturnType<typeof fetchDescriptionSuccess>;
3334

34-
export const fetchDescription: ActionCreator<ThunkAction<Promise<Action>, IState, void>> = () => {
35-
return (dispatch, getState) => {
35+
export const fetchDescription: ActionCreator<ThunkAction<Promise<void>, IState, void>> = () => {
36+
return async (dispatch, getState) => {
3637
dispatch(fetchDescriptionRequest());
37-
return new Promise(resolve => {
38-
setTimeout(() => resolve(dispatch(fetchDescriptionSuccess("About Description"))), 1000);
39-
});
38+
try {
39+
const url = getState().api.descriptionUrl;
40+
const response = await axios.get<{ description: string }>(url);
41+
dispatch(fetchDescriptionSuccess(response.data.description));
42+
} catch (e) {
43+
console.log(e);
44+
}
4045
};
4146
};

source/universal/actions/api.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { IApi } from "../models";
2+
3+
export type ApiAction = SetApiUrls;
4+
5+
export const SET_API_URLS = "SET_API_URLS";
6+
7+
export const setApiUrls = (api: IApi) => ({
8+
type: SET_API_URLS as typeof SET_API_URLS,
9+
descriptionUrl: api.descriptionUrl
10+
});
11+
12+
export type SetApiUrls = ReturnType<typeof setApiUrls>;

source/universal/actions/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from "./about";
22
export * from "./location";
3+
export * from "./api";

source/universal/models/api.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export interface IApi {
2+
descriptionUrl: string;
3+
}

source/universal/models/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from "./window";
22
export * from "./state";
3+
export * from "./api";

source/universal/models/state.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { AboutState } from "../reducers/about";
2+
import { ApiState } from "../reducers/api";
23
import { LocationState } from "../reducers/location";
34

45
export interface IState {
56
readonly about: AboutState;
67
readonly location: LocationState;
8+
readonly api: ApiState;
79
}

source/universal/reducers/api.ts

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { ApiAction, SET_API_URLS } from "../actions/api";
2+
3+
export type ApiState = ReturnType<typeof initialApiState>;
4+
5+
const initialApiState = () => ({
6+
descriptionUrl: ""
7+
});
8+
9+
export default function api(state = initialApiState(), action: ApiAction): ApiState {
10+
switch (action.type) {
11+
case SET_API_URLS:
12+
return {
13+
...state,
14+
descriptionUrl: action.descriptionUrl
15+
};
16+
default:
17+
return state;
18+
}
19+
}

source/universal/reducers/index.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import { combineReducers, Reducer } from "redux";
22

33
import { IState } from "../models";
44
import about, { AboutState } from "./about";
5+
import api, { ApiState } from "./api";
56
import location, { LocationState } from "./location";
67

78
export default combineReducers<IState>({
89
about: about as Reducer<AboutState>,
9-
location: location as Reducer<LocationState>
10+
location: location as Reducer<LocationState>,
11+
api: api as Reducer<ApiState>
1012
});

0 commit comments

Comments
 (0)