-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(product): Improve product normalization and fix http router wit…
…h tracing (#11724) **What** - Improve product normalization and prevent over fetching data - Fix HTTP router wrap handler with tracing enabled
- Loading branch information
Showing
15 changed files
with
464 additions
and
118 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
"@medusajs/product": patch | ||
"@medusajs/framework": patch | ||
"@medusajs/medusa": patch | ||
--- | ||
|
||
chore(product): Improve product normalization |
5 changes: 5 additions & 0 deletions
5
packages/core/framework/src/http/__fixtures__/routers/admin/fail/route.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { Request, Response } from "express" | ||
|
||
export function GET(req: Request, res: Response) { | ||
throw new Error("Failed") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
packages/medusa/src/instrumentation/__fixtures__/mocks/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { ConfigModule } from "@medusajs/types" | ||
|
||
export const customersGlobalMiddlewareMock = jest.fn() | ||
export const customersCreateMiddlewareMock = jest.fn() | ||
export const storeGlobalMiddlewareMock = jest.fn() | ||
|
||
export const config = { | ||
projectConfig: { | ||
databaseLogging: false, | ||
http: { | ||
authCors: "http://localhost:9000", | ||
storeCors: "http://localhost:8000", | ||
adminCors: "http://localhost:7001", | ||
jwtSecret: "supersecret", | ||
cookieSecret: "superSecret", | ||
}, | ||
}, | ||
featureFlags: {}, | ||
plugins: [], | ||
} satisfies Partial<ConfigModule> |
6 changes: 6 additions & 0 deletions
6
packages/medusa/src/instrumentation/__fixtures__/routers/admin/fail/route.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { MedusaError } from "@medusajs/framework/utils" | ||
import { Request, Response } from "express" | ||
|
||
export function GET(req: Request, res: Response) { | ||
throw new MedusaError(MedusaError.Types.INVALID_DATA, "Failed") | ||
} |
15 changes: 15 additions & 0 deletions
15
packages/medusa/src/instrumentation/__fixtures__/routers/middlewares.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { defineMiddlewares } from "@medusajs/framework" | ||
|
||
export const errorHandlerMock = jest | ||
.fn() | ||
.mockImplementation((err, req, res, next) => { | ||
console.log("errorHandlerMock", err) | ||
return res.status(400).json({ | ||
type: err.code.toLowerCase(), | ||
message: err.message, | ||
}) | ||
}) | ||
|
||
export default defineMiddlewares({ | ||
errorHandler: (err, req, res, next) => errorHandlerMock(err, req, res, next), | ||
}) |
183 changes: 183 additions & 0 deletions
183
packages/medusa/src/instrumentation/__fixtures__/server/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
import { | ||
moduleLoader, | ||
ModulesDefinition, | ||
registerMedusaModule, | ||
} from "@medusajs/modules-sdk" | ||
import { ContainerRegistrationKeys, generateJwtToken } from "@medusajs/utils" | ||
import { asValue } from "awilix" | ||
import express from "express" | ||
import querystring from "querystring" | ||
import supertest from "supertest" | ||
|
||
import { config } from "../mocks" | ||
import { ConfigModule, MedusaContainer } from "@medusajs/types" | ||
import { configManager } from "@medusajs/framework/config" | ||
import { | ||
ApiLoader, | ||
container, | ||
featureFlagsLoader, | ||
logger, | ||
MedusaRequest, | ||
} from "@medusajs/framework" | ||
|
||
function asArray(resolvers) { | ||
return { | ||
resolve: (container) => | ||
resolvers.map((resolver) => container.build(resolver)), | ||
} | ||
} | ||
|
||
/** | ||
* Sets up a test server that injects API Routes using the RoutesLoader | ||
* | ||
* @param {String} rootDir - The root directory of the project | ||
*/ | ||
export const createServer = async (rootDir) => { | ||
const app = express() | ||
|
||
const moduleResolutions = {} | ||
Object.entries(ModulesDefinition).forEach(([moduleKey, module]) => { | ||
moduleResolutions[moduleKey] = registerMedusaModule( | ||
moduleKey, | ||
module.defaultModuleDeclaration, | ||
undefined, | ||
module | ||
)[moduleKey] | ||
}) | ||
|
||
configManager.loadConfig({ | ||
projectConfig: config as unknown as ConfigModule, | ||
baseDir: rootDir, | ||
}) | ||
|
||
container.registerAdd = function (this: MedusaContainer, name, registration) { | ||
const storeKey = name + "_STORE" | ||
|
||
if (this.registrations[storeKey] === undefined) { | ||
this.register(storeKey, asValue([])) | ||
} | ||
const store = this.resolve(storeKey) as Array<any> | ||
|
||
if (this.registrations[name] === undefined) { | ||
this.register(name, asArray(store)) | ||
} | ||
store.unshift(registration) | ||
|
||
return this | ||
}.bind(container) | ||
|
||
container.register(ContainerRegistrationKeys.PG_CONNECTION, asValue({})) | ||
container.register("configModule", asValue(config)) | ||
container.register({ | ||
logger: asValue({ | ||
error: () => {}, | ||
}), | ||
manager: asValue({}), | ||
}) | ||
|
||
app.set("trust proxy", 1) | ||
app.use((req, _res, next) => { | ||
req["session"] = {} | ||
const data = req.get("Cookie") | ||
if (data) { | ||
req["session"] = { | ||
...req["session"], | ||
...JSON.parse(data), | ||
} | ||
} | ||
next() | ||
}) | ||
|
||
await featureFlagsLoader() | ||
await moduleLoader({ container, moduleResolutions, logger }) | ||
|
||
app.use((req, res, next) => { | ||
;(req as MedusaRequest).scope = container.createScope() as MedusaContainer | ||
next() | ||
}) | ||
|
||
await new ApiLoader({ | ||
app, | ||
sourceDir: rootDir, | ||
}).load() | ||
|
||
const superRequest = supertest(app) | ||
|
||
return { | ||
request: async (method, url, opts: any = {}) => { | ||
const { payload, query, headers = {} } = opts | ||
|
||
const queryParams = query && querystring.stringify(query) | ||
const req = superRequest[method.toLowerCase()]( | ||
`${url}${queryParams ? "?" + queryParams : ""}` | ||
) | ||
headers.Cookie = headers.Cookie || "" | ||
if (opts.adminSession) { | ||
const token = generateJwtToken( | ||
{ | ||
actor_id: opts.adminSession.userId || opts.adminSession.jwt?.userId, | ||
actor_type: "user", | ||
app_metadata: { | ||
user_id: | ||
opts.adminSession.userId || opts.adminSession.jwt?.userId, | ||
}, | ||
}, | ||
{ | ||
secret: config.projectConfig.http.jwtSecret!, | ||
expiresIn: "1d", | ||
} | ||
) | ||
|
||
headers.Authorization = `Bearer ${token}` | ||
} | ||
|
||
if (opts.clientSession) { | ||
const token = generateJwtToken( | ||
{ | ||
actor_id: | ||
opts.clientSession.customer_id || | ||
opts.clientSession.jwt?.customer_id, | ||
actor_type: "customer", | ||
app_metadata: { | ||
customer_id: | ||
opts.clientSession.customer_id || | ||
opts.clientSession.jwt?.customer_id, | ||
}, | ||
}, | ||
{ secret: config.projectConfig.http.jwtSecret!, expiresIn: "1d" } | ||
) | ||
|
||
headers.Authorization = `Bearer ${token}` | ||
} | ||
|
||
for (const name in headers) { | ||
if ({}.hasOwnProperty.call(headers, name)) { | ||
req.set(name, headers[name]) | ||
} | ||
} | ||
|
||
if (payload && !req.get("content-type")) { | ||
req.set("Content-Type", "application/json") | ||
} | ||
|
||
if (!req.get("accept")) { | ||
req.set("Accept", "application/json") | ||
} | ||
|
||
req.set("Host", "localhost") | ||
|
||
let res | ||
try { | ||
res = await req.send(JSON.stringify(payload)) | ||
} catch (e) { | ||
if (e.response) { | ||
res = e.response | ||
} else { | ||
throw e | ||
} | ||
} | ||
|
||
return res | ||
}, | ||
} | ||
} |
50 changes: 50 additions & 0 deletions
50
packages/medusa/src/instrumentation/__tests__/index.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { resolve } from "path" | ||
import { errorHandlerMock } from "../__fixtures__/routers/middlewares" | ||
import { createServer } from "../__fixtures__/server" | ||
import { instrumentHttpLayer } from "../index" | ||
import { MedusaError } from "@medusajs/framework/utils" | ||
|
||
jest.setTimeout(30000) | ||
|
||
jest.mock("../../commands/start", () => { | ||
return {} | ||
}) | ||
|
||
describe("HTTP Instrumentation", () => { | ||
let request | ||
|
||
afterEach(function () { | ||
jest.clearAllMocks() | ||
}) | ||
|
||
beforeAll(async function () { | ||
instrumentHttpLayer() | ||
|
||
const rootDir = resolve(__dirname, "../__fixtures__/routers") | ||
|
||
const { request: request_ } = await createServer(rootDir) | ||
|
||
request = request_ | ||
}) | ||
|
||
describe("traceRoute", () => { | ||
it("should be handled by the error handler when a route fails", async () => { | ||
const res = await request("GET", "/admin/fail", { | ||
adminSession: { | ||
jwt: { | ||
userId: "admin_user", | ||
}, | ||
}, | ||
}) | ||
|
||
expect(res.status).toBe(400) | ||
expect(errorHandlerMock).toHaveBeenCalled() | ||
expect(errorHandlerMock).toHaveBeenCalledWith( | ||
new MedusaError(MedusaError.Types.INVALID_DATA, "Failed"), | ||
expect.anything(), | ||
expect.anything(), | ||
expect.anything() | ||
) | ||
}) | ||
}) | ||
}) |
Oops, something went wrong.