ardatan / graphql-mesh

🕸️ GraphQL Federation Framework for any API services such as REST, OpenAPI, Swagger, SOAP, gRPC and more...
https://the-guild.dev/graphql/mesh
MIT License
3.27k stars 339 forks source link

Api source yaml file cannot be read if set with env variables #1304

Closed asherccohen closed 3 years ago

asherccohen commented 3 years ago

Versions:

    "@graphql-mesh/cli": "^0.12.5",
    "@graphql-mesh/config": "^0.11.5",
    "@graphql-mesh/openapi": "^0.10.12",
    "@graphql-mesh/runtime": "^0.10.5",
    "apollo-server": "^2.18.2",
    "dotenv": "^8.2.0",
    "graphql": "^15.4.0",
    "nodemon": "^2.0.6",
    "typescript": "^4.1.2"

    "ts-node": "^9.0.0",
    "ts-node-dev": "^1.0.0"

Context: .meshrc.yaml file can be written with interpolation of environment variables so that one can keep IPs and other tokens in an .env file. This is particularly useful for CI/CD and other staging automation. Dotenv package needs to be installed and imported in server index file like in this codesandbox: https://codesandbox.io/s/musing-tree-8voqb?file=/src/index.ts:0-23

Behavior: When a source is set with env variables I get this error:

TypeError: Cannot read property 'title' of undefined
    at /home/user/dev/graphql-demo/server/dist/handlers/openapi/src/openapi-to-graphql/index.js:503:1
    at Array.map (<anonymous>)
    at preliminaryChecks (/home/user/dev/graphql-demo/server/dist/handlers/openapi/src/openapi-to-graphql/index.js:501:30)
    at translateOpenAPIToGraphQL (/home/user/dev/graphql-demo/server/dist/handlers/openapi/src/openapi-to-graphql/index.js:128:1)
    at createGraphQLSchema (/home/user/dev/graphql-demo/server/dist/handlers/openapi/src/openapi-to-graphql/index.js:73:12)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
    at OpenAPIHandler.getMeshSource (/home/user/dev/graphql-demo/server/dist/handlers/openapi/src/index.js:41:13)
    at /home/user/dev/graphql-demo/server/dist/runtime/src/get-mesh.js:10:24
    at async Promise.all (index 0)
    at Object.getMesh (/home/user/dev/graphql-demo/server/dist/runtime/src/get-mesh.js:9:5)

I have tracked down the source of the issue to this line: https://github.com/Urigo/graphql-mesh/blob/master/packages/utils/src/read-file-or-url.ts#L69 (side note, fetchache looks like a typo).

Then in fetchache (can't find it in the the github repo sorry) I see:

async function fetchache(request, cache) {
    const cacheKey = request.url;
    const entry = await cache.get(cacheKey);
    if (!entry) {
        const response = await crossFetch.fetch(request);

// here the request fails and doesn't find the source yaml hosted at the ip (when set with env variables)

        const policy = new CachePolicy(policyRequestFrom(request), policyResponseFrom(response));
        return storeResponseAndReturnClone(cache, response, policy, cacheKey);
    } 

PS. Finally I also noticed that at this line: https://github.com/Urigo/graphql-mesh/blob/master/packages/handlers/openapi/src/openapi-to-graphql/index.ts#L705 There is a usage of optional chaining which is not compiled correctly as it is kept as:

return oas.info.title

while it should compile to something like:

return ((_a = oas.info) === null || _a === void 0 ? void 0 : _a.get('title')) || '';
ardatan commented 3 years ago

I don't think the problem is caused by using env variables. Does it work well when you write IP addresses manually? fetchache is our internal library that handles HTTP requests by respecting cache headers like browsers but on the server side. :)

https://unpkg.com/@graphql-mesh/openapi@0.10.13/index.cjs.js I can see the correct code in here. Maybe you're using an old version.

asherccohen commented 3 years ago

I don't think the problem is caused by using env variables. Does it work well when you write IP addresses manually? fetchache is our internal library that handles HTTP requests by respecting cache headers like browsers but on the server side. :)

https://unpkg.com/@graphql-mesh/openapi@0.10.13/index.cjs.js I can see the correct code in here. Maybe you're using an old version.

Ok true, I did update packages but some weird cache might have got into the way, a nice wipeout of the node_modules did the trick and now optional chaining is compiled correctly and I passed over the "Cannot read property 'title' of undefined" error even with env variables. Surely and issue that was already fixed.

Great, thanks for that.

asherccohen commented 3 years ago

I need to reopen this to clarify a point.

I have this command to generate the types. "mesh:ts": "graphql-mesh typescript --output ./src/mesh/generated/types.ts"

Once again, if I run this with an env variable set I get:

graphql-mesh typescript

Generates TypeScript typings for the generated mesh

Options:
      --version  Show version number                                   [boolean]
      --help     Show help                                             [boolean]
  -r, --require  Loads specific require.extensions before running the codegen
                 and reading the configuration             [array] [default: []]
      --output                                               [string] [required]

[Error: ENOENT: no such file or directory, stat '/api.yaml'] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'stat',
  path: '/api.yaml'
}

Path is again missing the endpoint from env vars.

ardatan commented 3 years ago

I think you want to load environmental variables from .env file. You need to load dotenv with require parameter; graphql-mesh typescript --require dotenv/config --output ./src/mesh/generated/types.ts

asherccohen commented 3 years ago

Brilliant, tx!