Skip to content
This repository was archived by the owner on Sep 27, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/api/http-error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@ export class HttpError implements Error {
return content === '{"message":"Forbidden"}'
}

public isMonthlyLimitExceeded(): boolean {
return !this.isInvalidTokenRequest() && this.response.getResponseCode() === 403
}

public isResourceNotFound(): boolean {
return this.response.getResponseCode() === 404
}

public isApiQuotaExceeded(): boolean {
return this.response.getResponseCode() === 429
}

public isBadRequest(): boolean {
return Math.floor(this.response.getResponseCode() / 100) === 4
}

public toString(): string {
return this.message
}
Expand Down
42 changes: 2 additions & 40 deletions src/custom-functions/v3/bcode.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,11 @@
import { HttpError } from '~/api/http-error'
import { CachingBuffettCodeApiClientV3 } from '~/api/v3/caching-client'
import { ApiResponseError, OndemandApiNotEnabledError, UnsupportedTickerError } from '~/custom-functions/error'
import { bcodeDaily } from '~/custom-functions/v3/bcode-daily'
import { bcodeQuarter } from '~/custom-functions/v3/bcode-quarter'
import { BcodeResult } from '~/custom-functions/v3/bcode-result'
import { InvalidLYLQError, InvalidYearError, InvalidQuarterError } from '~/fiscal-periods/error'
import { PeriodParser } from '~/fiscal-periods/period-parser'
import { ErrorHandler } from '~/services/error-handler'
import { Setting } from '~/setting'

function handleError(e): void {
if (e instanceof ApiResponseError) {
throw new Error('<<指定されたデータを取得できませんでした>>')
} else if (e instanceof OndemandApiNotEnabledError) {
throw new Error('<<従量課金APIが有効になっていません>>')
} else if (e instanceof UnsupportedTickerError) {
throw new Error('<<サポートされていないtickerです>>')
} else if (e instanceof HttpError) {
const code = e.response.getResponseCode()

if (e.isInvalidTestingRequest()) {
throw new Error('<<テスト用のAPIキーでは取得できないデータです>>')
} else if (e.isInvalidTokenRequest()) {
throw new Error('<<APIキーが有効ではありません>>')
} else if (code === 403) {
throw new Error('<<月間リクエスト制限に達しています>>')
} else if (code === 429) {
throw new Error('<<APIの実行回数が上限に達しました>>')
} else if (Math.floor(code / 100) === 4) {
throw new Error(`<<無効なリクエストです。${e.name}: ${e.message}>>`)
} else {
console.error('システムエラー', e.name, e.message)
throw new Error(`<<システムエラーが発生しました。${e.name}: ${e.message}>>`)
}
} else if (e instanceof InvalidLYLQError) {
throw new Error('<<無効なLY・LQが指定されています>>')
} else if (e instanceof InvalidYearError) {
throw new Error(`<<無効な決算年度が指定されています>>`)
} else if (e instanceof InvalidQuarterError) {
throw new Error(`<<無効な四半期が指定されています>>`)
} else {
console.error('未定義のエラー', e.name, e.message)
throw new Error(`<<未定義のエラーが発生しました。${e.name}: ${e.message}>>`)
}
}

export function bcode(
ticker: string,
period: string | Date,
Expand Down Expand Up @@ -98,6 +60,6 @@ export function bcode(

return result.format(isRawValue, isWithUnits)
} catch (e) {
handleError(e)
ErrorHandler.handle(e)
}
}
40 changes: 29 additions & 11 deletions src/services/csv-exporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { CachingBuffettCodeApiClientV3 } from '~/api/v3/caching-client'
import { YearQuarter } from '~/fiscal-periods/year-quarter'
import { YearQuarterParam } from '~/fiscal-periods/year-quarter-param'
import { YearQuarterRange } from '~/fiscal-periods/year-quarter-range'
import { ErrorHandler } from '~/services/error-handler'
import { Setting } from '~/setting'

export class CsvExporter {
Expand All @@ -28,7 +29,14 @@ export class CsvExporter {

const setting = Setting.load()
const client = new CachingBuffettCodeApiClientV3(setting.token)
const companyService = new CompanyService(ticker, client, today)

let companyService
try {
companyService = new CompanyService(ticker, client, today)
} catch (e) {
ErrorHandler.handle(e)
}
Comment on lines +33 to +38
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ここでエラーが出るとしたら HttpError だけの想定なんですが、どこでなんのエラーが出るかわからないので、未定義なエラーもハンドリングできるように ErrorHandler.handleHttpError ではなく広めに ErrorHandler.handle してます。


const ondemandQuarterApiPeriodRange = new OndemandApiPeriodRange(companyService)

let ondemandQuarterApiPeriods = []
Expand All @@ -48,12 +56,16 @@ export class CsvExporter {
}

const quarters = []
quarterApiPeriods.forEach(period => {
quarters.push(client.quarter(ticker, YearQuarterParam.fromYearQuarter(period)))
})
ondemandQuarterApiPeriods.forEach(period => {
quarters.push(client.ondemandQuarter(ticker, YearQuarterParam.fromYearQuarter(period)))
})
try {
quarterApiPeriods.forEach(period => {
quarters.push(client.quarter(ticker, YearQuarterParam.fromYearQuarter(period)))
})
ondemandQuarterApiPeriods.forEach(period => {
quarters.push(client.ondemandQuarter(ticker, YearQuarterParam.fromYearQuarter(period)))
})
} catch (e) {
ErrorHandler.handle(e)
}
Comment on lines +59 to +68
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

同上です。広めに ErrorHandler.handle してます。


if (!quarters.length) {
throw new Error('<<指定されたデータを取得できませんでした>>')
Expand Down Expand Up @@ -96,10 +108,16 @@ export class CsvExporter {
const numRows = data.length
const numColumns = data[0].length

const ss = SpreadsheetApp.getActiveSpreadsheet()
const sheet = ss.insertSheet()
const range = sheet.getRange(1, 1, numRows, numColumns) // starts from A1
try {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const sheet = ss.insertSheet()
const range = sheet.getRange(1, 1, numRows, numColumns) // starts from A1

range.setValues(data)
range.setValues(data)
} catch (e) {
throw new Error(
`<<出力中にエラーが発生しました (${e.name}: ${e.message})。改善しない場合はGoogleアカウントのログアウトおよび再ログインをお試しください>>`
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

シートに書き込むタイミングでエラーが出た場合は再ログインを促すようにします。

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

完璧、本来出ないはずではあるが、出るからなこれ…

)
}
}
}
47 changes: 47 additions & 0 deletions src/services/error-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { HttpError } from '~/api/http-error'
import { ApiResponseError, OndemandApiNotEnabledError, UnsupportedTickerError } from '~/custom-functions/error'
import { InvalidLYLQError, InvalidYearError, InvalidQuarterError } from '~/fiscal-periods/error'

export class ErrorHandler {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

内部用の Error を受け取って外部向けの Error を投げ返すだけのクラスです。

static handle(e: Error): void {
if (e instanceof ApiResponseError) {
throw new Error('<<指定されたデータを取得できませんでした>>')
} else if (e instanceof OndemandApiNotEnabledError) {
throw new Error('<<従量課金APIが有効になっていません>>')
} else if (e instanceof UnsupportedTickerError) {
throw new Error('<<サポートされていないtickerです>>')
} else if (e instanceof HttpError) {
ErrorHandler.handleHttpError(e)
} else if (e instanceof InvalidLYLQError) {
throw new Error('<<無効なLY・LQが指定されています>>')
} else if (e instanceof InvalidYearError) {
throw new Error(`<<無効な決算年度が指定されています>>`)
} else if (e instanceof InvalidQuarterError) {
throw new Error(`<<無効な四半期が指定されています>>`)
} else {
console.error('未定義のエラー', e.name, e.message)
throw new Error(
`<<未定義のエラーが発生しました (${e.name}: ${e.message})。改善しない場合はGoogleアカウントのログアウトおよび再ログインをお試しください>>`
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

未定義のエラーが出た場合は再ログインを促すようにします。

)
}
}

static handleHttpError(e: HttpError): void {
if (e.isInvalidTestingRequest()) {
throw new Error('<<テスト用のAPIキーでは取得できないデータです>>')
} else if (e.isInvalidTokenRequest()) {
throw new Error('<<APIキーが有効ではありません>>')
} else if (e.isMonthlyLimitExceeded()) {
throw new Error('<<月間リクエスト制限に達しています>>')
} else if (e.isResourceNotFound()) {
throw new Error('<<データが見つかりません。tickerや期間に間違いがないかご確認ください>>')
} else if (e.isApiQuotaExceeded()) {
throw new Error('<<APIの実行回数が上限に達しました>>')
} else if (e.isBadRequest()) {
throw new Error(`<<無効なリクエストです (${e.name}: ${e.message})>>`)
} else {
console.error('システムエラー', e.name, e.message)
throw new Error(`<<システムエラーが発生しました (${e.name}: ${e.message})>>`)
}
}
}
2 changes: 1 addition & 1 deletion src/ui/csv-export-dialog.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
const button = document.getElementById('export-button')
button.disabled = ""

alert('CSV出力中にエラーが発生しました: ' + e.message)
alert(`CSV出力中にエラーが発生しました\n${e.message}`)
}

function exportCsv() {
Expand Down