@sjcrh/proteinpaint-server 2.39.6 → 2.40.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjcrh/proteinpaint-server",
3
- "version": "2.39.6",
3
+ "version": "2.40.1",
4
4
  "description": "a genomics visualization tool for exploring a cohort's genotype and phenotype data",
5
5
  "main": "server.js",
6
6
  "bin": "start.js",
package/routes/gdc.maf.ts CHANGED
@@ -8,8 +8,6 @@ this route lists available gdc MAF files based on user's cohort filter
8
8
  and return them to client to be shown in a table for selection
9
9
  */
10
10
 
11
- const apihost = process.env.PP_GDC_HOST || 'https://api.gdc.cancer.gov' // to switch to serverconfig export
12
-
13
11
  const maxFileNumber = 1000 // determines max number of files to return to client
14
12
  // preliminary testing:
15
13
  // 36s for 1000 (87Mb)
@@ -60,7 +58,7 @@ function init({ genomes }) {
60
58
  const ds = g.datasets.GDC
61
59
  if (!ds) throw 'hg38 GDC missing'
62
60
 
63
- const payload = await listMafFiles(req.query as GdcMafRequest)
61
+ const payload = await listMafFiles(req.query as GdcMafRequest, ds)
64
62
  res.send(payload)
65
63
  } catch (e: any) {
66
64
  res.send({ status: 'error', error: e.message || e })
@@ -80,7 +78,7 @@ ds {
80
78
  }
81
79
  }
82
80
  */
83
- async function listMafFiles(q: GdcMafRequest) {
81
+ async function listMafFiles(q: GdcMafRequest, ds) {
84
82
  const filters = {
85
83
  op: 'and',
86
84
  content: [
@@ -90,15 +88,16 @@ async function listMafFiles(q: GdcMafRequest) {
90
88
  { op: '=', content: { field: 'access', value: 'open' } } // delete if later to support controlled files
91
89
  ]
92
90
  }
93
-
91
+ const case_filters: any = { op: 'and', content: [] }
94
92
  if (q.filter0) {
95
- filters.content.push(q.filter0)
93
+ case_filters.content.push(q.filter0)
96
94
  }
97
95
 
98
- const headers = { 'Content-Type': 'application/json', Accept: 'application/json' }
96
+ const { host, headers } = ds.getHostHeaders(q)
99
97
 
100
98
  const data = {
101
99
  filters,
100
+ case_filters,
102
101
  size: maxFileNumber,
103
102
  fields: [
104
103
  'id',
@@ -110,7 +109,7 @@ async function listMafFiles(q: GdcMafRequest) {
110
109
  ].join(',')
111
110
  }
112
111
 
113
- const response = await got.post(path.join(apihost, 'files'), { headers, body: JSON.stringify(data) })
112
+ const response = await got.post(path.join(host.rest, 'files'), { headers, body: JSON.stringify(data) })
114
113
 
115
114
  let re
116
115
  try {
@@ -7,8 +7,6 @@ import Readable from 'stream'
7
7
  import { GdcMafBuildRequest } from '#shared/types/routes/gdc.mafBuild.ts'
8
8
  import { maxTotalSizeCompressed } from './gdc.maf.ts'
9
9
 
10
- const apihost = process.env.PP_GDC_HOST || 'https://api.gdc.cancer.gov'
11
-
12
10
  export const api = {
13
11
  endpoint: 'gdc/mafBuild',
14
12
  methods: {
@@ -27,7 +25,11 @@ export const api = {
27
25
  function init({ genomes }) {
28
26
  return async (req: any, res: any): Promise<void> => {
29
27
  try {
30
- await buildMaf(req.query as GdcMafBuildRequest, res)
28
+ const g = genomes.hg38
29
+ if (!g) throw 'hg38 missing'
30
+ const ds = g.datasets.GDC
31
+ if (!ds) throw 'hg38 GDC missing'
32
+ await buildMaf(req.query as GdcMafBuildRequest, res, ds)
31
33
  } catch (e: any) {
32
34
  if (e.stack) console.log(e.stack)
33
35
  res.send({ status: 'error', error: e.message || e })
@@ -39,10 +41,10 @@ function init({ genomes }) {
39
41
  q{}
40
42
  res{}
41
43
  */
42
- async function buildMaf(q: GdcMafBuildRequest, res: any) {
44
+ async function buildMaf(q: GdcMafBuildRequest, res: any, ds) {
43
45
  const t0 = Date.now()
44
-
45
- const fileLst2 = (await getFileLstUnderSizeLimit(q.fileIdLst)) as string[]
46
+ const { host, headers } = ds.getHostHeaders(q)
47
+ const fileLst2 = (await getFileLstUnderSizeLimit(q.fileIdLst, host, headers)) as string[]
46
48
 
47
49
  if (serverconfig.debugmode)
48
50
  console.log(
@@ -53,7 +55,7 @@ async function buildMaf(q: GdcMafBuildRequest, res: any) {
53
55
  const arg = {
54
56
  fileIdLst: fileLst2,
55
57
  columns: q.columns,
56
- host: path.join(apihost, 'data') // must use the /data/ endpoint from current host
58
+ host: path.join(host.rest, 'data') // must use the /data/ endpoint from current host
57
59
  }
58
60
 
59
61
  const rustStream = run_rust_stream('gdcmaf', JSON.stringify(arg))
@@ -80,7 +82,7 @@ excess files are not processed in order not to crash server
80
82
  must not rely on file size sent by client, as that can be spoofed and never to be trusted
81
83
  it's inexpensive to query api for this
82
84
  */
83
- async function getFileLstUnderSizeLimit(lst: string[]) {
85
+ async function getFileLstUnderSizeLimit(lst: string[], host, headers) {
84
86
  if (lst.length == 0) throw 'fileIdLst[] not array or blank'
85
87
  const data = {
86
88
  filters: {
@@ -90,8 +92,7 @@ async function getFileLstUnderSizeLimit(lst: string[]) {
90
92
  size: 10000,
91
93
  fields: 'file_size'
92
94
  }
93
- const headers = { 'Content-Type': 'application/json', Accept: 'application/json' }
94
- const response = await got.post(path.join(apihost, 'files'), { headers, body: JSON.stringify(data) })
95
+ const response = await got.post(path.join(host.rest, 'files'), { headers, body: JSON.stringify(data) })
95
96
  let re
96
97
  try {
97
98
  re = JSON.parse(response.body)
@@ -1,12 +1,10 @@
1
1
  import { GdcTopMutatedGeneRequest, GdcTopMutatedGeneResponse, Gene } from '#shared/types/routes/gdc.topMutatedGenes.ts'
2
2
  import { mclasscnvgain, mclasscnvloss, dtsnvindel } from '#shared/common.js'
3
3
  import got from 'got'
4
+ import serverconfig from '#src/serverconfig.js'
4
5
 
5
6
  // TODO change to /termdb/topMutatedGenes
6
7
 
7
- const apihost = process.env.PP_GDC_HOST || 'https://api.gdc.cancer.gov'
8
- const apihostGraphql = apihost + (apihost.includes('/v0') ? '' : '/v0') + '/graphql'
9
-
10
8
  export const api = {
11
9
  endpoint: 'gdc/topMutatedGenes',
12
10
  methods: {
@@ -22,7 +20,7 @@ export const api = {
22
20
  }
23
21
  }
24
22
 
25
- function init() {
23
+ function init({ genomes }) {
26
24
  /*
27
25
  genomes parameter is currently not used
28
26
  could be used later to:
@@ -31,8 +29,12 @@ function init() {
31
29
  */
32
30
  return async (req: any, res: any): Promise<void> => {
33
31
  const q: GdcTopMutatedGeneRequest = req.query
32
+ const g = genomes.hg38
33
+ if (!g) throw 'hg38 missing'
34
+ const ds = g.datasets.GDC
35
+ if (!ds) throw 'hg38 GDC missing'
34
36
  try {
35
- const genes = await getGenesGraphql(q)
37
+ const genes = await getGenesGraphql(q, ds)
36
38
  const payload: GdcTopMutatedGeneResponse = { genes }
37
39
  res.send(payload)
38
40
  } catch (e: any) {
@@ -41,7 +43,10 @@ function init() {
41
43
  }
42
44
  }
43
45
 
44
- const query = `
46
+ // query string copied from v1, works in v2. but v1 are not "cohort-centric and lacks the case_filters: $caseFilters"
47
+ // delete the v1 after soft launch
48
+ const queryV1: any = {
49
+ query: `
45
50
  query GenesTable_relayQuery(
46
51
  $genesTable_filters: FiltersArgument
47
52
  $genesTable_size: Int
@@ -111,131 +116,344 @@ query GenesTable_relayQuery(
111
116
  }
112
117
  }
113
118
  }
114
- `
115
-
116
- async function getGenesGraphql(q: GdcTopMutatedGeneRequest) {
117
- // set type "any" to avoid complains
118
- const variables: any = {
119
- genesTable_filters: {
120
- op: 'and',
121
- content: []
122
- },
123
- genesTable_size: q.maxGenes || 50,
124
- genesTable_offset: 0,
125
- score: 'case.project.project_id',
126
- ssmCase: {
127
- op: 'and',
128
- content: [
129
- {
130
- op: 'in',
131
- content: {
132
- field: 'cases.available_variation_data',
133
- value: ['ssm']
119
+ `,
120
+ getVariables: (q: any) => {
121
+ // set type "any" to avoid complains
122
+ const variables: any = {
123
+ genesTable_filters: { op: 'and', content: [] },
124
+ genesTable_size: q.maxGenes || 50,
125
+ genesTable_offset: 0,
126
+ score: 'case.project.project_id',
127
+ ssmCase: {
128
+ op: 'and',
129
+ content: [
130
+ {
131
+ op: 'in',
132
+ content: {
133
+ field: 'cases.available_variation_data',
134
+ value: ['ssm']
135
+ }
136
+ },
137
+ {
138
+ op: 'NOT',
139
+ content: {
140
+ field: 'genes.case.ssm.observation.observation_id',
141
+ value: 'MISSING'
142
+ }
134
143
  }
135
- },
136
- {
137
- op: 'NOT',
138
- content: {
139
- field: 'genes.case.ssm.observation.observation_id',
140
- value: 'MISSING'
144
+ ]
145
+ },
146
+ geneCaseFilter: {
147
+ content: [
148
+ {
149
+ content: {
150
+ field: 'cases.available_variation_data',
151
+ value: ['ssm']
152
+ },
153
+ op: 'in'
141
154
  }
142
- }
143
- ]
144
- },
145
- geneCaseFilter: {
146
- content: [
147
- {
148
- content: {
149
- field: 'cases.available_variation_data',
150
- value: ['ssm']
151
- },
152
- op: 'in'
153
- }
154
- ],
155
- op: 'and'
156
- },
157
- ssmTested: {
158
- content: [
159
- {
160
- content: {
161
- field: 'cases.available_variation_data',
162
- value: ['ssm']
163
- },
164
- op: 'in'
165
- }
166
- ],
167
- op: 'and'
168
- },
169
- cnvTested: {
170
- op: 'and',
171
- content: [
172
- {
173
- content: {
174
- field: 'cases.available_variation_data',
175
- value: ['cnv']
155
+ ],
156
+ op: 'and'
157
+ },
158
+ ssmTested: {
159
+ content: [
160
+ {
161
+ content: {
162
+ field: 'cases.available_variation_data',
163
+ value: ['ssm']
164
+ },
165
+ op: 'in'
166
+ }
167
+ ],
168
+ op: 'and'
169
+ },
170
+ cnvTested: {
171
+ op: 'and',
172
+ content: [
173
+ {
174
+ content: {
175
+ field: 'cases.available_variation_data',
176
+ value: ['cnv']
177
+ },
178
+ op: 'in'
179
+ }
180
+ ]
181
+ },
182
+ cnvGainFilters: {
183
+ op: 'and',
184
+ content: [
185
+ {
186
+ content: {
187
+ field: 'cases.available_variation_data',
188
+ value: ['cnv']
189
+ },
190
+ op: 'in'
176
191
  },
177
- op: 'in'
178
- }
179
- ]
180
- },
181
- cnvGainFilters: {
182
- op: 'and',
183
- content: [
184
- {
185
- content: {
186
- field: 'cases.available_variation_data',
187
- value: ['cnv']
192
+ {
193
+ content: {
194
+ field: 'cnvs.cnv_change',
195
+ value: ['Gain']
196
+ },
197
+ op: 'in'
198
+ }
199
+ ]
200
+ },
201
+ cnvLossFilters: {
202
+ op: 'and',
203
+ content: [
204
+ {
205
+ content: {
206
+ field: 'cases.available_variation_data',
207
+ value: ['cnv']
208
+ },
209
+ op: 'in'
188
210
  },
189
- op: 'in'
190
- },
191
- {
192
- content: {
193
- field: 'cnvs.cnv_change',
194
- value: ['Gain']
211
+ {
212
+ content: {
213
+ field: 'cnvs.cnv_change',
214
+ value: ['Loss']
215
+ },
216
+ op: 'in'
217
+ }
218
+ ]
219
+ }
220
+ }
221
+
222
+ if (q.filter0) {
223
+ variables.genesTable_filters.content.push(JSON.parse(JSON.stringify(q.filter0)))
224
+ variables.geneCaseFilter.content.push(JSON.parse(JSON.stringify(q.filter0)))
225
+ variables.cnvTested.content.push(JSON.parse(JSON.stringify(q.filter0)))
226
+ variables.cnvGainFilters.content.push(JSON.parse(JSON.stringify(q.filter0)))
227
+ variables.cnvLossFilters.content.push(JSON.parse(JSON.stringify(q.filter0)))
228
+ }
229
+
230
+ if (q.geneFilter == 'CGC') {
231
+ variables.genesTable_filters.content.push(geneCGC())
232
+ variables.geneCaseFilter.content.push(geneCGC())
233
+ variables.cnvTested.content.push(geneCGC())
234
+ variables.cnvGainFilters.content.push(geneCGC())
235
+ variables.cnvLossFilters.content.push(geneCGC())
236
+ }
237
+ return variables
238
+ }
239
+ }
240
+
241
+ const queryV2: any = {
242
+ query: `
243
+ query GenesTable(
244
+ $caseFilters: FiltersArgument
245
+ $genesTable_filters: FiltersArgument
246
+ $genesTable_size: Int
247
+ $genesTable_offset: Int
248
+ $score: String
249
+ $ssmCase: FiltersArgument
250
+ $geneCaseFilter: FiltersArgument
251
+ $ssmTested: FiltersArgument
252
+ $cnvTested: FiltersArgument
253
+ $cnvGainFilters: FiltersArgument
254
+ $cnvLossFilters: FiltersArgument
255
+ $sort: [Sort]
256
+ ) {
257
+ genesTableViewer: viewer {
258
+ explore {
259
+ cases {
260
+ hits(first: 0, case_filters: $ssmTested) {
261
+ total
262
+ }
263
+ }
264
+ filteredCases: cases {
265
+ hits(first: 0, case_filters: $geneCaseFilter) {
266
+ total
267
+ }
268
+ }
269
+ cnvCases: cases {
270
+ hits(first: 0, case_filters: $cnvTested) {
271
+ total
272
+ }
273
+ }
274
+ genes {
275
+ hits(
276
+ first: $genesTable_size
277
+ offset: $genesTable_offset
278
+ filters: $genesTable_filters
279
+ case_filters: $caseFilters
280
+ score: $score
281
+ sort: $sort
282
+ ) {
283
+ total
284
+ edges {
285
+ node {
286
+ id
287
+ numCases: score
288
+ symbol
289
+ name
290
+ cytoband
291
+ biotype
292
+ gene_id
293
+ is_cancer_gene_census
294
+ ssm_case: case {
295
+ hits(first: 0, filters: $ssmCase) {
296
+ total
297
+ }
298
+ }
299
+ cnv_case: case {
300
+ hits(first: 0, filters: $cnvTested) {
301
+ total
302
+ }
303
+ }
304
+ case_cnv_gain: case {
305
+ hits(first: 0, filters: $cnvGainFilters) {
306
+ total
307
+ }
308
+ }
309
+ case_cnv_loss: case {
310
+ hits(first: 0, filters: $cnvLossFilters) {
311
+ total
312
+ }
313
+ }
314
+ }
315
+ }
316
+ }
317
+ }
318
+ }
319
+ }
320
+ }`,
321
+ getVariables: (q: any) => {
322
+ const variables: any = {
323
+ caseFilters: { op: 'and', content: [] },
324
+ genesTable_filters: { op: 'and', content: [] },
325
+ genesTable_size: q.maxGenes || 50,
326
+ genesTable_offset: 0,
327
+ score: 'case.project.project_id',
328
+ ssmCase: {
329
+ op: 'and',
330
+ content: [
331
+ {
332
+ op: 'in',
333
+ content: {
334
+ field: 'cases.available_variation_data',
335
+ value: ['ssm']
336
+ }
195
337
  },
196
- op: 'in'
197
- }
198
- ]
199
- },
200
- cnvLossFilters: {
201
- op: 'and',
202
- content: [
203
- {
204
- content: {
205
- field: 'cases.available_variation_data',
206
- value: ['cnv']
338
+ {
339
+ op: 'NOT',
340
+ content: {
341
+ field: 'genes.case.ssm.observation.observation_id',
342
+ value: 'MISSING'
343
+ }
344
+ }
345
+ ]
346
+ },
347
+ geneCaseFilter: {
348
+ content: [
349
+ {
350
+ content: {
351
+ field: 'cases.available_variation_data',
352
+ value: ['ssm']
353
+ },
354
+ op: 'in'
355
+ }
356
+ ],
357
+ op: 'and'
358
+ },
359
+ ssmTested: {
360
+ content: [
361
+ {
362
+ content: {
363
+ field: 'cases.available_variation_data',
364
+ value: ['ssm']
365
+ },
366
+ op: 'in'
367
+ }
368
+ ],
369
+ op: 'and'
370
+ },
371
+ cnvTested: {
372
+ op: 'and',
373
+ content: [
374
+ {
375
+ content: {
376
+ field: 'cases.available_variation_data',
377
+ value: ['cnv']
378
+ },
379
+ op: 'in'
380
+ }
381
+ ]
382
+ },
383
+ cnvGainFilters: {
384
+ op: 'and',
385
+ content: [
386
+ {
387
+ content: {
388
+ field: 'cases.available_variation_data',
389
+ value: ['cnv']
390
+ },
391
+ op: 'in'
207
392
  },
208
- op: 'in'
209
- },
210
- {
211
- content: {
212
- field: 'cnvs.cnv_change',
213
- value: ['Loss']
393
+ {
394
+ content: {
395
+ field: 'cnvs.cnv_change',
396
+ value: ['Gain']
397
+ },
398
+ op: 'in'
399
+ }
400
+ ]
401
+ },
402
+ cnvLossFilters: {
403
+ op: 'and',
404
+ content: [
405
+ {
406
+ content: {
407
+ field: 'cases.available_variation_data',
408
+ value: ['cnv']
409
+ },
410
+ op: 'in'
214
411
  },
215
- op: 'in'
216
- }
217
- ]
412
+ {
413
+ content: {
414
+ field: 'cnvs.cnv_change',
415
+ value: ['Loss']
416
+ },
417
+ op: 'in'
418
+ }
419
+ ]
420
+ }
218
421
  }
219
- }
220
422
 
221
- if (q.filter0) {
222
- variables.genesTable_filters.content.push(JSON.parse(JSON.stringify(q.filter0)))
223
- variables.geneCaseFilter.content.push(JSON.parse(JSON.stringify(q.filter0)))
224
- variables.cnvTested.content.push(JSON.parse(JSON.stringify(q.filter0)))
225
- variables.cnvGainFilters.content.push(JSON.parse(JSON.stringify(q.filter0)))
226
- variables.cnvLossFilters.content.push(JSON.parse(JSON.stringify(q.filter0)))
423
+ if (q.filter0) {
424
+ variables.caseFilters.content.push(JSON.parse(JSON.stringify(q.filter0)))
425
+ variables.geneCaseFilter.content.push(JSON.parse(JSON.stringify(q.filter0)))
426
+ variables.cnvLossFilters.content.push(JSON.parse(JSON.stringify(q.filter0)))
427
+ variables.cnvGainFilters.content.push(JSON.parse(JSON.stringify(q.filter0)))
428
+ variables.cnvTested.content.push(JSON.parse(JSON.stringify(q.filter0)))
429
+ }
430
+
431
+ if (q.geneFilter == 'CGC') {
432
+ variables.genesTable_filters.content.push(geneCGC())
433
+ variables.cnvLossFilters.content.push(geneCGC())
434
+ variables.cnvGainFilters.content.push(geneCGC())
435
+ }
436
+ return variables
227
437
  }
438
+ }
228
439
 
229
- if (q.geneFilter == 'CGC') {
230
- variables.genesTable_filters.content.push(geneCGC())
231
- variables.geneCaseFilter.content.push(geneCGC())
232
- variables.cnvTested.content.push(geneCGC())
233
- variables.cnvGainFilters.content.push(geneCGC())
234
- variables.cnvLossFilters.content.push(geneCGC())
440
+ async function getGenesGraphql(q: GdcTopMutatedGeneRequest, ds) {
441
+ let query: string, variables: object
442
+ const { host, headers } = ds.getHostHeaders(q)
443
+
444
+ // TODO: change this condition to use host.geneExp != host.rest ???
445
+ if (serverconfig.features?.geneExpHost) {
446
+ // quick fix! this is only set on local dev machines, meaning it's using v1 api; delete this after soft launch!!
447
+ query = queryV1.query
448
+ variables = queryV1.getVariables(q)
449
+ } else {
450
+ // this is not set and should be in qa-orange. it should be like this after softlaunch
451
+ query = queryV2.query
452
+ variables = queryV2.getVariables(q)
235
453
  }
236
454
 
237
- const response = await got.post(apihostGraphql, {
238
- headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
455
+ const response = await got.post(host.graphql, {
456
+ headers,
239
457
  body: JSON.stringify({ query, variables })
240
458
  })
241
459
 
@@ -294,7 +512,7 @@ this api only gets ssm-cases and does not account for cnv cases, will not return
294
512
  thus is replaced by getGenesGraphql
295
513
  async function getGenes(q: GdcTopMutatedGeneRequest) {
296
514
  const _f = q.filter0 || { op: 'and', content: [] } // allow blank filter to test geneset edit ui (without filter)
297
- const response = await got.post(path.join(apihost, '/analysis/top_mutated_genes_by_project'), {
515
+ const response = await got.post(path.join(host.rest, '/analysis/top_mutated_genes_by_project'), {
298
516
  headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
299
517
  body: JSON.stringify({
300
518
  size: q.maxGenes || 50,
package/routes/hicdata.ts CHANGED
@@ -86,7 +86,7 @@ function handle_hicdata(q: HicdataRequest) {
86
86
  }
87
87
  const n1 = Number.parseInt(l[0])
88
88
  const n2 = Number.parseInt(l[1])
89
- const v = Number.parseFloat(l[2])
89
+ const v = q.matrixType == 'oe' ? Math.log(Number.parseFloat(l[2])) : Number.parseFloat(l[2])
90
90
  if (Number.isNaN(n1) || Number.isNaN(n2) || Number.isNaN(v)) {
91
91
  fieldnotnumerical++
92
92
  return
@@ -25,7 +25,7 @@ export const api: any = {
25
25
 
26
26
  function init({ genomes }) {
27
27
  return async (req: any, res: any): Promise<void> => {
28
- const q = req.query as TermdbSingleSampleMutationRequest
28
+ const q: TermdbSingleSampleMutationRequest = req.query
29
29
  let result
30
30
  try {
31
31
  const g = genomes[q.genome]
@@ -2,7 +2,7 @@ import {
2
2
  TermdbTopVariablyExpressedGenesRequest,
3
3
  TermdbTopVariablyExpressedGenesResponse
4
4
  } from '#shared/types/routes/termdb.topVariablyExpressedGenes.ts'
5
- import { gdcGetCasesWithExressionDataFromCohort, apihost, geneExpHost } from '../src/mds3.gdc.js'
5
+ import { gdcGetCasesWithExressionDataFromCohort } from '../src/mds3.gdc.js'
6
6
  import path from 'path'
7
7
  import { run_rust } from '@sjcrh/proteinpaint-rust'
8
8
  import got from 'got'
@@ -142,11 +142,11 @@ function gdcValidateQuery(ds: any, genome: any) {
142
142
  }
143
143
 
144
144
  // change to this when api is available on prod
145
- const url = path.join(geneExpHost, '/gene_expression/gene_selection')
146
-
145
+ const { host, headers } = ds.getHostHeaders(q)
146
+ const url = path.join(host.geneExp, '/gene_expression/gene_selection')
147
147
  try {
148
148
  const response = await got.post(url, {
149
- headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
149
+ headers,
150
150
  body: JSON.stringify(getGeneSelectionArg(q, caseLst))
151
151
  })
152
152