Skip to content

Commit e9105dc

Browse files
Update MITxOnline API Client (#2554)
* remove erroneous duplicate code * update mitxonline api package * fix a ts error
1 parent 2a9dde1 commit e9105dc

File tree

16 files changed

+235
-2846
lines changed

16 files changed

+235
-2846
lines changed

frontends/api/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@
2525
"@testing-library/react": "^16.3.0",
2626
"enforce-unique": "^1.3.0",
2727
"jest": "^29.7.0",
28-
"jest-when": "^3.6.0",
28+
"jest-when": "^3.7.0",
2929
"lodash": "^4.17.21",
3030
"ol-test-utilities": "0.0.0"
3131
},
3232
"dependencies": {
33-
"@mitodl/mitxonline-api-axios": "^2025.9.11",
33+
"@mitodl/mitxonline-api-axios": "^2025.9.26",
3434
"@tanstack/react-query": "^5.66.0",
35-
"axios": "^1.6.3"
35+
"axios": "^1.12.2"
3636
}
3737
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
import { pagesQueries, getPagesDetail } from "./queries"
1+
import { pagesQueries } from "./queries"
22

3-
export { pagesQueries, getPagesDetail }
3+
export { pagesQueries }
Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
import { queryOptions } from "@tanstack/react-query"
2-
import {
3-
// pagesApi,
4-
axiosInstance,
5-
pagesApi,
6-
} from "../../clients"
7-
import { CoursePageList } from "@mitodl/mitxonline-api-axios/v2"
2+
import { pagesApi } from "../../clients"
3+
84
const pagesKeys = {
95
root: ["mitxonline", "pages"],
106
coursePageDetail: (readableId: string) => [
@@ -14,33 +10,16 @@ const pagesKeys = {
1410
],
1511
}
1612

17-
const getPagesDetail = async (readableId: string) => {
18-
// TODO: When MITxOnline is published, API client will support readable_id param.
19-
// The API supports it now, just not the client.
20-
// return pagesApi
21-
// .pagesfieldstypecmsCoursePageRetrieve({ readable_id: readableId })
22-
// .then((res) => res.data)
23-
const todo = (
24-
..._params: Parameters<typeof pagesApi.pagesfieldstypecmsCoursePageRetrieve>
25-
) => {}
26-
// @ts-expect-error See above ... This error will trigger when client is updated.
27-
todo({ readable_id: readableId })
28-
29-
const BASE_PATH =
30-
process.env.NEXT_PUBLIC_MITX_ONLINE_BASE_URL?.replace(/\/+$/, "") ?? ""
31-
32-
const url = `${BASE_PATH}/api/v2/pages/?fields=*&readable_id=${encodeURIComponent(readableId)}&type=cms.CoursePage`
33-
return axiosInstance.get<CoursePageList>(url)
34-
}
35-
3613
const pagesQueries = {
3714
courseDetail: (readableId: string) =>
3815
queryOptions({
3916
queryKey: pagesKeys.coursePageDetail(readableId),
4017
queryFn: async () => {
41-
return getPagesDetail(readableId).then((res) => res.data)
18+
return pagesApi
19+
.pagesfieldstypecmsCoursePageRetrieve({ readable_id: readableId })
20+
.then((res) => res.data)
4221
},
4322
}),
4423
}
4524

46-
export { pagesQueries, pagesKeys, getPagesDetail }
25+
export { pagesQueries, pagesKeys }

frontends/api/src/mitxonline/test-utils/factories/programs.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,15 @@ const program: PartialFactory<V2Program> = (overrides = {}) => {
6363
min_weekly_hours: `${faker.number.int({ min: 1, max: 5 })} hours`,
6464
max_weekly_hours: `${faker.number.int({ min: 6, max: 10 })} hours`,
6565
start_date: faker.date.past().toISOString(),
66+
max_price: faker.number.int({ min: 50, max: 5000 }),
67+
min_price: faker.number.int({ min: 50, max: 5000 }),
68+
enrollment_start: faker.helpers.maybe(() =>
69+
faker.date.past().toISOString(),
70+
),
71+
enrollment_end: faker.helpers.maybe(() =>
72+
faker.date.future().toISOString(),
73+
),
74+
end_date: faker.helpers.maybe(() => faker.date.future().toISOString()),
6675
}
6776

6877
return mergeOverrides<V2Program>(defaults, overrides)

frontends/api/src/mitxonline/test-utils/urls.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ const courses = {
4949

5050
const pages = {
5151
courseDetail: (readableId: string) =>
52-
`${API_BASE_URL}/api/v2/pages/?fields=*&readable_id=${encodeURIComponent(
52+
`${API_BASE_URL}/api/v2/pages/?fields=*&type=cms.CoursePage&readable_id=${encodeURIComponent(
5353
readableId,
54-
)}&type=cms.CoursePage`,
54+
)}`,
5555
}
5656

5757
const organization = {

frontends/api/src/test-utils/mockAxios.ts

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,28 @@ type Method = "get" | "post" | "patch" | "delete"
88

99
type PartialAxiosResponse = Pick<AxiosResponse, "data" | "status">
1010

11-
const alwaysError = (
12-
method: string,
11+
type RequestMaker = (
12+
method: Method,
1313
url: string,
14-
_body?: unknown,
15-
): Promise<PartialAxiosResponse> => {
14+
body?: unknown,
15+
) => Promise<PartialAxiosResponse>
16+
17+
const alwaysError: RequestMaker = (method, url, _body) => {
1618
const msg = `No response specified for ${method} ${url}`
1719
console.error(msg)
1820
throw new Error(msg)
1921
}
2022

23+
const standardizeUrl = (url: string) => {
24+
if (!url.includes("?")) {
25+
return url
26+
}
27+
const [path, queryString] = url.split("?")
28+
const query = new URLSearchParams(queryString)
29+
query.sort()
30+
return `${path}?${query.toString()}`
31+
}
32+
2133
/**
2234
* A jest mock function that makes fake network requests.
2335
*
@@ -29,17 +41,23 @@ const alwaysError = (
2941
* '/some/url/to/thing',
3042
* expect.objectContaining({ some: 'value' }) // request body
3143
* ])
44+
*
45+
* NOTE: URLs called by this function are first
3246
* ```
3347
*/
3448
const makeRequest = jest.fn(alwaysError)
49+
const makeSortedRequest: RequestMaker = (method, url, body) =>
50+
makeRequest(method, standardizeUrl(url), body)
3551

3652
const mockAxiosInstance = {
37-
get: jest.fn((url: string) => makeRequest("get", url, undefined)),
38-
post: jest.fn((url: string, body: unknown) => makeRequest("post", url, body)),
53+
get: jest.fn((url: string) => makeSortedRequest("get", url, undefined)),
54+
post: jest.fn((url: string, body: unknown) =>
55+
makeSortedRequest("post", url, body),
56+
),
3957
patch: jest.fn((url: string, body: unknown) =>
40-
makeRequest("patch", url, body),
58+
makeSortedRequest("patch", url, body),
4159
),
42-
delete: jest.fn((url: string) => makeRequest("delete", url, undefined)),
60+
delete: jest.fn((url: string) => makeSortedRequest("delete", url, undefined)),
4361
request: jest.fn(
4462
(
4563
{
@@ -57,7 +75,11 @@ const mockAxiosInstance = {
5775
// on object shape.
5876
const deserialized =
5977
typeof data === "string" ? JSON.parse(data) : undefined
60-
return makeRequest(method.toLowerCase(), url, deserialized)
78+
return makeSortedRequest(
79+
method.toLowerCase() as Method,
80+
url,
81+
deserialized,
82+
)
6183
},
6284
),
6385
defaults: {}, // OpenAPI Generator accesses this, so it needs to exist
@@ -72,24 +94,16 @@ const expectAnythingOrNil = expect.toBeOneOf([
7294
expect.toBeNil(),
7395
])
7496

75-
const standardizeUrl = <T>(url: T) => {
76-
if (!(typeof url === "string")) return url
77-
if (!url.includes("?")) return url
78-
const [path, queryString] = url.split("?")
79-
const query = new URLSearchParams(queryString)
80-
query.sort()
81-
return `${path}?${query.toString()}`
82-
}
83-
8497
const mockRequest = <T, U>(
8598
method: Method,
8699
url: string,
87100
requestBody: T = expectAnythingOrNil,
88101
responseBody: U | ((req: T) => U) | undefined = undefined,
89102
code: number,
90103
) => {
104+
const urlMatcher = typeof url === "string" ? standardizeUrl(url) : url
91105
when(makeRequest)
92-
.calledWith(method, standardizeUrl(url), requestBody)
106+
.calledWith(method, urlMatcher, requestBody)
93107
.mockImplementation(async () => {
94108
let data
95109
if (isFunction(responseBody)) {
@@ -158,7 +172,7 @@ const setMockResponse = {
158172
{ code = 200, requestBody }: MockResponseOptions = {},
159173
) => mockRequest("patch", url, requestBody, responseBody, code),
160174
/**
161-
* Set mock response for a PATCH request; default response status is 204.
175+
* Set mock response for a DELETE request; default response status is 204.
162176
*
163177
* If `responseBody` is a Promise, the request will resolve to the value of
164178
* `responseBody` when `responseBody` resolves.

frontends/main/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"@emotion/cache": "^11.13.1",
1515
"@emotion/styled": "^11.11.0",
1616
"@mitodl/course-search-utils": "3.3.2",
17-
"@mitodl/mitxonline-api-axios": "^2025.9.11",
17+
"@mitodl/mitxonline-api-axios": "^2025.9.26",
1818
"@mitodl/smoot-design": "^6.17.1",
1919
"@next/bundle-analyzer": "^14.2.15",
2020
"@react-pdf/renderer": "^4.3.0",

0 commit comments

Comments
 (0)