summaryrefslogtreecommitdiff
path: root/app/services
diff options
context:
space:
mode:
authorKirill Rogovoy <[email protected]>2021-07-20 21:24:52 +0300
committerKirill Rogovoy <[email protected]>2021-07-20 21:24:52 +0300
commit5f4611d65e40eae3ca6191a15f68d69ea5a1c4cb (patch)
tree273dfc086444533d86d580961c92ba8d14781a67 /app/services
parentf0bf4e7afdcd8b02a62be45ab3e7d047ed865a79 (diff)
WIP
Diffstat (limited to 'app/services')
-rw-r--r--app/services/api/api-config.ts27
-rw-r--r--app/services/api/api-problem.test.ts104
-rw-r--r--app/services/api/api-problem.ts76
-rw-r--r--app/services/api/api.ts102
-rw-r--r--app/services/api/api.types.ts17
-rw-r--r--app/services/api/character-api.ts37
-rw-r--r--app/services/api/index.ts2
-rw-r--r--app/services/reactotron/index.ts1
-rw-r--r--app/services/reactotron/reactotron-config.ts30
-rw-r--r--app/services/reactotron/reactotron.ts188
-rw-r--r--app/services/reactotron/tron.ts2
-rw-r--r--app/services/reactotron/tron.web.ts2
12 files changed, 0 insertions, 588 deletions
diff --git a/app/services/api/api-config.ts b/app/services/api/api-config.ts
deleted file mode 100644
index b939c0e..0000000
--- a/app/services/api/api-config.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-// Use this import if you want to use "env.js" file
-// const { API_URL } = require("../../config/env")
-// Or just specify it directly like this:
-const API_URL = 'http://example.com'
-
-/**
- * The options used to configure the API.
- */
-export interface ApiConfig {
- /**
- * The URL of the api.
- */
- url: string
-
- /**
- * Milliseconds before we timeout the request.
- */
- timeout: number
-}
-
-/**
- * The default configuration for the app.
- */
-export const DEFAULT_API_CONFIG: ApiConfig = {
- url: API_URL || 'https://jsonplaceholder.typicode.com',
- timeout: 10000,
-}
diff --git a/app/services/api/api-problem.test.ts b/app/services/api/api-problem.test.ts
deleted file mode 100644
index 2b37aa9..0000000
--- a/app/services/api/api-problem.test.ts
+++ /dev/null
@@ -1,104 +0,0 @@
-import { getGeneralApiProblem } from './api-problem'
-import { ApiErrorResponse } from 'apisauce'
-
-test('handles connection errors', () => {
- expect(
- getGeneralApiProblem({
- problem: 'CONNECTION_ERROR',
- } as ApiErrorResponse<null>),
- ).toEqual({
- kind: 'cannot-connect',
- temporary: true,
- })
-})
-
-test('handles network errors', () => {
- expect(
- getGeneralApiProblem({
- problem: 'NETWORK_ERROR',
- } as ApiErrorResponse<null>),
- ).toEqual({
- kind: 'cannot-connect',
- temporary: true,
- })
-})
-
-test('handles timeouts', () => {
- expect(
- getGeneralApiProblem({
- problem: 'TIMEOUT_ERROR',
- } as ApiErrorResponse<null>),
- ).toEqual({
- kind: 'timeout',
- temporary: true,
- })
-})
-
-test('handles server errors', () => {
- expect(
- getGeneralApiProblem({ problem: 'SERVER_ERROR' } as ApiErrorResponse<null>),
- ).toEqual({
- kind: 'server',
- })
-})
-
-test('handles unknown errors', () => {
- expect(
- getGeneralApiProblem({
- problem: 'UNKNOWN_ERROR',
- } as ApiErrorResponse<null>),
- ).toEqual({
- kind: 'unknown',
- temporary: true,
- })
-})
-
-test('handles unauthorized errors', () => {
- expect(
- getGeneralApiProblem({
- problem: 'CLIENT_ERROR',
- status: 401,
- } as ApiErrorResponse<null>),
- ).toEqual({
- kind: 'unauthorized',
- })
-})
-
-test('handles forbidden errors', () => {
- expect(
- getGeneralApiProblem({
- problem: 'CLIENT_ERROR',
- status: 403,
- } as ApiErrorResponse<null>),
- ).toEqual({
- kind: 'forbidden',
- })
-})
-
-test('handles not-found errors', () => {
- expect(
- getGeneralApiProblem({
- problem: 'CLIENT_ERROR',
- status: 404,
- } as ApiErrorResponse<null>),
- ).toEqual({
- kind: 'not-found',
- })
-})
-
-test('handles other client errors', () => {
- expect(
- getGeneralApiProblem({
- problem: 'CLIENT_ERROR',
- status: 418,
- } as ApiErrorResponse<null>),
- ).toEqual({
- kind: 'rejected',
- })
-})
-
-test('handles cancellation errors', () => {
- expect(
- getGeneralApiProblem({ problem: 'CANCEL_ERROR' } as ApiErrorResponse<null>),
- ).toBeNull()
-})
diff --git a/app/services/api/api-problem.ts b/app/services/api/api-problem.ts
deleted file mode 100644
index d5b1445..0000000
--- a/app/services/api/api-problem.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-import { ApiResponse } from 'apisauce'
-
-export type GeneralApiProblem =
- /**
- * Times up.
- */
- | { kind: 'timeout'; temporary: true }
- /**
- * Cannot connect to the server for some reason.
- */
- | { kind: 'cannot-connect'; temporary: true }
- /**
- * The server experienced a problem. Any 5xx error.
- */
- | { kind: 'server' }
- /**
- * We're not allowed because we haven't identified ourself. This is 401.
- */
- | { kind: 'unauthorized' }
- /**
- * We don't have access to perform that request. This is 403.
- */
- | { kind: 'forbidden' }
- /**
- * Unable to find that resource. This is a 404.
- */
- | { kind: 'not-found' }
- /**
- * All other 4xx series errors.
- */
- | { kind: 'rejected' }
- /**
- * Something truly unexpected happened. Most likely can try again. This is a catch all.
- */
- | { kind: 'unknown'; temporary: true }
- /**
- * The data we received is not in the expected format.
- */
- | { kind: 'bad-data' }
-
-/**
- * Attempts to get a common cause of problems from an api response.
- *
- * @param response The api response.
- */
-export function getGeneralApiProblem(
- response: ApiResponse<any>,
-): GeneralApiProblem | void {
- switch (response.problem) {
- case 'CONNECTION_ERROR':
- return { kind: 'cannot-connect', temporary: true }
- case 'NETWORK_ERROR':
- return { kind: 'cannot-connect', temporary: true }
- case 'TIMEOUT_ERROR':
- return { kind: 'timeout', temporary: true }
- case 'SERVER_ERROR':
- return { kind: 'server' }
- case 'UNKNOWN_ERROR':
- return { kind: 'unknown', temporary: true }
- case 'CLIENT_ERROR':
- switch (response.status) {
- case 401:
- return { kind: 'unauthorized' }
- case 403:
- return { kind: 'forbidden' }
- case 404:
- return { kind: 'not-found' }
- default:
- return { kind: 'rejected' }
- }
- case 'CANCEL_ERROR':
- return null
- }
-
- return null
-}
diff --git a/app/services/api/api.ts b/app/services/api/api.ts
deleted file mode 100644
index 4093d34..0000000
--- a/app/services/api/api.ts
+++ /dev/null
@@ -1,102 +0,0 @@
-import { ApisauceInstance, create, ApiResponse } from 'apisauce'
-import { getGeneralApiProblem } from './api-problem'
-import { ApiConfig, DEFAULT_API_CONFIG } from './api-config'
-import * as Types from './api.types'
-
-/**
- * Manages all requests to the API.
- */
-export class Api {
- /**
- * The underlying apisauce instance which performs the requests.
- */
- apisauce: ApisauceInstance
-
- /**
- * Configurable options.
- */
- config: ApiConfig
-
- /**
- * Creates the api.
- *
- * @param config The configuration to use.
- */
- constructor(config: ApiConfig = DEFAULT_API_CONFIG) {
- this.config = config
- }
-
- /**
- * Sets up the API. This will be called during the bootup
- * sequence and will happen before the first React component
- * is mounted.
- *
- * Be as quick as possible in here.
- */
- setup() {
- // construct the apisauce instance
- this.apisauce = create({
- baseURL: this.config.url,
- timeout: this.config.timeout,
- headers: {
- Accept: 'application/json',
- },
- })
- }
-
- /**
- * Gets a list of users.
- */
- async getUsers(): Promise<Types.GetUsersResult> {
- // make the api call
- const response: ApiResponse<any> = await this.apisauce.get(`/users`)
-
- // the typical ways to die when calling an api
- if (!response.ok) {
- const problem = getGeneralApiProblem(response)
- if (problem) return problem
- }
-
- const convertUser = (raw) => {
- return {
- id: raw.id,
- name: raw.name,
- }
- }
-
- // transform the data into the format we are expecting
- try {
- const rawUsers = response.data
- const resultUsers: Types.User[] = rawUsers.map(convertUser)
- return { kind: 'ok', users: resultUsers }
- } catch {
- return { kind: 'bad-data' }
- }
- }
-
- /**
- * Gets a single user by ID
- */
-
- async getUser(id: string): Promise<Types.GetUserResult> {
- // make the api call
- const response: ApiResponse<any> = await this.apisauce.get(`/users/${id}`)
-
- // the typical ways to die when calling an api
- if (!response.ok) {
- const problem = getGeneralApiProblem(response)
- if (problem) return problem
- }
-
- // transform the data into the format we are expecting
- try {
- const resultUser: Types.User = {
- id: response.data.id,
- name: response.data.name,
- }
- return { kind: 'ok', user: resultUser }
- } catch {
- return { kind: 'bad-data' }
- }
- }
-}
diff --git a/app/services/api/api.types.ts b/app/services/api/api.types.ts
deleted file mode 100644
index 5090e74..0000000
--- a/app/services/api/api.types.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { GeneralApiProblem } from './api-problem'
-import { Character } from '../../models/character/character'
-
-export interface User {
- id: number
- name: string
-}
-
-export type GetUsersResult = { kind: 'ok'; users: User[] } | GeneralApiProblem
-export type GetUserResult = { kind: 'ok'; user: User } | GeneralApiProblem
-
-export type GetCharactersResult =
- | { kind: 'ok'; characters: Character[] }
- | GeneralApiProblem
-export type GetCharacterResult =
- | { kind: 'ok'; character: Character }
- | GeneralApiProblem
diff --git a/app/services/api/character-api.ts b/app/services/api/character-api.ts
deleted file mode 100644
index e28ec48..0000000
--- a/app/services/api/character-api.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { ApiResponse } from 'apisauce'
-import { Api } from './api'
-import { GetCharactersResult } from './api.types'
-import { getGeneralApiProblem } from './api-problem'
-
-const API_PAGE_SIZE = 50
-
-export class CharacterApi {
- private api: Api
-
- constructor(api: Api) {
- this.api = api
- }
-
- async getCharacters(): Promise<GetCharactersResult> {
- try {
- // make the api call
- const response: ApiResponse<any> = await this.api.apisauce.get(
- 'https://raw.githubusercontent.com/infinitered/ignite/master/data/rick-and-morty.json',
- { amount: API_PAGE_SIZE },
- )
-
- // the typical ways to die when calling an api
- if (!response.ok) {
- const problem = getGeneralApiProblem(response)
- if (problem) return problem
- }
-
- const characters = response.data.results
-
- return { kind: 'ok', characters }
- } catch (e) {
- __DEV__ && console.tron.log(e.message)
- return { kind: 'bad-data' }
- }
- }
-}
diff --git a/app/services/api/index.ts b/app/services/api/index.ts
deleted file mode 100644
index f133e64..0000000
--- a/app/services/api/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from './api'
-export * from './api.types'
diff --git a/app/services/reactotron/index.ts b/app/services/reactotron/index.ts
deleted file mode 100644
index 0c02f1f..0000000
--- a/app/services/reactotron/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './reactotron'
diff --git a/app/services/reactotron/reactotron-config.ts b/app/services/reactotron/reactotron-config.ts
deleted file mode 100644
index 40e9c93..0000000
--- a/app/services/reactotron/reactotron-config.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-export interface ReactotronConfig {
- /** The name of the app. */
- name?: string
- /** The host to connect to: default 'localhost'. */
- host?: string
- /** Should we use async storage */
- useAsyncStorage?: boolean
- /** Should we clear Reactotron when load? */
- clearOnLoad?: boolean
- /** Root state logging. */
- state?: {
- /** log the initial data that we put into the state on startup? */
- initial?: boolean
- /** log snapshot changes. */
- snapshots?: boolean
- }
-}
-
-/**
- * The default Reactotron configuration.
- */
-export const DEFAULT_REACTOTRON_CONFIG: ReactotronConfig = {
- clearOnLoad: true,
- host: 'localhost',
- useAsyncStorage: true,
- state: {
- initial: true,
- snapshots: false,
- },
-}
diff --git a/app/services/reactotron/reactotron.ts b/app/services/reactotron/reactotron.ts
deleted file mode 100644
index eda9ed9..0000000
--- a/app/services/reactotron/reactotron.ts
+++ /dev/null
@@ -1,188 +0,0 @@
-import { Tron } from './tron'
-import AsyncStorage from '@react-native-async-storage/async-storage'
-import { RootStore } from '../../models/root-store/root-store'
-import { onSnapshot } from 'mobx-state-tree'
-import {
- ReactotronConfig,
- DEFAULT_REACTOTRON_CONFIG,
-} from './reactotron-config'
-import { mst } from 'reactotron-mst'
-import { clear } from '../../utils/storage'
-import { RootNavigation } from '../../navigators'
-import { Platform } from 'react-native'
-
-// Teach TypeScript about the bad things we want to do.
-declare global {
- interface Console {
- /**
- * Hey, it's Reactotron if we're in dev, and no-ops if we're in prod.
- */
- tron: typeof Tron
- }
-}
-
-/** Do Nothing. */
-const noop = () => undefined
-
-// in dev, we attach Reactotron, in prod we attach a interface-compatible mock.
-if (__DEV__) {
- console.tron = Tron // attach reactotron to `console.tron`
-} else {
- // attach a mock so if things sneaky by our __DEV__ guards, we won't crash.
- console.tron = {
- benchmark: noop,
- clear: noop,
- close: noop,
- configure: noop,
- connect: noop,
- display: noop,
- error: noop,
- image: noop,
- log: noop,
- logImportant: noop,
- onCustomCommand: noop,
- overlay: noop,
- reportError: noop,
- send: noop,
- startTimer: noop,
- storybookSwitcher: noop,
- use: noop,
- useReactNative: noop,
- warn: noop,
- }
-}
-
-/**
- * You'll probably never use the service like this since we hang the Reactotron
- * instance off of `console.tron`. This is only to be consistent with the other
- * services.
- */
-export class Reactotron {
- config: ReactotronConfig
-
- rootStore: any
-
- /**
- * Create the Reactotron service.
- *
- * @param config the configuration
- */
- constructor(config: ReactotronConfig = DEFAULT_REACTOTRON_CONFIG) {
- // merge the passed in config with some defaults
- this.config = {
- host: 'localhost',
- useAsyncStorage: true,
- ...config,
- state: {
- initial: false,
- snapshots: false,
- ...(config && config.state),
- },
- }
- }
-
- /**
- * Hook into the root store for doing awesome state-related things.
- *
- * @param rootStore The root store
- */
- setRootStore(rootStore: any, initialData: any) {
- if (__DEV__) {
- rootStore = rootStore as RootStore // typescript hack
- this.rootStore = rootStore
-
- const { initial, snapshots } = this.config.state
- const name = 'ROOT STORE'
-
- // logging features
- if (initial) {
- console.tron.display({
- name,
- value: initialData,
- preview: 'Initial State',
- })
- }
- // log state changes?
- if (snapshots) {
- onSnapshot(rootStore, (snapshot) => {
- console.tron.display({ name, value: snapshot, preview: 'New State' })
- })
- }
-
- console.tron.trackMstNode(rootStore)
- }
- }
-
- /**
- * Configure reactotron based on the the config settings passed in, then connect if we need to.
- */
- async setup() {
- // only run this in dev... metro bundler will ignore this block: 🎉
- if (__DEV__) {
- // configure reactotron
- Tron.configure({
- name: this.config.name || require('../../../package.json').name,
- host: this.config.host,
- })
-
- // hookup middleware
- if (Platform.OS !== 'web') {
- if (this.config.useAsyncStorage) {
- Tron.setAsyncStorageHandler(AsyncStorage)
- }
- Tron.useReactNative({
- asyncStorage: this.config.useAsyncStorage ? undefined : false,
- })
- }
-
- // ignore some chatty `mobx-state-tree` actions
- const RX = /postProcessSnapshot|@APPLY_SNAPSHOT/
-
- // hookup mobx-state-tree middleware
- Tron.use(
- mst({
- filter: (event) => RX.test(event.name) === false,
- }),
- )
-
- // connect to the app
- Tron.connect()
-
- // Register Custom Commands
- Tron.onCustomCommand({
- title: 'Reset Root Store',
- description: 'Resets the MST store',
- command: 'resetStore',
- handler: () => {
- console.tron.log('resetting store')
- clear()
- },
- })
-
- Tron.onCustomCommand({
- title: 'Reset Navigation State',
- description: 'Resets the navigation state',
- command: 'resetNavigation',
- handler: () => {
- console.tron.log('resetting navigation state')
- RootNavigation.resetRoot({ routes: [] })
- },
- })
-
- Tron.onCustomCommand({
- title: 'Go Back',
- description: 'Goes back',
- command: 'goBack',
- handler: () => {
- console.tron.log('Going back')
- RootNavigation.goBack()
- },
- })
-
- // clear if we should
- if (this.config.clearOnLoad) {
- Tron.clear()
- }
- }
- }
-}
diff --git a/app/services/reactotron/tron.ts b/app/services/reactotron/tron.ts
deleted file mode 100644
index 6086e48..0000000
--- a/app/services/reactotron/tron.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-import Reactotron from 'reactotron-react-native'
-export const Tron = Reactotron
diff --git a/app/services/reactotron/tron.web.ts b/app/services/reactotron/tron.web.ts
deleted file mode 100644
index a525c06..0000000
--- a/app/services/reactotron/tron.web.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-import Reactotron from 'reactotron-react-js'
-export const Tron = Reactotron