1. Http call
1.1. Http call approaches
- Node
- http
- request (✅)
- Browser
- XMLHttpRequest
- jQuery
- Framework-based (Angular http service)
- Fetch (✅ polyfill for both regular version or isomorphic-fetch)
- Node & Browser (any below is good)
- isomorphic-fetch
- xhr
- superAgent
- axios (great)
1.1.1. Fetch
You can find compatibility for fetch: https://caniuse.com/#search=fetch
Fetch cannot be cancelled at this time.
const request = new Request('http://your-api.com/user', {
method: 'GET',
mode: 'cors',
headers: new Headers({
'Content-Type': 'text/html; charset=UTF-8',
}),
});
fetch(request).then(onSuccess, onError);
1.1.2. Axios
axios({
url: 'http://your-api.com/user',
method: 'post',
headers: {
'Content-type': 'text/html; charset=UTF-8',
},
data: 'text',
}).then(onSuccess, onError);
1.2. Why centralize API calls
- Configure all calls
- Handle preloader logic
- Handle errors
- Single seam(缝合;接合) for mocking
create src/api/userApi.js
import 'whatwg-fetch'; // let browser that hasn't supported fetch work with fetch
const onSuccess = (response) => response.json();
const onError = (error) => console.log(error); //eslint-disable-line no-console
const get = (url) => fetch(url).then(onSuccess, onError);
export const getUsers = () => get('users');
So in index.js, I can call this api:
import { getUsers } from './api/userApi';
getUsers().then((result) => {});
Only send polyfill to those who need it:
<script src="https://cdn.polyfill.io/v2/polyfill.js?features=fetch"></script>
1.3. Mock
1.3.1. Why Mock HTTP?
- Unit Testing
- Instant response
- Keep working when services are down
- Rapid prototyping
- Avoid inter-team bottlenecks
- Work offline
1.3.2. How to Mock HTTP (also review interview/frontend/Mock.md)
- Nock (mock http calls in unit test)
- Static JSON
- Create development webserver
- api-mock
- JSON server
- JSON Schema faker(random data)
- Browsersync
- Express, etc.
My json server: https://my-json-server.typicode.com/
1.3.3. Authentication
- https://dzone.com/articles/basic-authentication-for-json-server
- https://medium.com/@kaustubhtalathi/mock-data-for-angular-5-applications-with-json-server-part-1-d377eced223b
- https://github.com/techiediaries/fake-api-jwt-json-server
1.3.4. Our Plan for Mocking HTTP
- Declare our schema:
- JSON Schema Faker
- Generate Random Data:
- faker.js
- chance.js
- randexp.js
- Serve Data via API
- JSON Server
1.3.5. Mocking Libraries
1.3.6. Demo
1. create Schema: buildScripts/mockDataSchema.js
export const schema = {
type: 'object',
properties: {
users: {
type: 'array',
minItems: 3,
maxItems: 5,
items: {
type: 'object',
properties: {
id: {
type: 'number',
unique: true,
minimum: 1,
},
firstName: {
type: 'string',
faker: 'name.firstName',
},
lastName: {
type: 'string',
faker: 'name.lastName',
},
email: {
type: 'string',
faker: 'internet.email',
},
},
required: ['id', 'firstName', 'lastName', 'email'],
},
},
},
required: ['users'],
};
2. generate Mock Data: buildScripts/generateMockData.js
import jsf from 'json-schema-faker';
import { schema } from './mockDataSchema';
import fs from 'fs';
import chalk from 'chalk';
const json = JSON.stringify(jsf(schema));
fs.writeFile('./src/api/db.json', json, (err) => {
if (err) {
return console.log(chalk.red(err));
} else {
console.log(chalk.green('Mock data generated.'));
}
});
npm scripts:
"generate-mock-data": "babel-node buildScripts/generateMockData"
Run npm run generate-mock-data
and you should see src/api/db.json.
3. serving mock data via json server
npm scripts:
"start-mockapi": "json-server --watch src/api/db.json --port 3001"
npm run start-mockapi
and access http://localhost:3001/users, you should see the data
I prefer to change data every time when restarting the app.
Randomized data is helpful.
- empty lists
- long lists
- long value
- testing
- filtering
- sorting
To change data, follow below:
npm scripts:
"start": "npm-run-all --parallel security-check start:server lint:watch test:watch start-mockapi",
"generate-mock-data": "babel-node buildScripts/generateMockData",
"prestart-mockapi": "npm run generate-mock-data",
"start-mockapi": "json-server --watch src/api/db.json --port 3001"
Targeting mock api or production api by environment
Assume srcServer.js's app.get('/users')
is called only for production, while in dev mode, we should hit Json-server port 3001. So when requesting localhost:3000/
, we know it's development environment and call getUsers api which hosting in port 3001 by Json-server. When request http://production
, we call production api.
api/baseUrl.js
export default function getBaseUrl() {
const inDevelopment = window.location.hostname === 'localhost';
return inDevelopment ? 'http://localhost:3001/' : '/'; // first is json-server address, second is production api address
}
api/userApi.js
import getBaseUrl from './baseUrl';
const baseUrl = getBaseUrl();
const get = (url) => fetch(baseUrl + url).then(onSuccess, onError);
delete user for Json-server
index.js
const deleteLinks = document.querySelectorAll('.deleteUser');
Array.from(deleteLinks, (link) => {
link.onclick = (e) => {
const ele = e.target;
e.preventDefault();
deleteUser(ele.dataset.id);
const row = ele.parentNode.parentNode; // tr
row.parentNode.removeChild(row);
};
});
userApi.js
const del = (url) => {
const request = new Request(baseUrl + url, {
method: 'delete',
});
return fetch(request).then(onSuccess, onError);
};
export const deleteUser = (id) => del(`users/${id}`);