Skip to content

Commit

Permalink
build: add Axios, use in korpRequest
Browse files Browse the repository at this point in the history
  • Loading branch information
arildm committed Jan 15, 2025
1 parent 2561ef5 commit 92db964
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 50 deletions.
54 changes: 20 additions & 34 deletions app/scripts/backend/common.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
/** @format */
import { selectHttpMethod } from "@/util"
import axios from "axios"
import { getAuthorizationHeader } from "@/components/auth/auth"
import settings from "@/settings"
import { API, ErrorMessage, ProgressHandler, ProgressReport, ProgressResponse, Response as KResponse } from "./types"
import { omitBy, pickBy } from "lodash"
import { API, ErrorMessage, ProgressHandler, ProgressReport, ProgressResponse, Response } from "./types"
import { pickBy } from "lodash"
import { selectHttpMethod } from "@/util"

type RequestOptions<K extends keyof API> = {
/** Abort signal to cancel the request */
Expand All @@ -17,24 +18,22 @@ export async function korpRequest<K extends keyof API>(
params: API[K]["params"],
options: RequestOptions<K> = {}
): Promise<API[K]["response"]> {
// Skip params with `null` or `undefined`
params = omitBy(params, (value) => value == null) as API[K]["params"]
// Switch to POST if the URL would be to long
const { url, request } = selectHttpMethod(settings.korp_backend_url + "/" + endpoint, params)
request.headers = { ...request.headers, ...getAuthorizationHeader() }
if (options.abortSignal) request.signal = options.abortSignal

// Send request
const response = await fetch(url, request)

// If progress handler given, parse response data as it comes in
const json = await readIncrementally(response, (json) => {
if (options.onProgress) {
const progress = calcProgress<K>(json)
if (progress) options.onProgress(progress)
}
const conf = selectHttpMethod({
url: settings.korp_backend_url + "/" + endpoint,
params,
headers: getAuthorizationHeader(),
signal: options.abortSignal,
onDownloadProgress: (event) => {
const xhr = event.event?.target as XMLHttpRequest | undefined
if (xhr && options.onProgress) {
const progress = calcProgress<K>(xhr.responseText)
if (progress) options.onProgress(progress)
}
},
})
const data: KResponse<API[K]["response"]> = JSON.parse(json)

const response = await axios.request<Response<API[K]["response"]>>(conf)
const data = response.data

if ("ERROR" in data) {
const { type, value } = data.ERROR as ErrorMessage
Expand All @@ -44,19 +43,6 @@ export async function korpRequest<K extends keyof API>(
return data
}

/** Read and handle a HTTP response body as it comes in */
async function readIncrementally(response: Response, handle: (content: string) => void): Promise<string> {
const reader = response.body!.getReader()
let content = ""
while (true) {
const { done, value } = await reader.read()
content += new TextDecoder("utf-8").decode(value)
handle(content)
if (done) break
}
return content
}

export class KorpBackendError extends Error {
constructor(public readonly type: string, public readonly value: string) {
super(`${type}: ${value}`)
Expand All @@ -65,7 +51,7 @@ export class KorpBackendError extends Error {
}

export function calcProgress<K extends keyof API>(partialJson: string): ProgressReport<K> | undefined {
const data = parsePartialJson<ProgressResponse & KResponse<API[K]["response"]>>(partialJson)
const data = parsePartialJson<ProgressResponse & Response<API[K]["response"]>>(partialJson)
if (!data) return

/** Look up sizes of corpora and sum them */
Expand Down
4 changes: 2 additions & 2 deletions app/scripts/controllers/example_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ class ExampleCtrl extends KwicCtrl {
})
)
.catch((error) => {
// AbortError is expected if a new search is made before the previous one is finished
if (error.name == "AbortError") return
// CanceledError is expected if a new search is made before the previous one is finished
if (error.name == "CanceledError") return
console.error(error)
// TODO Show error
$timeout(() => (s.error = true))
Expand Down
4 changes: 2 additions & 2 deletions app/scripts/controllers/kwic_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,8 @@ export class KwicCtrl implements IController {
)
.then((data) => $timeout(() => s.renderCompleteResult(data, isPaging)))
.catch((error) => {
// AbortError is expected if a new search is made before the previous one is finished
if (error.name == "AbortError") return
// CanceledError is expected if a new search is made before the previous one is finished
if (error.name == "CanceledError") return
console.error(error)
// TODO Show error
$timeout(() => {
Expand Down
4 changes: 2 additions & 2 deletions app/scripts/controllers/statistics_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ angular.module("korpApp").directive("statsResultCtrl", () => ({
})
)
.catch((error) => {
// AbortError is expected if a new search is made before the previous one is finished
if ((error.name = "AbortError")) return
// CanceledError is expected if a new search is made before the previous one is finished
if ((error.name = "CanceledError")) return
console.error(error)
// TODO Show error
$timeout(() => {
Expand Down
4 changes: 2 additions & 2 deletions app/scripts/controllers/word_picture_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ angular.module("korpApp").directive("wordpicCtrl", () => ({
})
)
.catch((error) => {
// AbortError is expected if a new search is made before the previous one is finished
if (error.name == "AbortError") return
// CanceledError is expected if a new search is made before the previous one is finished
if (error.name == "CanceledError") return
console.error(error)
// TODO Show error
$timeout(() => {
Expand Down
18 changes: 10 additions & 8 deletions app/scripts/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { MaybeWithOptions, MaybeConfigurable } from "./settings/config.types"
import { CorpusTransformed } from "./settings/config-transformed.types"
import { LinkedKwic, Row } from "./components/kwic"
import { ApiKwic } from "./backend/types"
import { AxiosRequestConfig } from "axios"

/** Use html`<div>html here</div>` to enable formatting template strings with Prettier. */
export const html = String.raw
Expand Down Expand Up @@ -421,14 +422,15 @@ export const regescape = (s: string): string => s.replace(/[.|?|+|*||'|()^$\\]/g
/** Unescape special characters in a regular expression – remove single backslashes and replace double with single. */
export const unregescape = (s: string): string => s.replace(/\\\\|\\/g, (match) => (match === "\\\\" ? "\\" : ""))

/**
* Select GET or POST depending on url length.
*/
export function selectHttpMethod(url: string, params: Record<string, any>): { url: string; request: RequestInit } {
const urlFull = buildUrl(url, params)
return urlFull.length > settings.backendURLMaxLength
? { url, request: { method: "POST", body: toFormData(params) } }
: { url: urlFull, request: {} }
/** Select GET or POST depending on url length. Modifies conf in place. */
export function selectHttpMethod(conf: AxiosRequestConfig & { url: string }): AxiosRequestConfig {
const urlFull = buildUrl(conf.url, conf.params || {})
conf.method = urlFull.length > settings.backendURLMaxLength ? "POST" : "GET"
if (conf.method == "POST") {
conf.data = toFormData(conf.params || {})
delete conf.params
}
return conf
}

/** Convert object to FormData */
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"angular-filter": "0.5.17",
"angular-ui-bootstrap": "2.5.6",
"angular-ui-sortable": "~0.19.0",
"axios": "^1.7.9",
"bootstrap-sass": "^3.4.3",
"chart.js": "^4.4.3",
"comma-separated-values": "3.6.4",
Expand Down
14 changes: 14 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -858,6 +858,15 @@ axios@^1.6.7:
form-data "^4.0.0"
proxy-from-env "^1.1.0"

axios@^1.7.9:
version "1.7.9"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.9.tgz#d7d071380c132a24accda1b2cfc1535b79ec650a"
integrity sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==
dependencies:
follow-redirects "^1.15.6"
form-data "^4.0.0"
proxy-from-env "^1.1.0"

balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
Expand Down Expand Up @@ -1910,6 +1919,11 @@ follow-redirects@^1.15.4:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020"
integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==

follow-redirects@^1.15.6:
version "1.15.9"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1"
integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==

forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
Expand Down

0 comments on commit 92db964

Please sign in to comment.