Coder Social home page Coder Social logo

wundergraph / wundergraph Goto Github PK

View Code? Open in Web Editor NEW
2.2K 15.0 148.0 116.38 MB

WunderGraph is a Backend for Frontend Framework to optimize frontend, fullstack and backend developer workflows through API Composition.

Home Page: https://wundergraph.com

License: Apache License 2.0

Dockerfile 0.01% Makefile 0.02% Go 9.75% TypeScript 88.14% Shell 0.17% JavaScript 1.38% CSS 0.33% HTML 0.14% Svelte 0.03% Rust 0.03%
api api-gateway graphql graphql-api api-integration api-management rest rest-api restful-api go

wundergraph's Introduction

wunderctl Star us on GitHub PRs welcome License Apache 2 Enterprise support

Quickstart   •   Website   •   Docs   •   Examples   •   Blog

Join our Discord Server Tweet at us on Twitter

Love WunderGraph? Give us a ⭐ on GitHub!

What is WunderGraph?

WunderGraph is a Backend for Frontend (BFF) Framework designed to optimize Developer Workflows through API Composition.

At its core, WunderGraph combines two patterns, API Gateway and BFF with the concept of a package manager, making API composition as simple as npm install. Our mantra is: Compose, don't integrate.

API Composition is a new pattern that allows you to interact with a heterogeneous set of APIs as if they were a single unified API. This not just eliminates a lot of glue code, but also allows you to reason about the API Dependencies of an application. Do you actually know what APIs and Services your application depends on? WunderGraph can easily answer this question for you, and even gives you analytics and observability into what APIs and Endpoints are used by your application and what the quality of service your API dependencies provide.

WunderGraph in a nutshell

Here's how WunderGraph works:

  1. Compose your APIs
// .wundergraph/wundergraph.config.ts

import { NextJsTemplate } from '@wundergraph/nextjs/dist/template';

// introspect a PostgreSQL database
const pg = introspect.postgresql({
  apiNamespace: 'pg',
  databaseURL: new EnvironmentVariable('PG_DATABASE_URL'),
});

// introspect the Stripe API using OpenAPI
const stripe = introspect.openApiV2({
  apiNamespace: 'stripe',
  source: {
    kind: 'file',
    filePath: './stripe.yaml',
  },
  headers: (builder) => builder.addClientRequestHeader('Authorization', `Bearer ${process.env.STRIPE_SECRET_KEY}`),
});

// introspect the Shopify Storefront API using GraphQL
const shopify = introspect.graphql({
  apiNamespace: 'shopify',
  url: 'https://my-shop.myshopify.com/api/2021-07/graphql.json',
  headers: (builder) =>
    builder.addStaticHeader('X-Shopify-Storefront-Access-Token', new EnvironmentVariable('SHOPIFY_STOREFRONT_TOKEN')),
});

configureWunderGraphApplication({
  // compose the APIs into a unified WunderGraph API
  apis: [pg, stripe, shopify],

  // generate type-safe clients for your Frontend
  codeGenerators: [
    {
      templates: [new NextJsTemplate()],
      path: '../web/components/generated',
    },
  ],
});

WunderGraph allows you to create a code pipeline to introspect and compose multiple APIs into a unified API. This makes it easy to update an API dependency without a single click.

  1. Define an Operation

By combining the introspected APIs, WunderGraph generates a unified GraphQL Schema across all APIs. All we have to do is define an Operation and call it from our Frontend. You can create a GraphQL operation or a TypeScript operation. Both are type-safe. TypeScript operations allows you to add custom logic e.g aggregating data from multiple APIs, defining custom input validation, etc.

GraphQL TypeScript
# .wundergraph/operations/users/ByID.graphql
query ($id: String!) {
  user: pg_findFirstUser(where: { id: { equals: $id } }) {
    id
    email
    name
    bio
  }
}
// .wundergraph/operations/users/CustomByID.ts
import { createOperation, z } from '../../generated/wundergraph.factory';

export default createOperation.query({
  // Input validation
  input: z.object({
    id: z.string(),
  }),
  handler: async ({ input }) => {
    // Call into your virtual graph, type-safe
    const { errors, data } = await operations.query({
      operationName: 'users/ByID',
      input: {
        id: input.id,
      },
    });

    return {
      ...data,
    };
  },
});
  1. Call the Operation from your Frontend

As you define Operations, WunderGraph automatically generates a type-safe client for your Frontend, supporting all major Frontend Frameworks like React, NextJS, Remix, Astro, Svelte, Expo, Vue, etc...

// web/pages/profile.ts

import { useQuery } from '../../components/generated/nextjs';

export default async function ProfilePage(props) {
  const { data } = await useQuery({
    operationName: 'users/CustomByID', // or 'users/ByID'
    input: {
      id: props.params.id,
    },
  });

  return (
    <div>
      <h1>{data.user.id}</h1>
      <p>{data.user.name}</p>
    </div>
  );
}

In the same vein, you could now add Authentication, Authorization, file uploads, etc...

Getting started

The easiest way to get started from scratch is to use the following command:

npx create-wundergraph-app my-project --example nextjs

If you already have an existing project, you can add WunderGraph to it by running:

npx create-wundergraph-app --init

Examples:

We've got a comprehensive list of examples to get you started. The best way to try them out is by cloning the mono-repo.

Advanced Examples:

The WunderGraph Stack

WunderGraph is made up of the three core components:

  • wunderctl: A command line tool to create, deploy and manage your WunderGraph application.
  • SDK: Create, configure & extend your WunderGraph Application with TypeScript.

Core features

  • APIs as Dependencies - Define which data sources your frontend depends on and WunderGraph handles the rest. Say goodbye to unmaintainable glue-code, focus on adding real business value.
  • Backend for Frontend Architecture - WunderGraph lives next to your frontend code, but can also be used stand alone as an API Gateway. Whatever you're building, you can always depend on the same great DX.
  • End-to-End-TypeSafety - Start new projects in minutes with powerful conventions and code generation. WunderGraph generates instant, typesafe API clients, including authentication and file uploads.
  • API Composition with Namespacing - WunderGraph is the only tool that allows you to compose multiple APIs into a single unified API without naming collisions or manual configuration thanks to API namespacing.

Architecture & Key Differentiators

You can learn more about the architecture of WunderGraph and why we’ve built it this way in the architecture section.

How does WunderGraph work

This section provides a high-level overview of how WunderGraph works and its most consumer centric components. For a more thorough introduction, visit the architecture documentation.

After initializing your WunderGraph application, you have a NPM package and a .wundergraph folder. This folder contains the following files:

  • wundergraph.config.ts - The primary config file for your WunderGraph application. Add data-sources and more.
  • wundergraph.operations.ts - Configure authentication, caching and more for a specific or all operations.
  • wundergraph.server.ts - The hooks server to hook into different lifecycle events of your gateway.

As a user of WunderGraph, you add your data-sources and authentication configuration to the wundergraph.config.ts file. You will then define your Operations by creating either a *.graphql or *.ts file in the .wundergraph/operations/ directory. Using GraphQL, you can directly interact with the GraphQL Schema of your data-sources. If you'd like to add more customization, you can also use TypeScript to define custom operations.

All Operations are then compiled into JSON-RPC and served by the WunderGraph Gateway. You can either use one of the generated type-safe clients, or try out the API using the Postman Collection or OpenAPI Specification which will be generated in the .wundergraph/generated directory.

Contributing

Read the CONTRIBUTING.md to learn how to contribute to WunderGraph.

Security

We are thankful for any and all security reports. Please read the SECURITY.md to learn how to report any security concerns to WunderGraph.

Community & Support

  • GitHub Issues. Best for: bugs and errors you encounter using WunderGraph.
  • Email Support. Best for: specific questions around WunderGraph as an early enterprise adopter.
  • Slack Support. Best for: problems with WunderGraph as an enterprise customer.
  • Discord. Best for: sharing your applications and hanging out with the community.
  • Feedback and Feature Requests. Best for: discussing and voting on feature requests and giving feedback to our developers.

Enterprise

We're a small but growing team of API Enthusiasts, thrilled to help you get the best Developer Experience of working with APIs. Our Support Plans are tailored to help your teams get the most out of WunderGraph. We love building close relationships with our customers, allowing us to continuously improve the product and iterate fast. Our sales team is available to talk with you about your project needs, pricing information, support plans, and custom-built features.

Use this Link to contact our sales team for a demo.

wundergraph's People

Contributors

aenimus avatar chronotc avatar daniakash avatar devsergiy avatar fiam avatar ggeijteman-wg avatar github-actions[bot] avatar jensneuse avatar jivusayrus avatar kaleem68 avatar leoalves avatar marcneubauer avatar mjubair avatar olingard avatar pagebakers avatar palerdot avatar rayhughes avatar revosw avatar rpeterson avatar rwest202 avatar samberic avatar sergenarhi avatar shanemaglangit avatar slickstef11 avatar starptech avatar thisisnithin avatar uroslates avatar wunderhawk avatar xzyfer avatar yuribuerov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wundergraph's Issues

🐛 Getting Started missing important information

Bug description

https://wundergraph.com/docs/guides/your_first_wundergraph_application/overview out of date, missing information like where to execute wunderctl

How to reproduce

  1. npm i -g @wundergraph/wunderctl@latest
  2. mkdir test-wundergraph && cd test-wundergraph
  3. wunderctl init
  4. npm install
  5. wunderctl add wundergraph/weather wundergraph/countries
  6. Open the file wundergraph.config.ts to adjust the configuration.
  7. wunderctl generate <-- Error

Expected behavior

Hint the reader to change the folder to .wundergraph or make the wunderctl search in .wundergraph

WunderGraph information

https://wundergraph.com/docs/guides/your_first_wundergraph_application/overview

Environment & setup

  • OS: OS: Windows 10 10.0.19044
  • Node.js version: 16.13.1

WunderCtl Version

Version: 0.90.32
Commit: 386a3d4b66204411dc89da6919aad0bebe524657
Date: 2022-06-06T12:22:22Z
BuiltBy: ci

wunderctl up client generation different from wunderctl generate

Bug description

Hello wundergraph team,

I have created a nextjs project using wunderctl init --template nextjs-postgres-starter and installed all dependencies.

Inside the project, I have created a card model in schema.prisma

model card {
  id          Int    @id @default(autoincrement())
  iconUrl     String
  description String
}

as well as a corresponding "select all" style query inside operations/findCards.graphql

{
  db_findManycard {
    id         
    description 
    iconUrl   
  }
}

When I run wunderctl generate, it is able to create the client as expected.
However, when I run wunderctl up, I get the following error message:

Error parsing operation findCards: Cannot query field "db_findManycard" on type "Query". Did you mean "db_findManyuser"?

How to reproduce

  1. Clone
  2. Run wunderctl generate followed by git diff HEAD~1. Observe proper client generation
  3. Run wunderctl up --debug. Observe generated client undone by wunderctl generate

Expected behavior

Expect wunderctl up to be able to add hot reloading with same output as wunderctl generate.

WunderGraph information

Environment & setup

  • OS: Mac OS
  • Go version: go1.19 darwin/amd64
  • Database: Postgresql
  • Node.js version: 17.9.1
  • Yarn version: 1.22.19

WunderCtl Version

0.97.0

Add support for Fauna Region Groups

Problem

The steps to use Fauna as a data store do work, but only the Classic Region Group works because the Fauna GraphQL API endpoint URL is a static value. To support Region Groups, the endpoint URL needs to be configurable.

Suggested solution

I started a PR in my own fork: faunaee#1

I didn't create the PR in this repo because I was unable to get make test to complete successfully. Details in my PR description.

OpenID Connect provider, oidc.login.xyz, is returning: `Unrecognised client id.` or `Bad query params`

Bug description

OpenID Connect provider, oidc.login.xyz, is returning. Unrecognised client id. or Bad query params

How to reproduce

Created a new client id with Login.xyz

curl -X POST https://oidc.signinwithethereum.org/register \
   -H 'Content-Type: application/json' \
   -d "{\"redirect_uris\": [\"backend.example.com\"]}"

Save variables to .env file

login_xyz_issuer="https://oidc.login.xyz/"
login_xyz_client_id="$login_xyz_client_id" # from curl response
login_xyz_client_secret="$login_xyz_client_secret" # from curl response
login_xyz_redirect_uri="https://backend.example.com" 

Configured cookieBased authProviders.openIdConnect to wundergraph.config.ts

  authProviders.openIdConnect({
    id: 'loginxyz',
    issuer: new EnvironmentVariable('login_xyz_issuer'),
    clientId: new EnvironmentVariable('login_xyz_client_id'),
    clientSecret: new EnvironmentVariable('login_xyz_client_secret'),
  }),
],
authorizedRedirectUris: [
  new EnvironmentVariable('login_xyz_redirect_uri'),
]
secureCookieHashKey: new EnvironmentVariable('WUNDERGRAPH_SECURE_COOKIE_HASH_KEY'), // must be of length 32
secureCookieBlockKey: new EnvironmentVariable('WUNDERGRAPH_SECURE_COOKIE_BLOCK_KEY'), // must be of length 32
csrfTokenSecret: new EnvironmentVariable('WUNDERGRAPH_CSRF_TOKEN_SECRET'), // must be of length 11

Test cookie auth with curl

curl https://backend.example.com/app/main/auth/cookie/authorize/loginxyz?redirect_uri=https://backend.example.com
<a href="https://oidc.login.xyz/authorize?client_id=9445e4ff-2bda-4b8d-8b1b-a9f40a52c133&amp;redirect_uri=http%3A%2F%2Fbackend.example.com%2Fapp%2Fmain%2Fauth%2Fcookie%2Fcallback%2Floginxyz&amp;response_type=code&amp;scope=openid+profile+email&amp;state=O1MDVfjSc35vvMdevV00sQ">Found</a>.

Following the link will return:

Bad query params

Test cookie auth with browser

Unrecognised client id.

Expected behavior

Successful authentication.

WunderGraph information

wundergraph.config.ts - within the steps to reproduce
wundergraph.operations.ts - default
wundergraph.server.ts - default

Environment & setup

  • OS: Gentoo Linux
  • Go version: go version go1.19.2 linux/amd64
  • Database: MongoDB
  • Node.js version: v18.6.0

WunderCtl Version

Version: 0.109.1
Commit: 738ee0e
Date: 2022-09-15T21:53:21Z
BuiltBy: ci

Generated Nextjs starter out of date.

Bug description

I was having issues getting the Nextjs starter running, it turns out the code generated was out of date.

import {
    AuthProviders,
    useLiveQuery,
    useWunderGraph,
    withWunderGraph,
} from '../components/generated/wundergraph.nextjs.integration';

Should be

import {
    AuthProviders,
    useLiveQuery,
    useWunderGraph,
    withWunderGraph,
} from '../components/generated/nextjs';

But when looking at the source, this is looking up to date, so I'm not sure where the issue lies.

https://github.com/wundergraph/wundergraph/blob/main/packages/nextjs-testapp/pages/authentication.tsx

How to reproduce

  1. Install wunderctl with npm
npm i -g wunderctl
  1. Run
wunderctl init --template nextjs-starter -o /some/path

Expected behavior

The app should run without errors.

WunderGraph information

All default

Environment & setup

MacOS m1
Node 14

WunderCtl Version

Version: 0.90.32
Commit: 386a3d4b66204411dc89da6919aad0bebe524657
Date: 2022-06-06T12:25:36Z
BuiltBy: ci

Bump up graphql-go-tools version to improve subscription connections

Bug description

I'm wondering if you can release a new version of graphql-go-tools and then bump up the dependency in this repo? There's a fix that we need to make subscriptions work properly in our app - it's already been merged to the graphql-go-tools master branch back in July but hasn't been included in any release yet.

How to reproduce

N/A

Expected behavior

No response

WunderGraph information

Environment & setup

  • OS:
  • Go version:
  • Database:
  • Node.js version:

WunderCtl Version


@transform Directive failed

Bug description

image

How to reproduce

query MyQuery($code: ID!, $name: String! @internal) {
  countries_country(code: $code) {
    code
    capital @export(as: "name")
    emoji
    name
    weather: _join @transform(get: "weather_getCityByName.weather") {
      weather_getCityByName(name: $name) {
        weather  {
          temperature {
            actual
            feelsLike
          }
        }
      }
    }
  }
}

Expected behavior

No response

WunderGraph information

const weather = introspect.graphql({
  apiNamespace: 'weather',
  url: 'https://graphql-weather-api.herokuapp.com/',
});

const countries = introspect.graphql({
  apiNamespace: 'countries',
  url: 'https://countries.trevorblades.com/',
});

Environment & setup

  • OS:
  • Go version:
  • Database:
  • Node.js version:

WunderCtl Version

111d0c4b05b41c75fc76b3ad23be691582506d5a

Query Fragments Support for Server Driven UI architecture

Problem

My aim is to build SDUI apps.

Server-driven UI composition means I have data structures that are reused frequently and bound to explicit components (...from extremely simple and fine-grained utility components that are composed into larger, more complex and coarse-grained feature-level components).

Example 1: A 'FormattableString' type that includes a value along with the underlying format ('markdown', 'plain-text', 'html', etc). I bind this micro-data-structure a single front-end component for rendering, and another one for editing.
Example 2: A 'comment' data structure paired with a component that can be applied to different entities (that uses the 'FormattableString' component)

Not having fragment support poses two primary development and maintenance problems with a SDUI architecture:

  1. Operations are overly verbose and a challenge to read/write/maintain
  2. Schema changes are painful because of the cascades across all queries (and multiple places in each query)

Currently, Wundergraph (without fragment support) means a sustainable/composable SDUI architecture is not really possible. This is because every detailed piece of data needed for each instance of a reusable component has to be re-re-restated in the query… which is especially tedious with the more fine-grained UI building blocks.

Without fragment support, I also see significant maintenance challenges as my apps mature, and my code base grows …. I love what you are doing with WunderGraph and think it is a brilliant approach (and the right one). Unfortunately, I may have to go another route for a SDUI front-end (which would be a shame, because everything else in WunderGraph is truly awesome).

Suggested solution

I would like to see first-class support of fragments.

Alternatives

My challenge is more of a maintenance and development experience concern, rather than a functional one.

I would be completely satisfied if we just supported the fragment development experience.

I think there is an approach to keep-it-simple and achieve syntactic parity with other GraphQL frameworks.

Adding a translation step that would inline each fragment into each operation before generating the client would support the fragment syntax, but keep the implementation bare-bones.

This means you would support fragments syntactically, have another core GraphQL feature under your belt, and everyone can use existing GraphQL tooling to be more productive.

...It would also give you time to do something fancier with fragments down the road with minimal breaking changes, if any.

Watcher crashes if there are no fragments or webhooks

Bug description

A slightly annoying bug on newer wunderctl versions (I think starting from 0.98.0). If I don't have a .wundergraph/webhooks or .wundergraph/fragments directory, then the watcher crashes with error, e.g.:

error   Could not watch files   {"watcherName": "config-bundler", "error": "lstat /app/services/api/.wundergraph/webhooks: no such file or directory"}

and afterward, any change to .wundergraph will no longer trigger reload.

If I add a dummy fragment and webhook, then hot reload works again.

How to reproduce

  1. Open https://github.com/wundergraph/wundergraph-demo in Gitpod
  2. Update wunderctl to ^0.98.0
  3. Try changing a file in api/.wundergraph/operations
  4. Reload is no longer triggered.

Expected behavior

Hot reload should work in projects without any fragment or webhook.

WunderGraph information

Environment & setup

  • OS:
  • Go version:
  • Database:
  • Node.js version:

WunderCtl Version

Version: 0.99.1
Commit: cdeeda2095e9bf0f356b55a064e2a977db51b8bd
Date: 2022-08-18T19:44:12Z
BuiltBy: ci

Custom request headers not working when using `wunderctl generate`

Bug description

I currently have a GraphQL subgraph written in Apollo, running on NodeJS, exposing a federated schema (ie - the _service field). When trying to use Wundergraph as an Apollo Federated Gateway in a Docker image, in the build layer, I'm getting an HTTP response with a status code of 400 when wunderctl generate is called. The 400 status code from the subgraph occurs when a set of custom headers and the Authorization header are not passed.

Is there a way to specify a set of headers to the wunderctl generate call so it can get the result of the query { _service { sdl } } w/o disabling these required headers on the subgraph?

Below is my Dockerfile:

# Image layer for building the application
FROM node:16-buster-slim as build

# global npm dependencies: recommended to place those dependencies in the non-root user directory
ENV NPM_CONFIG_PREFIX=/home/node/.npm-global
# optionally if you want to run npm global bin without specifying path
ENV PATH=$PATH:/home/node/.npm-global/bin

ARG SUBGRAPH_URLS

RUN apt update
RUN apt install -y curl

WORKDIR /usr/src/app

# rebuild image when package.json or lock has changed
COPY package*.json ./

# install dependencies
RUN npm ci --only=production

# install wunderctl in correct version
RUN curl -s -L https://github.com/wundergraph/wundergraph/releases/download/v0.100.0/wunderctl_0.100.0_Linux_x86_64.tar.gz | tar xzvf - && \
    chmod +x wunderctl && mv wunderctl /usr/local/bin
RUN wunderctl version

# add project artifacts to docker image
ADD . .

# generate your wundergraph application
RUN cd .wundergraph && wunderctl generate

# Image layer for production
FROM node:16-buster-slim as runner
WORKDIR /usr/src/app

# copy entire project and dependencies
COPY --from=build --chown=node:node /usr/src/app/node_modules ./node_modules
COPY --from=build --chown=node:node /usr/src/app/.wundergraph ./.wundergraph
# copy wunderctl to start the server
COPY --from=build --chown=node:node /usr/local/bin/wunderctl /usr/local/bin/wunderctl

# run as non-root user
USER node

WORKDIR .wundergraph

CMD wunderctl start --listen-addr 0.0.0.0:9991 --debug

EXPOSE 9991

and the wundergraph.config.ts file:

import {
    Application,
    configureWunderGraphApplication,
    cors,
    introspect,
} from '@wundergraph/sdk';
import server from './wundergraph.server';
import operations from './wundergraph.operations';

function buildHeaders(builder) {
    return builder
        .addClientRequestHeader('Authorization', 'Authorization')
        .addClientRequestHeader('X-Custom-1', 'X-Custom-1')
        .addClientRequestHeader('X-Custom-2', 'X-Custom-2')
        .addClientRequestHeader('X-Custom-3', 'X-Custom-3');
}

const subgraphUrls = process.env.SUBGRAPH_URLS;
if(!subgraphUrls) {
    throw new Error('No subgraph URLs provided!');
}

const upstreams = subgraphUrls.split(',').map(url => ({
    url,
    headers: buildHeaders
}));

const federatedApi = introspect.federation({
    upstreams
});

const myApplication = new Application({
    name: 'federated-gateway',
    apis: [federatedApi]
});

// configureWunderGraph emits the configuration
configureWunderGraphApplication({
    application: myApplication,
    server,
    operations,
    cors: {
        ...cors.allowAll,
        allowedOrigins: ['https://studio.apollographql.com']
    },
    security: {
        enableGraphQLEndpoint: true,
    },
});

A snippet of the error I receive when building the Docker image is below (the entire error seems to be a debug stack trace that's hundreds of lines long):

[+] Building 30.4s (14/19)                                                                                                                                                                                     
 => [internal] load build definition from Dockerfile                                                                                                                                                      0.0s
 => => transferring dockerfile: 37B                                                                                                                                                                       0.0s
 => [internal] load .dockerignore                                                                                                                                                                         0.0s
 => => transferring context: 34B                                                                                                                                                                          0.0s
 => [internal] load metadata for docker.io/library/node:16-buster-slim                                                                                                                                    0.0s
 => CACHED [build  1/10] FROM docker.io/library/node:16-buster-slim                                                                                                                                       0.0s
 => [internal] load build context                                                                                                                                                                         0.0s
 => => transferring context: 151.03kB                                                                                                                                                                     0.0s
 => [build  2/10] RUN apt update                                                                                                                                                                          4.3s
 => [build  3/10] RUN apt install -y curl                                                                                                                                                                 6.4s
 => [build  4/10] WORKDIR /usr/src/app                                                                                                                                                                    0.0s 
 => [build  5/10] COPY package*.json ./                                                                                                                                                                   0.0s 
 => [build  6/10] RUN npm ci --only=production                                                                                                                                                           15.3s
 => [build  7/10] RUN curl -s -L https://github.com/wundergraph/wundergraph/releases/download/v0.100.0/wunderctl_0.100.0_Linux_x86_64.tar.gz | tar xzvf - &&     chmod +x wunderctl && mv wunderctl /usr  1.7s
 => [build  8/10] RUN wunderctl version                                                                                                                                                                   0.4s
 => [build  9/10] ADD . .                                                                                                                                                                                 0.0s
 => ERROR [build 10/10] RUN cd .wundergraph && wunderctl generate                                                                                                                                         2.2s
------
 > [build 10/10] RUN cd .wundergraph && wunderctl generate:
#15 2.101 uncaught exception, origin: unhandledRejection, error: Error: Request failed with status code 400
#15 2.115 /usr/src/app/node_modules/axios/lib/core/createError.js:16
#15 2.115   var error = new Error(message);
#15 2.115               ^
#15 2.115 
#15 2.115 Error: Request failed with status code 400
#15 2.115     at createError (/usr/src/app/node_modules/axios/lib/core/createError.js:16:15)
#15 2.115     at settle (/usr/src/app/node_modules/axios/lib/core/settle.js:17:12)
#15 2.115     at IncomingMessage.handleStreamEnd (/usr/src/app/node_modules/axios/lib/adapters/http.js:322:11)
#15 2.115     at IncomingMessage.emit (node:events:525:35)
#15 2.115     at endReadableNT (node:internal/streams/readable:1358:12)
#15 2.115     at processTicksAndRejections (node:internal/process/task_queues:83:21) {
#15 2.115   config: {
#15 2.115     transitional: {
#15 2.115       silentJSONParsing: true,
#15 2.115       forcedJSONParsing: true,
#15 2.115       clarifyTimeoutError: false
#15 2.115     },
#15 2.115     adapter: [Function: httpAdapter],
#15 2.115     transformRequest: [ [Function: transformRequest] ],
#15 2.115     transformResponse: [ [Function: transformResponse] ],
#15 2.115     timeout: 0,
#15 2.115     xsrfCookieName: 'XSRF-TOKEN',
#15 2.115     xsrfHeaderName: 'X-XSRF-TOKEN',
#15 2.115     maxContentLength: -1,
#15 2.115     maxBodyLength: -1,
#15 2.115     validateStatus: [Function: validateStatus],
#15 2.115     headers: {
#15 2.115       Accept: 'application/json',
#15 2.115       'Content-Type': 'application/json',
#15 2.115       'User-Agent': 'axios/0.26.1',
#15 2.115       'Content-Length': 27
#15 2.115     },
#15 2.115     method: 'post',
#15 2.115     url: 'https://<redacted>/graphql',
#15 2.115     data: '{"query":"{_service{sdl}}"}'
#15 2.115   },

How to reproduce

  1. Create a Apollo Federation compliant subgraph which returns an HTTP status code of 400 when a custom header (eg - X-Custom-1) isn't provided on the HTTP request.
  2. Create a Dockerfile using the provided one as a template
  3. Build the Docker image
  4. wunderctl generate will fail due with an error saying the HTTP request received a 400 status code

Expected behavior

No response

WunderGraph information

See description.

Environment & setup

  • OS: OSX
  • Go version: version bundled with wunderctl
  • Database: na
  • Node.js version: 16.x

WunderCtl Version

$ wunderctl version
Version: 0.100.0
Commit: b60912fb6ab2830aa19c69f0b593f13f2dd75476
Date: 2022-08-29T14:51:18Z
BuiltBy: ci

Operation does't support graphql Parameter Default Value syntax.

Bug description

Operation does't support graphql Parameter Default Value syntax.

How to reproduce

  1. config datasource
const db_weather = introspect.graphql({
    url: "https://graphql-weather-api.herokuapp.com/", apiNamespace: "weather"
});
  1. Go to 'operations' dic

  2. new file 'testparm.graphsql',the content

query MyQuery($name: String = "bern") {
  weather_getCityByName(name: $name) {
    name
    id
    weather {
      temperature {
        actual
      }
    }
  }
}
  1. Run 'cd wundergraph/.wundergraph && wunderctl up --debug --listen-addr 0.0.0.0:9991'
  2. See error
2022-08-18T09:59:16+08:00	error	EndpointUnavailableHandler	{"Operation": "testparm", "Endpoint": "/operations/testparm", "Help": "The Operation is not properly configured. This usually happens when there is a mismatch between GraphQL Schema and Operation. Please make sure, the Operation is valid. This can be supported best by enabling intellisense for GraphQL within your IDE."}
2022-08-18T09:59:16+08:00	error	registerOperation	{"error": "external: value: $name doesn't satisfy inputType: String!, locations: [], path: [query,weather_getCityByName]"}

Expected behavior

No response

WunderGraph information

Environment & setup

  • OS:
  • Go version:
  • Database:
  • Node.js version:

WunderCtl Version


API returns empty data

Bug description

The endpoint generated by wundergraph returns empty data, though it queries the actual api perfectly fine.

How to reproduce

IDK

Expected behavior

Here is my SelfProfile.graphql file

query Profile {
  fapi_getAccountGetme {
    code
    msg
    data {
      aid
    }
  }
}

These are the console logs i am getting.

--- ClientRequest start ---

GET /fapi/main/operations/SelfProfile HTTP/1.1
Host: localhost:9991
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Cookie: sIdRefreshToken=c82d3f07-5cf8-4d44-a370-3cdc55a1b6de; sAccessToken=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsInZlcnNpb24iOiIyIn0%3D.eyJzZXNzaW9uSGFuZGxlIjoiMjIxNjI4N2YtYjA1YS00YmVkLThjODctYTM5YmY3OWM4Yzk1IiwidXNlcklkIjoiNjMxZGQ2YzUtZTRjMy00OTc1LThjYTMtNjFmMDI2NDMwZWM1IiwicmVmcmVzaFRva2VuSGFzaDEiOiJhYmJjMTNlZmZjMzFjYTI5Yzk0YmQ0MGU0ZjEyMDU4MWM1NGMxYjRmOTAyYWZhMmE3MTAzYjliYjVmMWEwY2Y0IiwicGFyZW50UmVmcmVzaFRva2VuSGFzaDEiOiI2YTMyOWU1OWI1MmZjMWQwMmYzNjJlNjVlNTg1MmU5NDIzODc2ODZjYTQxMmFkZmJjODEwNjdkZjE1ZmQ0MTM3IiwidXNlckRhdGEiOnt9LCJhbnRpQ3NyZlRva2VuIjpudWxsLCJleHBpcnlUaW1lIjoxNjY2MjQ2NDg5OTI2LCJ0aW1lQ3JlYXRlZCI6MTY2NjI0Mjg4OTkyNiwibG1ydCI6MTY2NjI0Mjg4OTkyNn0%3D.NT0b8uPjGh95j5btGO9B5vUxK6SZzTN61SHlaatnWUJ0XHkvqvS%2BjQpDJe0004sBdU1Z%2Blh7p0zKa40isRUZ89w8KEHdjsm0z7cmnVtln%2FfeUkcdmoh%2BcYbaTqc6oGF%2B3rvTySdwpKhqvwVZvw0cLFEdU6CbTKjczbDgIx6R%2B0I7zW8LcuJJArXikerCcyUvH8bSzZ2Tj%2FewWJgMgp0kKm1sPo6sUrEmH%2F8EsuQptM914vCqUoZmAssOATzeK5sGBYmoiV6sq0Qz5yIg0z8mvyqOnG4bfmZTKTR0kXzssH9eLDu7vpGAALrVI43k%2BcW97YQaXSLwQnQiy6cTdd6t9w%3D%3D; sIRTFrontend=c82d3f07-5cf8-4d44-a370-3cdc55a1b6de; sFrontToken=eyJ1aWQiOiI2MzFkZDZjNS1lNGMzLTQ5NzUtOGNhMy02MWYwMjY0MzBlYzUiLCJhdGUiOjE2NjYyNDY0ODk5MjYsInVwIjp7fX0=
Dnt: 1
Sec-Ch-Ua: "Microsoft Edge";v="107", "Chromium";v="107", "Not=A?Brand";v="24"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Sec-Gpc: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.8





--- ClientRequest end ---



--- DebugTransport ---

Request:

GET /account/getme HTTP/1.1
Host: localhost:8080
Accept: application/json
Content-Type: application/json
Cookie: sIdRefreshToken=c82d3f07-5cf8-4d44-a370-3cdc55a1b6de; sAccessToken=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsInZlcnNpb24iOiIyIn0%3D.eyJzZXNzaW9uSGFuZGxlIjoiMjIxNjI4N2YtYjA1YS00YmVkLThjODctYTM5YmY3OWM4Yzk1IiwidXNlcklkIjoiNjMxZGQ2YzUtZTRjMy00OTc1LThjYTMtNjFmMDI2NDMwZWM1IiwicmVmcmVzaFRva2VuSGFzaDEiOiJhYmJjMTNlZmZjMzFjYTI5Yzk0YmQ0MGU0ZjEyMDU4MWM1NGMxYjRmOTAyYWZhMmE3MTAzYjliYjVmMWEwY2Y0IiwicGFyZW50UmVmcmVzaFRva2VuSGFzaDEiOiI2YTMyOWU1OWI1MmZjMWQwMmYzNjJlNjVlNTg1MmU5NDIzODc2ODZjYTQxMmFkZmJjODEwNjdkZjE1ZmQ0MTM3IiwidXNlckRhdGEiOnt9LCJhbnRpQ3NyZlRva2VuIjpudWxsLCJleHBpcnlUaW1lIjoxNjY2MjQ2NDg5OTI2LCJ0aW1lQ3JlYXRlZCI6MTY2NjI0Mjg4OTkyNiwibG1ydCI6MTY2NjI0Mjg4OTkyNn0%3D.NT0b8uPjGh95j5btGO9B5vUxK6SZzTN61SHlaatnWUJ0XHkvqvS%2BjQpDJe0004sBdU1Z%2Blh7p0zKa40isRUZ89w8KEHdjsm0z7cmnVtln%2FfeUkcdmoh%2BcYbaTqc6oGF%2B3rvTySdwpKhqvwVZvw0cLFEdU6CbTKjczbDgIx6R%2B0I7zW8LcuJJArXikerCcyUvH8bSzZ2Tj%2FewWJgMgp0kKm1sPo6sUrEmH%2F8EsuQptM914vCqUoZmAssOATzeK5sGBYmoiV6sq0Qz5yIg0z8mvyqOnG4bfmZTKTR0kXzssH9eLDu7vpGAALrVI43k%2BcW97YQaXSLwQnQiy6cTdd6t9w%3D%3D; sIRTFrontend=c82d3f07-5cf8-4d44-a370-3cdc55a1b6de; sFrontToken=eyJ1aWQiOiI2MzFkZDZjNS1lNGMzLTQ5NzUtOGNhMy02MWYwMjY0MzBlYzUiLCJhdGUiOjE2NjYyNDY0ODk5MjYsInVwIjp7fX0= 



Duration: 25 ms

Response:

HTTP/1.1 200 OK
Content-Length: 315
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Expose-Headers: front-token
Content-Type: application/json; charset=utf-8
Date: Thu, 20 Oct 2022 05:30:13 GMT
Front-Token: eyJ1aWQiOiI2MzFkZDZjNS1lNGMzLTQ5NzUtOGNhMy02MWYwMjY0MzBlYzUiLCJhdGUiOjE2NjYyNDc0MTM1MzgsInVwIjp7fX0=
Set-Cookie: sAccessToken=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsInZlcnNpb24iOiIyIn0%3D.eyJzZXNzaW9uSGFuZGxlIjoiMjIxNjI4N2YtYjA1YS00YmVkLThjODctYTM5YmY3OWM4Yzk1IiwidXNlcklkIjoiNjMxZGQ2YzUtZTRjMy00OTc1LThjYTMtNjFmMDI2NDMwZWM1IiwicmVmcmVzaFRva2VuSGFzaDEiOiJhYmJjMTNlZmZjMzFjYTI5Yzk0YmQ0MGU0ZjEyMDU4MWM1NGMxYjRmOTAyYWZhMmE3MTAzYjliYjVmMWEwY2Y0IiwicGFyZW50UmVmcmVzaFRva2VuSGFzaDEiOm51bGwsInVzZXJEYXRhIjp7fSwiYW50aUNzcmZUb2tlbiI6bnVsbCwiZXhwaXJ5VGltZSI6MTY2NjI0NzQxMzUzOCwidGltZUNyZWF0ZWQiOjE2NjYyNDM4MTM1MzgsImxtcnQiOjE2NjYyNDI4ODk5MjZ9.OGiwpZXZQL3m4uv%2B1end2etO02pBD14uuZEblrDAeJcvtKKmk2wpTFXc0hnGpRqpt4ADVSkNOiIM%2BYafyJAyXjlXGwxUgdKlgnDgDapcxBGgQNlA7pYqpDfr85dSoq1cMhKj%2FNhsBn2sq5eyt0guXAYXmV%2BHMYcg%2FLC5ihep53hEfivfjdOazytFoBJl2%2FrP4wBEvvk3TqZh%2BrLp9kdj88B5IOeiwFpGXbzRnDBSKTYrAYV7pLYcJdllzTsTFoq34aDaQR6uE7W2tkgSDBrbnkP0BKFberRuqubfYX7MtirgJhPFAqJL0gpJn%2FIaJMNk%2FDxPhVKTkpvNEOdx5RodsQ%3D%3D; Path=/; Expires=Thu, 20 Oct 2022 06:30:13 GMT; HttpOnly; SameSite=Lax
Traceparent: 00-fd96ad70526003d65d2152edd3cf624e-74e0891ee44384ef-01

{"code":200,"msg":"OK","data":{"aid":"WQE8DKodOomqZ_HTNxaYo","uid":"631dd6c5-e4c3-4975-8ca3-61f026430ec5","profile":{"pid":"JG2OTM9yLIfzECINpcttW","username":"","display_name":"rtwe🚉te","bio":"I am bio 🚉","gender":"other","location":"s","memorial":false},"created_at":1666201846162,"updated_time":1666202011}}

--- DebugTransport

As you can see the backend api returns the data perfectly fine

{"code":200,"msg":"OK","data":{"aid":"WQE8DKodOomqZ_HTNxaYo","uid":"631dd6c5-e4c3-4975-8ca3-61f026430ec5","profile":{"pid":"JG2OTM9yLIfzECINpcttW","username":"","display_name":"rtwe🚉te","bio":"I am bio 🚉","gender":"other","location":"s","memorial":false},"created_at":1666201846162,"updated_time":1666202011}}

but when I do not receive any data from api generated by wundergraph http://localhost:9991/fapi/main/operations/SelfProfile

image

WunderGraph information

wundergraph.config.ts

import { NextJsTemplate } from "@wundergraph/nextjs/dist/template";
import {
  Application,
  configureWunderGraphApplication,
  cors,
  introspect,
  templates,
} from "@wundergraph/sdk";
import operations from "./wundergraph.operations";
import server from "./wundergraph.server";

const openapi = introspect.openApi({
  apiNamespace: "fapi",
  source: {
    kind: "file",
    filePath: "./swagger.json",
  },
  introspection: {
    pollingIntervalSeconds: 5,
  },
  baseURL: "http://localhost:8080",
  headers: (builder) => builder.addClientRequestHeader("cookie", "cookie"),
});

const myApplication = new Application({
  name: "fapi",
  apis: [openapi],
});

// configureWunderGraph emits the configuration
configureWunderGraphApplication({
  application: myApplication,
  server,
  operations,
  codeGenerators: [
    {
      templates: [
        ...templates.typescript.all,
        templates.typescript.operations,
        templates.typescript.linkBuilder,
      ],
    },
    {
      templates: [templates.typescript.client],
      path: "../components/generated",
    },
    {
      templates: [new NextJsTemplate()],
      path: "../components/generated",
    },
  ],

  cors: {
    ...cors.allowAll,
    allowedOrigins: ["http://localhost:3000"],
  },

  authentication: {},
  security: {
    enableGraphQLEndpoint: process.env.NODE_ENV !== "production",
  },
});

wundergraph.operations.ts

import { configureWunderGraphOperations } from "@wundergraph/sdk";
import type { OperationsConfiguration } from "./generated/wundergraph.operations";
export default configureWunderGraphOperations<OperationsConfiguration>({
  operations: {
    defaultConfig: {
      authentication: {
        required: false,
      },
    },

    queries: (config) => ({
      ...config,
      caching: {
        enable: false,
        staleWhileRevalidate: 60,
        maxAge: 60,
        public: true,
      },
      liveQuery: {
        enable: true,
        pollingIntervalSeconds: 1,
      },
    }),

    mutations: (config) => ({
      ...config,
    }),
    subscriptions: (config) => ({
      ...config,
    }),

    custom: {},
  },
});

wundergraph.server.ts

import { configureWunderGraphServer } from "@wundergraph/sdk";
import type { HooksConfig } from "./generated/wundergraph.hooks";
import type { InternalClient } from "./generated/wundergraph.internal.client";

export default configureWunderGraphServer<HooksConfig, InternalClient>(() => ({
  hooks: {
    queries: {},
    mutations: {},
  },
  graphqlServers: [],
}));

Environment & setup

  • OS: Windows
  • Go version: go version go1.19.2 windows/amd64
  • Node.js version: v18.11.0

WunderCtl Version

Version: 0.92.1
Commit: 1428e7dd68b74c8408d5997bd0997b7e42a66f0d
Date: 2022-06-21T20:12:47Z
BuiltBy: ci

start mode graphql Introspection failure

Bug description

  1. up mode execute this garaphql query success
query IntrospectionQuery {
  __schema {
    queryType {
      name
    }
    mutationType {
      name
    }
    subscriptionType {
      name
    }
    types {
      ...FullType
    }
    directives {
      name
      description
      locations
      args {
        ...InputValue
      }
    }
  }
}

fragment FullType on __Type {
  kind
  name
  description
  fields(includeDeprecated: true) {
    name
    description
    args {
      ...InputValue
    }
    type {
      ...TypeRef
    }
    isDeprecated
    deprecationReason
  }
  inputFields {
    ...InputValue
  }
  interfaces {
    ...TypeRef
  }
  enumValues(includeDeprecated: true) {
    name
    description
    isDeprecated
    deprecationReason
  }
  possibleTypes {
    ...TypeRef
  }
}

fragment InputValue on __InputValue {
  name
  description
  type {
    ...TypeRef
  }
  defaultValue
}

fragment TypeRef on __Type {
  kind
  name
  ofType {
    kind
    name
    ofType {
      kind
      name
      ofType {
        kind
        name
        ofType {
          kind
          name
          ofType {
            kind
            name
            ofType {
              kind
              name
              ofType {
                kind
                name
              }
            }
          }
        }
      }
    }
  }
}
  1. start mode execute above graphql query failure,and enableGraphQLEndpoint is true

wundergraph.config.ts

security: {enableGraphQLEndpoint:true} ,
{
  "errors": [
    {
      "message": "unable to resolve",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "__schema"
      ]
    }
  ],
  "data": null
}
  1. start mode execute other graphql query success,for example
query {
  gql_hello
}

4.try to debug ,get this error

image

How to reproduce

  1. Go to '...'
  2. Change '....'
  3. Run '....'
  4. See error

Expected behavior

No response

WunderGraph information

Environment & setup

  • OS:
  • Go version:
  • Database:
  • Node.js version:

WunderCtl Version

commit 111d0c4b05b41c75fc76b3ad23be691582506d5a

mutatingPostResolveHook not returning data.

Bug description

Hi, I am trying to use the mutatingPostResolve hook and the go process is not returning the value returned from the post resolve hook.
Without the post resolve hook, everything works perfectly.

The request is traveling to the resolving API, back, then to the mutating hook, then the correct value is coming back, but then no data is returned to the initiating client. The body is entirely empty.

Here is the info from the stdout:

--- ClientRequest start ---

GET /api/main/operations/coreGIGet?id=0 HTTP/1.1
Host: localhost:9991
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.5
Connection: keep-alive
Cookie: token=14402056-ebb1-466e-b968-3fee014eb778
Dnt: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: cross-site
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:101.0) Gecko/20100101 Firefox/101.0





--- ClientRequest end ---



--- DebugTransport ---

Request:

POST / HTTP/1.1
Host: localhost:8000
Accept: application/json
Content-Type: application/json

{"variables":{"id":0},"query":"query($id: Int!){objects: sObjects(ids: [$id]){description image labels}}"}

Duration: 117 ms

Response:

HTTP/1.1 200 OK
Content-Length: 70
Content-Type: application/json
Date: Fri, 03 Jun 2022 04:00:07 GMT
Server: uvicorn

{"data":{"objects":[{"description":null,"image":null,"labels":null}]}}

--- DebugTransport

2022/06/03 14:00:08 [DEBUG] POST http://127.0.0.1:9992/operation/coreGIGet/mutatingPostResolve
{"level":30,"time":1654228808432,"pid":316252,"hostname":"my-host","reqId":"req-1","req":{"method":"POST","url":"/operation/coreGIGet/mutatingPostResolve","hostname":"127.0.0.1:9992","remoteAddress":"127.0.0.1","remotePort":41122},"msg":"incoming request"}
received data: {"data":{"objects":[{"description":null,"image":null,"labels":null}]}}
{"level":30,"time":1654228808448,"pid":316252,"hostname":"my-host","reqId":"req-1","res":{"statusCode":200},"responseTime":13.967247009277344,"msg":"request completed"}

Below are the captures from wireshark for the mutating post resolve side:

Here is the request to the mutating post resolver:

EL*@@í7 ¢'ÜW´Uí
@Æí@ÆìPOST /operation/coreGIGet/mutatingPostResolve HTTP/1.1
Host: 127.0.0.1:9992
User-Agent: Go-http-client/1.1
Content-Length: 673
Content-Type: application/json
Accept-Encoding: gzip

{"__wg":{"client_request":{"method":"GET","requestURI":"/api/main/operations/coreGIGet?id=0","headers":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.5","Connection":"keep-alive","Cookie":"token=14402056-ebb1-466e-b968-3fee014eb778","Dnt":"1","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"cross-site","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:101.0) Gecko/20100101 Firefox/101.0"}}},"input":{"id":0},"response":{"data":{"objects":[{"description":null,"image":null,"labels":null}]}}}

And here is the response:

E}Ã@@x_' ¢´UíÜ"·ÿq
@Ç@ÆíHTTP/1.1 200 OK
content-type: application/json; charset=utf-8
content-length: 158
Date: Fri, 03 Jun 2022 04:00:08 GMT
Connection: keep-alive
Keep-Alive: timeout=5

{"op":"coreGIGet","hook":"mutatingPostResolve","input":{"data":{"objects":[{"description":null,"image":null,"labels":null}]}},"setClientRequestHeaders":{}}

Here is the HAR extract from the final response to the browser:

        "response": {
          "status": 200,
          "statusText": "OK",
          "httpVersion": "HTTP/1.1",
          "headers": [
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "ETag",
              "value": "W/\"17241709254077376921\""
            },
            {
              "name": "Vary",
              "value": "Origin"
            },
            {
              "name": "Date",
              "value": "Fri, 03 Jun 2022 04:33:00 GMT"
            },
            {
              "name": "Content-Length",
              "value": "0"
            }
          ],
          "cookies": [],
          "content": {
            "mimeType": "application/json",
            "size": 0,
            "text": ""
          },
          "redirectURL": "",
          "headersSize": 153,
          "bodySize": 153
        }

From looking at the above information, If I was to guess why this is failing, I would say it's because the mutatingPostResolve hook is populating the "input" field with the response data on the response from the mutatingpostresolve hook (the wireshark capture)

How to reproduce

Create a mutatingPostResolveHook and see if it returns the correct data

Expected behavior

The correct data is returned from the hook.

WunderGraph information

here is the hook definition:
It just returns the unmodified data (I removed all mutations when I had issues)

        queries: {
            coreGIGet: {
                async mutatingPostResolve(ctx: Context, input: coreGIGetInput, response) {
                    console.log(`received data: ${JSON.stringify(response)}`)
                    return response
                },
            },
        },

Environment & setup

node: v14.17.6
@wundergraph/sdk: 0.90.6
linux

WunderCtl Version

0.90.25

up mode, file path error.

Bug description

up mode, file path error.

Expect add AbsWorkingDir at initialBuild function in bundleconfig.go file.

image

How to reproduce

  1. Go to '/cmd/wunderctl'
  2. Change 'nothing'
  3. Run 'go run main.go up --debug true --wundergraph-dir ../../examples/simple/.wundergraph'
  4. See error
2022-05-28T15:12:38+08:00       debug   starting without env file
2022-05-28T15:12:38+08:00       info    starting WunderNode     {"version": "dev", "commit": "unknown", "date": "unknown", "builtBy": "unknown"}
2022-05-28T15:12:38+08:00       fatal   Config Bundler: initial build failed    {"bundler": "config", "outFile": "../../examples/simple/.wundergraph/generated/bundle/config.js", "errors": [{"PluginName":"","Text":"The entry point \"wundergraph.config.ts\" cannot be marked as external","Location":null,"Notes":null,"Detail":null}]}
exit status 1

Expected behavior

No response

WunderGraph information

Environment & setup

  • OS: Mac OS
  • Go version: go version go1.17.5 darwin/amd64
  • Node.js version: v16.13.1

WunderCtl Version

2b16f96

OAS introspection failed due to top level endpoint

Bug description

I have an issue when introspecting hapi-fhir open api spec
I don't know if you are parsing the specification manually or with some sort of library
bu it seems to be an issue with top level paths

this is the OAS file
hapi_fhir_v601.txt

I have tried to debug a little

"/": {
      "post": {
        "tags": ["System Level Operations"],
        "summary": "server-transaction: Execute a FHIR Transaction (or FHIR Batch) Bundle",
        "requestBody": {
          "content": {
            "application/fhir+json": {
              "schema": {
                "$ref": "#/components/schemas/FHIR-JSON-RESOURCE"

The problem seems to be related to top level paths which produce an empty array, this is the error msg

TypeError: Reduce of empty array with no initial value
    at Array.reduce (<anonymous>)
    at RESTApiBuilder.resolveFieldName (/Users/mac/Desktop/Project/node_modules/@wundergraph/sdk/dist/v2openapi/index.js:943:47)
    at RESTApiBuilder.traversePath 

So the reduce methode throw an exeption in this function

this.resolveFieldName = (operationObject, path, verb) => {
            if (operationObject.operationId) {
                if (operationObject.operationId.startsWith('/')) {
                    return operationObject.operationId.substring(1);
                }
                return operationObject.operationId;
            }
            
            const formattedPath = path
                .split('/')
                .filter((element) => element !== '')
                .reduce((prev, current) => {
                var _a;
                if (current.startsWith('{') && current.endsWith('}')) {
                    const trimmed = current.substring(1, current.length - 1);
                    return prev + 'By' + trimmed[0].toUpperCase() + trimmed.substring(1);
                }
                return prev + ((_a = current[0]) === null || _a === void 0 ? void 0 : _a.toUpperCase()) + current.substring(1);
            });
            return (0, protobuf_1.hTTPMethodToJSON)(verb).toLowerCase() + formattedPath[0].toUpperCase() + formattedPath.substring(1);
        };

How to reproduce

when introspecting the OAS file

Expected behavior

No response

WunderGraph information

wundergraph.config.ts

const hapiFHIR = introspect.openApi({
  apiNamespace: 'hapi',

  source: {
    kind: 'file',
    filePath: 'OpenApiSpec/hapi_fhir_v601.json',
  },
});

const myApplication = new Application({
  name: 'app',
  apis: [
    managementAPI,
    hapiFHIR,
    /*federatedApi,
        openAPI,
        graphQLAPI*/
  ],
});

Environment & setup

  • OS: Mac OS
  • Node.js version: 17
  • OAS 3

WunderCtl Version

Version: 0.94.3
Commit: 70980d17822bbd270c436541066260618e26ec16
Date: 2022-07-15T18:52:07Z
BuiltBy: ci

Failed to use Postgraphile as a graphql datasource

Bug description

an error occurred and the code could not be generated

only working with option --skip-plugins graphile-build:NodePlugin

How to reproduce

run postgrapgphile

postgraphile -c 'postgres://storeo:storeo@localhost:5433/storeo' --watch --enhance-graphiql --dynamic-json

setup datasource
wundergraph.config.ts

const postgraphile = introspect.graphql({
    apiNamespace: 'pg',
    url: 'http://localhost:5000/graphql'
})

const myApplication = new Application({
    name: 'app',
    apis: [
        postgraphile
    ],
});

run wunderctl

wunderctl generate  --env .env

error

2:58:38 PM: wundergraph.app.schema.graphql updated
Error: Interface field pg_Node.nodeId expected but Query does not provide it.
    at assertValidSchema (/home/minhdtb/projects/storeo/storeo-backend/node_modules/graphql/type/validate.js:59:11)
    at validate (/home/minhdtb/projects/storeo/storeo-backend/node_modules/graphql/validation/validate.js:63:35)
    at Object.enter (/home/minhdtb/projects/storeo/storeo-backend/node_modules/@wundergraph/sdk/dist/graphql/operations.js:47:59)
    at visit (/home/minhdtb/projects/storeo/storeo-backend/node_modules/graphql/language/visitor.js:197:21)
    at parseOperations (/home/minhdtb/projects/storeo/storeo-backend/node_modules/@wundergraph/sdk/dist/graphql/operations.js:30:29)
    at /home/minhdtb/projects/storeo/storeo-backend/node_modules/@wundergraph/sdk/dist/configure/index.js:350:61
    at processTicksAndRejections (node:internal/process/task_queues:96:5)





--->
No Operations found! Please create at least one Operation in the directory ./operations
Operation files must have the file extension '.graphql', otherwise they are ignored.
Operations don't need to be named, the file name is responsible for the operation name.
<---

Expected behavior

working as expected

WunderGraph information

N/A

Environment & setup

OS: Ubuntu
Go version: go1.17.2 linux/amd64
Database: PostgreSQL
Node.js version: v16.15.1

WunderCtl Version

Version: 0.90.32
Commit: 386a3d4b66204411dc89da6919aad0bebe524657
Date: 2022-06-06T12:21:43Z
BuiltBy: ci

Many to Many relation Prisma introspection broken: uses Entity name instead of field name

Bug description

Name of fields in the GraphQL schema after Prisma introspection are wrong: the field name uses Entity name instead of field name

How to reproduce

  1. Create project with the nextjs-postgres template
  2. Replace the prisma Schema with
datasource db {
  provider = "postgresql"
  url      = "postgresql://admin:admin@localhost:54322/example?schema=public"
}

model User {
  id    Int    @id @default(autoincrement())
  email String @unique
  name  String
  posts Post[]
}

model Post {
  id       Int  @id @default(autoincrement())
  authorId Int
  author   User @relation(fields: [authorId], references: [id])
}
  1. Go on http://localhost:9991/app/main/graphql
  2. You cannot issue this query:
{
  db_findFirstUser {
    posts {
      id
    }
  }
}
  1. But this query:
{
  db_findFirstUser {
    Post {
      id
    }
  }
}

Expected behavior

In step 4 and five above, I'd expect:

  1. You can issue this query:
{
  db_findFirstUser {
    posts {
      id
    }
  }
}
  1. But not this query:
{
  db_findFirstUser {
    Post {
      id
    }
  }
}

WunderGraph information

All default from running npx -y @wundergraph/wunderctl init --template nextjs-postgres-starter today

Environment & setup

  • OS: MacOS
  • Go version: no go found
  • Database: Postgres
  • Node.js version: 16.15.0

WunderCtl Version

npm run wunderctl version

> [email protected] wunderctl
> wunderctl "version"

Version: 0.93.4
Commit: 0a97083cf60de6d7765077edd21d0385f00f4782
Date: 2022-06-30T17:09:28Z
BuiltBy: ci

hooks server 9992 port is occupied.

Bug description

Hooks port 9992 not killed when Wg process terminates.

How to reproduce

  1. Run 'wunderctl up --debug --listen-addr 0.0.0.0:9991'
  2. See error
{"level":30,"time":1660807160760,"pid":79013,"hostname":"ansondeMacBook-Pro.local","msg":"Hooks plugin registered"}
{"level":50,"time":1660807160765,"pid":79013,"hostname":"ansondeMacBook-Pro.local","code":"EADDRINUSE","errno":-48,"syscall":"listen","address":"127.0.0.1","port":9992,"stack":"Error: listen EADDRINUSE: address already in use 127.0.0.1:9992\n    at Server.setupListenHandle [as _listen2] (node:net:1334:16)\n    at listenInCluster (node:net:1382:12)\n    at doListen (node:net:1520:7)\n    at processTicksAndRejections (node:internal/process/task_queues:84:21)","type":"Error","msg":"Could not start the hook server"}
2022-08-18T15:19:20+08:00       fatal   Config Bundler: error executing script  {"bundler": "server", "error": "exit status 1"}
  1. Run 'lsof -i:9992'
COMMAND   PID  USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
node    76119 anson   22u  IPv4 0xb571adce244db49d      0t0  TCP localhost:palace-1 (LISTEN)
  1. Run 'kill 76119 '
  2. Run 'wunderctl up --debug --listen-addr 0.0.0.0:9991'
  3. success

Expected behavior

No response

WunderGraph information

Environment & setup

  • OS:
  • Go version:
  • Database:
  • Node.js version:

WunderCtl Version

Version: 0.94.5
Commit: 7b5e6108ec00cb5de98235f33c07b612415dc346
Date: 2022-07-18T09:13:16Z
BuiltBy: ci

Improve wunderctl generate error messages to aid in debugging

Bug description

When I run wunderctl generate I receive an error. The message is not particularly helpful for debugging. Can this include the file and line number so I know where to start looking for the empty data variable?

> wunderctl generate
Couldn't configure your WunderNode: Error: could not resolve empty data variable: undefined
Error: configuration could not be generated. Process exit with code 1
2022-10-16T07:25:47-07:00       error   Script runner exited with error {"runnerName": "config-runner", "exit": 1, "startTs": 1665930347155262000, "stopTs": 1665930347457188000, "complete": true}

How to reproduce

Expected behavior

No response

WunderGraph information

Environment & setup

  • OS: Mac OS
  • Go version: go version go1.18 darwin/arm64
  • Database: PostgreSQL
  • Node.js version: v17.6.0

WunderCtl Version

Version: 0.111.4
Commit: 4e9eb8f7500fa37afa524890cae122cf801033b9
Date: 2022-10-10T17:58:54Z
BuiltBy: ci

resolve: ENG-808

Implement the Apollo Federation Subgraph Specification

Problem

Per @jensneuse , WunderGraph does not currently support the Apollo Federation Subgraph spec (https://discord.com/channels/738739428314316823/896563324278415370/1003923461493760060) and is not listed at on the compatibility matrix located at https://github.com/apollographql/apollo-federation-subgraph-compatibility.

Suggested solution

Implement the subgraph specification to be compatible at whatever level of the spec which is appropriate.

Alternatives

n/a

Additional context

n/a

Requesting list of records with null foreign key relationship mix up the response and makes data integrity issue

Bug description

As you can see in the below query, i am requesting list of orders, each order has federated query with Branch, not all orders have a branch hence when the branch id is null, wundergraph returned mixed data, basically in the response you will see for each order record responses are correct until it reach the first null branch and it will start mixing data

query orderslist($first: Int){
  orders(first:$first) {
    edges {
      node {
        number
        id
        branch {
            name
            id
        }
      }
    }
  }
}

Variables:

{
  "first": 100
}

---------------------------------------------federated query
branch service query as you see the problem is in {"__typename":"Branch"} basically it request with no id on go-tools it requests with {"id":null,"__typename":"Branch"}, i dont believe this should be request, and wondergraph should not expect other than graph, I tried same scnario on appolo and it does not request null id:

Query

query($representations: [_Any!]!){
  _entities(representations: $representations)
  {... on Branch {name, id}
  }
}

Variables

{"representations":[{"__typename":"Branch","id":"QnJhbmNoOjkx"},{"__typename":"Branch","id":"QnJhbmNoOjY4"},{"__typename":"Branch","id":"QnJhbmNoOjEzNw=="},{"__typename":"Branch","id":"QnJhbmNoOjEzNA=="},{"__typename":"Branch","id":"QnJhbmNoOjEyNw=="},{"__typename":"Branch","id":"QnJhbmNoOjE3"},{"__typename":"Branch","id":"QnJhbmNoOjQ3"},{"__typename":"Branch"},{"__typename":"Branch","id":"QnJhbmNoOjE3OQ=="},{"__typename":"Branch","id":"QnJhbmNoOjEwNA=="},{"__typename":"Branch","id":"QnJhbmNoOjc0"}]}

federated response :

{
    "data": {
      "_entities": [
        {
          "name": "Branch 1"
        },
        {
          "name": "Branch 2"
        },
        {
          "name": "Branch 3"
        },
        {
          "name": "Branch 4"
        },
        {
          "name": "Branch 5"
        },
        {
          "name": "Branch 7"
        },
        {
          "name": "Branch 9"
        },
        null,
        {
          "name": "Branch 6"
        },
        {
          "name": "Branch 10"
        },
        {
          "name": "Branch 8"
        }
      ]
    }
  }

-----------------------------------Response-----------------------------------

{
    "data": {
        "orders": {
            "edges": [
                {
                    "node": {
                        "number": "628",
                        "id": "T3JkZXI6NjI4",
                        "branch": {
                            "name": "Branch 1",
                            "id": "QnJhbmNoOjkx"
                        }
                    }
                },
                {
                    "node": {
                        "number": "627",
                        "id": "T3JkZXI6NjI3",
                        "branch": {
                            "name": "Branch 2",
                            "id": "QnJhbmNoOjY4"
                        }
                    }
                },
                {
                    "node": {
                        "number": "626",
                        "id": "T3JkZXI6NjI2",
                        "branch": {
                            "name": "Branch 3",
                            "id": "QnJhbmNoOjEzNw=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "625",
                        "id": "T3JkZXI6NjI1",
                        "branch": {
                            "name": "Branch 4",
                            "id": "QnJhbmNoOjEzNA=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "624",
                        "id": "T3JkZXI6NjI0",
                        "branch": {
                            "name": "Branch 5",
                            "id": "QnJhbmNoOjEyNw=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "623",
                        "id": "T3JkZXI6NjIz",
                        "branch": {
                            "name": "Branch 7",
                            "id": "QnJhbmNoOjE3"
                        }
                    }
                },
                {
                    "node": {
                        "number": "620",
                        "id": "T3JkZXI6NjIw",
                        "branch": {
                            "name": "Branch 9",
                            "id": "QnJhbmNoOjQ3"
                        }
                    }
                },
                {
                    "node": {
                        "number": "605",
                        "id": "T3JkZXI6NjA1",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "596",
                        "id": "T3JkZXI6NTk2",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjE3OQ=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "594",
                        "id": "T3JkZXI6NTk0",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "584",
                        "id": "T3JkZXI6NTg0",
                        "branch": {
                            "name": "Branch 6",
                            "id": "QnJhbmNoOjE3"
                        }
                    }
                },
                {
                    "node": {
                        "number": "583",
                        "id": "T3JkZXI6NTgz",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "575",
                        "id": "T3JkZXI6NTc1",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjEwNA=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "572",
                        "id": "T3JkZXI6NTcy",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "564",
                        "id": "T3JkZXI6NTY0",
                        "branch": {
                            "name": "Branch 7",
                            "id": "QnJhbmNoOjEwNA=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "561",
                        "id": "T3JkZXI6NTYx",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "540",
                        "id": "T3JkZXI6NTQw",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjE3OQ=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "538",
                        "id": "T3JkZXI6NTM4",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "530",
                        "id": "T3JkZXI6NTMw",
                        "branch": {
                            "name": "Branch 10",
                            "id": "QnJhbmNoOjEwNA=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "527",
                        "id": "T3JkZXI6NTI3",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "523",
                        "id": "T3JkZXI6NTIz",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjEwNA=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "516",
                        "id": "T3JkZXI6NTE2",
                        "branch": {
                            "name": "Branch 10",
                            "id": "QnJhbmNoOjEzNA=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "511",
                        "id": "T3JkZXI6NTEx",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "505",
                        "id": "T3JkZXI6NTA1",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjE3"
                        }
                    }
                },
                {
                    "node": {
                        "number": "496",
                        "id": "T3JkZXI6NDk2",
                        "branch": {
                            "name": "Branch 6",
                            "id": "QnJhbmNoOjE3OQ=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "494",
                        "id": "T3JkZXI6NDk0",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "487",
                        "id": "T3JkZXI6NDg3",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjEyNw=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "483",
                        "id": "T3JkZXI6NDgz",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "474",
                        "id": "T3JkZXI6NDc0",
                        "branch": {
                            "name": "Branch 10",
                            "id": "QnJhbmNoOjE3OQ=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "472",
                        "id": "T3JkZXI6NDcy",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "463",
                        "id": "T3JkZXI6NDYz",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjE3OQ=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "461",
                        "id": "T3JkZXI6NDYx",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "452",
                        "id": "T3JkZXI6NDUy",
                        "branch": {
                            "name": "Branch 10",
                            "id": "QnJhbmNoOjE3OQ=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "450",
                        "id": "T3JkZXI6NDUw",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "433",
                        "id": "T3JkZXI6NDMz",
                        "branch": {
                            "name": "Branch 4",
                            "id": "QnJhbmNoOjE3OQ=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "431",
                        "id": "T3JkZXI6NDMx",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "422",
                        "id": "T3JkZXI6NDIy",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjE3OQ=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "420",
                        "id": "T3JkZXI6NDIw",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "410",
                        "id": "T3JkZXI6NDEw",
                        "branch": {
                            "name": "Branch 7",
                            "id": "QnJhbmNoOjc0"
                        }
                    }
                },
                {
                    "node": {
                        "number": "404",
                        "id": "T3JkZXI6NDA0",
                        "branch": {
                            "name": "Branch 6",
                            "id": "QnJhbmNoOjE3OQ=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "402",
                        "id": "T3JkZXI6NDAy",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "399",
                        "id": "T3JkZXI6Mzk5",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjc0"
                        }
                    }
                },
                {
                    "node": {
                        "number": "393",
                        "id": "T3JkZXI6Mzkz",
                        "branch": {
                            "name": "Branch 5",
                            "id": "QnJhbmNoOjE3OQ=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "391",
                        "id": "T3JkZXI6Mzkx",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "385",
                        "id": "T3JkZXI6Mzg1",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjEzNA=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "380",
                        "id": "T3JkZXI6Mzgw",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "364",
                        "id": "T3JkZXI6MzY0",
                        "branch": {
                            "name": "Branch 6",
                            "id": "QnJhbmNoOjE3OQ=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "362",
                        "id": "T3JkZXI6MzYy",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "359",
                        "id": "T3JkZXI6MzU5",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjc0"
                        }
                    }
                },
                {
                    "node": {
                        "number": "356",
                        "id": "T3JkZXI6MzU2",
                        "branch": {
                            "name": "Branch 6",
                            "id": "QnJhbmNoOjEzNA=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "353",
                        "id": "T3JkZXI6MzUz",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjE3OQ=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "351",
                        "id": "T3JkZXI6MzUx",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "345",
                        "id": "T3JkZXI6MzQ1",
                        "branch": {
                            "name": "Branch 6",
                            "id": "QnJhbmNoOjEzNA=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "340",
                        "id": "T3JkZXI6MzQw",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "337",
                        "id": "T3JkZXI6MzM3",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjc0"
                        }
                    }
                },
                {
                    "node": {
                        "number": "334",
                        "id": "T3JkZXI6MzM0",
                        "branch": {
                            "name": "Branch 6",
                            "id": "QnJhbmNoOjEzNA=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "331",
                        "id": "T3JkZXI6MzMx",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjE3OQ=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "329",
                        "id": "T3JkZXI6MzI5",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "315",
                        "id": "T3JkZXI6MzE1",
                        "branch": {
                            "name": "Branch 6",
                            "id": "QnJhbmNoOjEzNA=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "310",
                        "id": "T3JkZXI6MzEw",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "309",
                        "id": "T3JkZXI6MzA5",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjY4"
                        }
                    }
                },
                {
                    "node": {
                        "number": "308",
                        "id": "T3JkZXI6MzA4",
                        "branch": {
                            "name": "Branch 8",
                            "id": "QnJhbmNoOjEzNA=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "307",
                        "id": "T3JkZXI6MzA3",
                        "branch": {
                            "name": "Branch 6",
                            "id": "QnJhbmNoOjE3"
                        }
                    }
                },
                {
                    "node": {
                        "number": "302",
                        "id": "T3JkZXI6MzAy",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjE3OQ=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "298",
                        "id": "T3JkZXI6Mjk4",
                        "branch": {
                            "name": "Branch 8",
                            "id": "QnJhbmNoOjE3OQ=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "291",
                        "id": "T3JkZXI6Mjkx",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "281",
                        "id": "T3JkZXI6Mjgx",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "275",
                        "id": "T3JkZXI6Mjc1",
                        "branch": {
                            "name": "Branch 6",
                            "id": "QnJhbmNoOjE3"
                        }
                    }
                },
                {
                    "node": {
                        "number": "274",
                        "id": "T3JkZXI6Mjc0",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "268",
                        "id": "T3JkZXI6MjY4",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjE3"
                        }
                    }
                },
                {
                    "node": {
                        "number": "267",
                        "id": "T3JkZXI6MjY3",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "263",
                        "id": "T3JkZXI6MjYz",
                        "branch": {
                            "name": "Branch 4",
                            "id": "QnJhbmNoOjc0"
                        }
                    }
                },
                {
                    "node": {
                        "number": "260",
                        "id": "T3JkZXI6MjYw",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjEzNA=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "257",
                        "id": "T3JkZXI6MjU3",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "253",
                        "id": "T3JkZXI6MjUz",
                        "branch": {
                            "name": "Branch 6",
                            "id": "QnJhbmNoOjEzNA=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "250",
                        "id": "T3JkZXI6MjUw",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "243",
                        "id": "T3JkZXI6MjQz",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "242",
                        "id": "T3JkZXI6MjQy",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjc0"
                        }
                    }
                },
                {
                    "node": {
                        "number": "238",
                        "id": "T3JkZXI6MjM4",
                        "branch": {
                            "name": "Branch 8",
                            "id": "QnJhbmNoOjE3OQ=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "236",
                        "id": "T3JkZXI6MjM2",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "231",
                        "id": "T3JkZXI6MjMx",
                        "branch": {
                            "name": "Branch 4",
                            "id": "QnJhbmNoOjE3OQ=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "229",
                        "id": "T3JkZXI6MjI5",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "223",
                        "id": "T3JkZXI6MjIz",
                        "branch": {
                            "name": "Branch 6",
                            "id": "QnJhbmNoOjE3"
                        }
                    }
                },
                {
                    "node": {
                        "number": "222",
                        "id": "T3JkZXI6MjIy",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "221",
                        "id": "T3JkZXI6MjIx",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "220",
                        "id": "T3JkZXI6MjIw",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "219",
                        "id": "T3JkZXI6MjE5",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "214",
                        "id": "T3JkZXI6MjE0",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjE3OQ=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "212",
                        "id": "T3JkZXI6MjEy",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "211",
                        "id": "T3JkZXI6MjEx",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "210",
                        "id": "T3JkZXI6MjEw",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "209",
                        "id": "T3JkZXI6MjA5",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "208",
                        "id": "T3JkZXI6MjA4",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "207",
                        "id": "T3JkZXI6MjA3",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "206",
                        "id": "T3JkZXI6MjA2",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "201",
                        "id": "T3JkZXI6MjAx",
                        "branch": {
                            "name": "Branch 4",
                            "id": "QnJhbmNoOjE3OQ=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "199",
                        "id": "T3JkZXI6MTk5",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "194",
                        "id": "T3JkZXI6MTk0",
                        "branch": {
                            "name": null,
                            "id": "QnJhbmNoOjE3OQ=="
                        }
                    }
                },
                {
                    "node": {
                        "number": "192",
                        "id": "T3JkZXI6MTky",
                        "branch": null
                    }
                },
                {
                    "node": {
                        "number": "191",
                        "id": "T3JkZXI6MTkx",
                        "branch": {
                            "name": "Branch 8",
                            "id": "QnJhbmNoOjEzNA=="
                        }
                    }
                }
            ]
        }
    }
}

How to reproduce

Expected behavior

I tried the same thing on the apollo server and in the service query it neither asks for null id or leaves empty and it does not expect it

currently on wundergraph it sends it without an id and when the service replies with null, wundergraph starts mixing data
on go tools it sends with id = null and returns from service is null and go tools gateway starts mixing data.

WunderGraph information

wunderctl version : 0.111.2

Environment & setup

  • OS: [CentOS]
  • Database: [My sql ]

WunderCtl Version

wunderctl version : 0.111.2

The lack of package:"github.com/wundergraph/wundergraph/types/go/wgpb"

Bug description

When I run cmd/wunderctl, I get a error:
../../pkg/loadvariable/loadvariable.go:8:2: no required module provides package github.com/wundergraph/wundergraph/types/go/wgpb; to add it: go get github.com/wundergraph/wundergraph/types/go/wgpb

And find that The lack of package:"github.com/wundergraph/wundergraph/types/go/wgpb"

How to reproduce

  1. Go to 'cmd/wunderctl'
  2. Change 'nothing'
  3. Run 'go run main.go'
  4. See error:
    ../../pkg/loadvariable/loadvariable.go:8:2: no required module provides package github.com/wundergraph/wundergraph/types/go/wgpb; to add it: go get github.com/wundergraph/wundergraph/types/go/wgpb

Expected behavior

No response

WunderGraph information

Environment & setup

  • OS:
  • Go version:
  • Database:
  • Node.js version:

WunderCtl Version

2b16f96

wunderctl returns nothing

Bug description

When using the wunderctl command line, it returns nothing to the user. The options are not returning anything to the user.

How to reproduce

  1. Install the latest version of wunterctl from npm
  2. Run wunderctl --version

Expected behavior

See results from commands.

WunderGraph information

Environment & setup

  • OS: Windows 11
  • Go version: go1.18.4 windows/amd6
  • Database: PostgresSQL
  • Node.js version: 16.6.0

WunderCtl Version

The command is returning nothing.

Uploading files pollutes the logs

Currently, when running wunderctl up --debug we're logging all requests including req+res.
That's problematic in case of file uploads, because we're printing the file to the std out.
Ideally, we could detect if the request is a file upload and prevent logging the body to keep the logs clean.

Add transformer to extract an item out of a list.

Problem

It is often the case that an API has an interface for performing an operation over multiple items, however the user of the API would like to offer an operation that operates over a single item.

An example is a delete item operation. Imagine a theoretical API:

DELETE www.example.com/api/v1/items?ids=[12,43,4]

Which returns a list of ids.

But we want to offer a Wundergraph operation deleteItem(id: int)

At the moment, I need to do some mangling in the hooks to convert the return type, which means I cannot use the typed helpers, and the transformation is not happening in the fast go codebase.

Suggested solution

Add a transformer to allow extraction of an indexed item from a returned list.

maybe @transform(index: 0)

Where "index" is the transformation over a list type item that converts it to a single item. The argument it the 0-based position of the item.

The resulting type would need to be nullable because the item at the index may not exist.

Alternatives

The alternative it to use a mutatingPostResolve hook, but this is less desirable for the reasons stated above.

🐛 No easy way to stop wunderctl up

Bug description

So while there is something like wunderctl up --debug that shows debug information. If you exit via ctrl+c the process remains active.
There is no wunderctl down so you can't make it stop unless you either memorized the PID or you look it up on which process is using port 9991 or 9992 and kill it manually.

How to reproduce

  1. wunderctl up --debug

Expected behavior

Make wunderctl down

WunderGraph information

https://wundergraph.com/docs/guides/your_first_wundergraph_application/overview

Environment & setup

  • OS: Windows 10 10.0.19044
  • Node.js version: 16.13.1

WunderCtl Version

Version: 0.90.32
Commit: 386a3d4b66204411dc89da6919aad0bebe524657
Date: 2022-06-06T12:22:22Z
BuiltBy: ci

Add validation to file uploads

Problem

Currently file uploads cannot be restricted by size or mimetype

Suggested solution

A configuration in s3UploadProvider could look like:

allowedUploads: [
	{
		mimeTypes: ["image/*", "audio/*"],
		sizeLimit: '200M',
		requiredRoles: ['verified']
	},
	{
		mimeTypes: ['text/*'],
		sizeLimit: '5M',
		requiredRoles: []
	},
	{
		mimeTypes: ['video/*', 'audio/*'],
		sizeLimit: '2G',
		requiredRoles: ['paidsubscriber']
	}
]

with the default value being

allowedUploads: [
	{
		mimeTypes: ['*'],
		sizeLimit: null,
		requiredRoles: []
	},
]

Alternatives

Using typescript middleware to validate / authorize uploads is also another option, but less efficient

[docs] Comparison to PostGraphile

Problem

I liked the comparison to Hasura which gave me a better understanding. Now, I'd like to have one PostGraphile. Why should I use wundergraph instead and/or next to Postgraphil?

Hooks can't be minified

Bug description

Hooks are used a lot in the codebase.

Relay and ApolloGraph (while having other disadvantages) generate a hook for every query e.g. useUserInfo:

const {data} = useUserInfoQuery()

Which minifies to:

d=e().data,

Unfortunately wundergraph uses properties which can't be minified:

const {data} = `useQuery.UserInfo().body`;

Which minifies to almost twice as much code:

d=e.UserInfo().body,

This codes needs to be transfered, decompressed and parsed and has a small negative impact on performance.

It would be cool to further optimize Wundergraphs API to allow even smaller javascript bundles.

Incorrect authentication error message

Bug description

incorrect authentication error when RBAC is not sufficient

How to reproduce

Create a simple WunderGraph application from template and use open id connect auth provider

Operation

query @rbac(requireMatchAll: [tester,admin]) {
    findUsers: db_findManyuser {
        id
        email
        name
    }
}

create a hook in wundergraph.server.ts

export default configureWunderGraphServer<HooksConfig, InternalClient>((serverContext) => ({
    hooks: {
        authentication: {
            mutatingPostAuthentication: async (user) => {
                return {
                    status: "ok",
                    user: {
                        ...user,
                        roles: [
                            "tester",
                        ]
                    }
                }
            }
        },
        queries: {},
        mutations: {},
    },
    graphqlServers: [],
}));

index.tsx

import { NextPage } from 'next';
import styles from '../styles/Home.module.css';
import { AuthProviders, useQuery, useWunderGraph, withWunderGraph } from '../components/generated/nextjs';

const Home: NextPage = () => {
    const {result: test} = useQuery.Test();
    const {user, login, logout} = useWunderGraph();
    return (
        <div className={styles.container}>
            <button onClick={() => login(AuthProviders.storeo)}>Login</button>
            <button onClick={() => logout({
                logout_openid_connect_provider: true
            })}>Logout
            </button>
            <h1 className={styles.title}>Hello WunderGraph! {user?.user_id}</h1>
            {test.status === "ok" && test.data.findUsers.length !== 0 && (
                <div>
                    {test.data.findUsers.map(message => {
                        return (<div key={message.id}>
                            <p>
                                id: {message.id}, email: {message.email}, name: {message.name}
                            </p>
                        </div>)
                    })}
                </div>
            )}
            {test.status === "error" && (
                <div>
                    {test.errors.map(value => {
                        return (<div key={value.message}>
                            <p>
                               message: {value.message}, path: {value.path}
                            </p>

                        </div>)
                    })}
                </div>
            )}
        </div>
    );
};

export default withWunderGraph(Home);

Actual error message:

Unexpected token u in JSON at position 0

Expected behavior

The error message should be Access denied or something related to exact problem

WunderGraph information

Environment & setup

  • OS: Ubuntu
  • Go version: go1.17.2 linux/amd64
  • Database: PostgreSQL
  • Node.js version: v16.15.1

WunderCtl Version

Version: 0.90.32
Commit: 386a3d4b66204411dc89da6919aad0bebe524657
Date: 2022-06-06T12:21:43Z
BuiltBy: ci

"Operation" directory support Multilevel routing

Problem

Dose wg support Multilevel routing?

Suggested solution

I try to add sub dirctory 'user' and add graphql operation file 'list.graphql' in the sub dirctory,and hope that wg can genearte REST API "/user/list".

Additional context

I think it's usefull. Because 'Operation' dicecory will be more and more disorder with the growth of project . And this problem can be solved by using the folder origanization operation .

When .wundergraph/generated directory is missing on first start, JSON-RPC endpoints are not being created

Bug description

On the initial start, the generated folder doesn't exist.
This means, the wundergraph.config.json file doesn't exist either, so it's not possible to setup a listener on the file.
Once it's created, it's not being picked up and endpoints are not being created.

How to reproduce

  1. head to default test app
  2. remove generated dir
  3. start testapp
  4. endpoints not created
  5. stop and restart
  6. endpoints now created

Expected behavior

No response

WunderGraph information

Environment & setup

  • OS:
  • Go version:
  • Database:
  • Node.js version:

WunderCtl Version


up mode a File change detected exception

Bug description

up mode accur File change detected exception

How to reproduce

  1. Go to '.wundergraph'
  2. Run 'wunderctl up --debug --listen-addr 0.0.0.0:9991'
  3. See error
2022-08-22T17:26:09+08:00       debug   File change detected    {"watcherName": "config", "paths": ["/home/admin/app/start/wundergraph/.wundergraph/generated/wundergraph.config.json"]}
  1. There is an infinite loop

Expected behavior

No response

WunderGraph information

/.wundergraph/wundergraph.config.ts

import {
    Application,
    authProviders,
    configurePublishWunderGraphAPI,
    configureWunderGraphApplication,
    cors,
    introspect,
    templates
} from '@wundergraph/sdk';
import server from './wundergraph.server';
import operations from './wundergraph.operations';

const weather = introspect.graphql({
    apiNamespace: "weather",
    url: "https://graphql-weather-api.herokuapp.com/",
});



const myApplication = new Application({
    name: 'app',
    apis: [weather,],
});

// configureWunderGraph emits the configuration
configureWunderGraphApplication({
    application: myApplication,
    server,
    operations,
    authentication:{} ,
    authorization: {roles:["admin","user"]} ,
    cors: {        ...cors.allowAll, allowedOrigins:["localhost:3000"],allowedHeaders:[""],exposedHeaders:[""],maxAge:60 },
    security: {enableGraphQLEndpoint:true} ,
    dotGraphQLConfig: {
            hasDotWunderGraphDirectory: false,
    },
    codeGenerators: [
            {
                templates: [
                    // use all the typescript react templates to generate a client
                    ...templates.typescript.all,
                    templates.typescript.operations,
                    templates.typescript.linkBuilder,
                ],
                // create-react-app expects all code to be inside /src
                // path: "../frontend/src/generated",
            },
    ],
});

/.wundergraph/wundergraph.operations.ts

import { configureWunderGraphOperations } from '@wundergraph/sdk';
import type { OperationsConfiguration } from './generated/wundergraph.operations';

export default configureWunderGraphOperations<OperationsConfiguration>({
	operations: { 
		defaultConfig:{authentication:{required:false}},
		queries: (config) => ({  
			...config,
			caching : {enable:true,staleWhileRevalidate:2,maxAge:2,public:false},
			liveQuery: {enable:false,pollingIntervalSeconds:0},
		}),
 		mutations: (config) => ({
            ...config,
        }),
        subscriptions: (config) => ({
            ...config,
        }),
	 custom: { }, },
});

/.wundergraph/wundergraph.server.ts

import {GraphQLObjectType, GraphQLSchema, GraphQLString} from 'graphql';
import {configureWunderGraphServer} from '@wundergraph/sdk';
import type {AuthenticationResponse, HooksConfig} from './generated/wundergraph.hooks';
import type {InternalClient} from './generated/wundergraph.internal.client';

   

export default configureWunderGraphServer<HooksConfig, InternalClient>(() => ({
   hooks:{  authentication: {
				
            },  }, graphqlServers: [] 
}));

Environment & setup

  • OS:
  • Go version:
  • Database:
  • Node.js version:

WunderCtl Version

Version: 0.94.5
Commit: 7b5e6108ec00cb5de98235f33c07b612415dc346
Date: 2022-07-18T09:13:16Z
BuiltBy: ci

null values in body are not passed through to graphql backend

The Wundergraph operation looks like this:

mutation someUpdate($id: Int!, $name: String, $description: String, $icon: URL, $image: URL, $labels: [String!]) {
    object: someUpdate(id: $id, name: $name, description: $description, icon: $icon, image: $image, labels: $labels)
    {
        id
    }
}

I have the semantics that we can clear a value by sending an update with a null value.
This is different to sending an update when some values are not set, which means don't change the values not included in the call.

For example, in the below call, I want to clear the existing "name" attribute on the object.

--- ClientRequest start ---

POST /api/main/operations/someUpdate HTTP/1.1
Host: localhost:9991
Accept: */*
Content-Length: 23
Content-Type: application/json
User-Agent: curl/7.68.0

{"id": 0, "name": null}



--- ClientRequest end ---



--- DebugTransport ---

Request:

POST / HTTP/1.1
Host: localhost:8000
Accept: application/json
Content-Type: application/json

{"variables":{"id":0},"query":"mutation($id: Int!, $name: String, $description: String, $icon: URL, $image: URL, $labels: [String!]){object: someUpdate(id: $id, name: $name, description: $description, icon: $icon, image: $image, labels: $labels){id}}"}

Duration: 121 ms

Response:

HTTP/1.1 200 OK
Content-Length: 28
Content-Type: application/json
Date: Fri, 05 Aug 2022 04:52:27 GMT
Server: uvicorn

{"data":{"object":{"id":0}}}

--- DebugTransport

You can see by the above, the Wundergraph server removes the "name" attribute, as it is null. If I set it to something else, it works ok.

The desired behaviour is for the wundergraph server to pass through null-valued arguments.

Allow configuration of application deployment name

Problem

At the moment the deployment name is always "main". I want to be able to configure that.

Suggested solution

Add 'deployment' field to ApplicationConfig and Application, and use it in resolveConfig() instead of the hard-coded 'main'.

then a user could configure the deployment within configureWunderGraphApplication()

Alternatives

Possibly allow overriding via an environment variable.

Additional context

const name = 'main';

export interface ApplicationConfig {

wunderctl generate hangs when run inside a docker build

Bug description

RUN wunderctl generate inside a docker image hangs until a timeout when trying to generate the prisma engines

How to reproduce

Cross posted from wundergraph/docker#2

Expected behavior

wunderctl generate completes in a reasonable amount of time

WunderGraph information

Environment & setup

  • OS: Mac OS, Windows, Debian, CentOS
  • Go version: go version go1.18 darwin/arm64
  • Database: PostgreSQL
  • Node.js version: v18.11.0

WunderCtl Version

Version: 0.111.4
Commit: 4e9eb8f7500fa37afa524890cae122cf801033b9
Date: 2022-10-10T17:58:54Z
BuiltBy: ci

Event stream responses are missing the X-Accel-Buffering header

Bug description

I've been testing the Live Queries feature and it works well locally. But when I put Wundergraph behind the nginx in my cluster, the nginx seems to buffer the response from the server and the client's request is stuck in a loading state for a long time.

From my research, (e.g., see here), there are a bunch of settings I need to change in my nginx config - I can do these myself. But in addition, ideally, the Wundergraph server should also add a header X-Accel-Buffering: no; in its response.

I'm not too familiar with your code base, but I suppose you probably just need to add the header somewhere here, here, or here.

How to reproduce

I didn't have time to come up with a minimum reproducible example, as my entire server setup is fairly complex. But I think from the discussion in Serverfault thread, it should make sense to add the X-Accel-Buffering header in the server response for streaming events.

Expected behavior

No response

WunderGraph information

Environment & setup

  • OS: Ubuntu

WunderCtl Version

Version: 0.97.0
Commit: 9473809239b83d337906fa6c2346863fa1748b71
Date: 2022-08-09T11:30:39Z
BuiltBy: ci

using @internal on operations breaks code generation

Bug description

when using an operation like this:

query($where: db_NodeWhereInput @internal) {
	db_findManyNode(where: $where){
		name
		id
		created_at
	}
}```

the `db_NodeWhereInput` is not being generated, although it should.

The intention is to configure the "where" input from a mutatingPreResolve hook, but not expose the where variable to the user.

Code generation seems to ignore variables declared as `@internal`.
This is correct for the "externally" facing types, but the type used for the hook should have the internal variable.

### WunderCtl Version

latest

Wildcard CORS does not work

Bug description

The CorsConfiguration type recommends to use ['*'] as the value to all origins. However when I set the wildcard values I continue to get cors issues. Setting the domains manually works fine, but any wildcards in the domain seems not to work at all.

export interface CorsConfiguration {
    /**
     * AllowedOrigins is a list of origins a cross-domain request can be executed from.
     * If the special "*" value is present in the list, all origins will be allowed.
     * An origin may contain a wildcard (*) to replace 0 or more characters
     * (i.e.: http://*.domain.com). Usage of wildcards implies a small performance penalty.
     * Only one wildcard can be used per origin.
     * Default value is ["*"]
     */
    allowedOrigins: ConfigurationVariable[];

How to reproduce

  1. Go to 'wundergraph.config.ts'
  2. Change 'allowedOrigins to ['*']
  3. Run
  4. See error when loading data from any origin

Expected behavior

CORS allows all origins

WunderGraph information

cors: {
    ...cors.allowAll,
    allowedOrigins: ['*']
}

Environment & setup

  • OS: Windows, deployed to Ubuntu in production

WunderCtl Version

0.94.2

pnpm version mismatch

Bug description

In package.json:

...
  "engines": {
    "node": ">=16.0.0",
    "pnpm": ">=7.0.0 < 7.4.0"
  },
...
  "dependencies": {
    "pnpm": "^7.5.2"
  }
...

These incompatible version specifications result in the following error:

$ npm i

> [email protected] postinstall
> husky install && pnpm run patch

husky - Git hooks installed
 ERR_PNPM_UNSUPPORTED_ENGINE  Unsupported environment (bad pnpm and/or Node.js version)

Your pnpm version is incompatible with "/Users/eskwayrd/repos/wundergraph".

Expected version: >=7.0.0 < 7.4.0
Got: 7.5.2

This is happening because the package's manifest has an engines.pnpm field specified.
To fix this issue, install the required pnpm version globally.

To install the latest version of pnpm, run "pnpm i -g pnpm".
To check your pnpm version, run "pnpm -v".

How to reproduce

Expected behavior

I would expect the dependency installation to complete successfully.

WunderGraph information

Environment & setup

  • OS: macOS Monterey 12.4
  • Go version: 1.18.4
  • Database: FaunaDB
  • Node.js version: 17.5.0

WunderCtl Version

N/A: Dependency installation did not complete. I'm using this repo at commit 8f5d9161383981e5abae2be5c66587cf2b5fb547.

Issue explicitly forwarding Content-Type header with introspected federation API

Bug description

When using the following code block to build header forwarding for a federated introspection, I'm seeing headers replaced with templates rather than values:

function buildHeaders(builder) {
    return builder
        .addClientRequestHeader('Content-Type', 'Content-Type')
        .addClientRequestHeader('Authorization', 'Authorization')
        .addClientRequestHeader('X-Custom-Header', 'X-Custom-Header');
}

My subgraph is receiving the following HTTP request headers (shown as JSON):

{"accept":"application/json","content-type":"{{ .request.headers.Content-Type }}","authorization":"{{ .request.headers.Authorization }}","x-custom-header":"{{ .request.headers.X-Custom-Header }}","user-agent":"axios/0.26.1","content-length":"1811","host":"localhost:4001","connection":"close"}

By removing the .addClientRequestHeader('Content-Type', 'Content-Type') line, I start to get header values forwarded correctly. This is an acceptable work around, I just wanted to pass along what I encountered.

How to reproduce

  1. Use Wundergraph as an Apollo Federated gateway building header to forward as described in the description.
  2. Call wunderctl up
  3. Execute a request to Wundergraph
  4. Observe the HTTP request sent to the subgraph's HTTP server (see example in bug description)

Expected behavior

Receive the specified forwarded header values provided in the HTTP request to the Wundernode in the subgraph.

WunderGraph information

wundergraph.server.ts

import { GraphQLObjectType, GraphQLSchema, GraphQLString } from 'graphql';
import { configureWunderGraphServer } from '@wundergraph/sdk';
import type { HooksConfig } from './generated/wundergraph.hooks';
import type { InternalClient } from './generated/wundergraph.internal.client';

export default configureWunderGraphServer<HooksConfig, InternalClient>(() => ({
	hooks: {
		queries: {},
		mutations: {}
	}
}));

wundergraph.operations.ts

import { configureWunderGraphOperations } from '@wundergraph/sdk';
import type { OperationsConfiguration } from './generated/wundergraph.operations';

export default configureWunderGraphOperations<OperationsConfiguration>({
	operations: {
		defaultConfig: {
			authentication: {
				required: false,
			},
		},
		queries: (config) => ({
			...config,
			caching: {
				enable: false,
				staleWhileRevalidate: 60,
				maxAge: 60,
				public: true,
			},
			liveQuery: {
				enable: false
			},
		}),
		mutations: (config) => ({
			...config,
		}),
		subscriptions: (config) => ({
			...config,
		}),
		custom: {},
	},
});

wundegraph.config.ts:

function buildHeaders(builder) {
    return builder
        .addClientRequestHeader('Content-Type', 'Content-Type')
        .addClientRequestHeader('Authorization', 'Authorization')
        .addClientRequestHeader('X-Custom-Header', 'X-Custom-Header');
}

const upstreams = [
    {
        url: 'http://localhost:4001/graphql',
        headers: buildHeaders
    }
];

const federatedApi = introspect.federation({
    upstreams
});

const myApplication = new Application({
    name: 'my-federated-gateway',
    apis: [federatedApi]
});

configureWunderGraphApplication({
    application: myApplication,
    server,
    operations,
    cors: {
        ...cors.allowAll,
        allowedOrigins: ['https://studio.apollographql.com']
    },
    security: {
        enableGraphQLEndpoint: true,
    },
});

Environment & setup

  • OS: OSX
  • Go version: Default shipped with wunderctl
  • Database: None
  • Node.js version: 16.x

WunderCtl Version

Version: 0.99.3
Commit: 2be71e21894cf0982bfcbf8d68c066e273d26a1f
Date: 2022-08-25T20:12:53Z
BuiltBy: ci

🐛 [GitPod] Network error in graphiql when trying to load schema

Bug description

image

How to reproduce

  1. https://gitpod.io/#https://github.com/wundergraph/wundergraph
  2. go to gitpod /app/main/graphql
  3. try to open the docs explorer

Expected behavior

docs explorer should show the schema

WunderGraph information

https://gitpod.io/#https://github.com/wundergraph/wundergraph

Environment & setup

https://gitpod.io/#https://github.com/wundergraph/wundergraph

WunderCtl Version

https://gitpod.io/#https://github.com/wundergraph/wundergraph

Support schema extension for GraphQL and REST data sources

Context

Consider the following. We're storing image metadata in our Postgres database using the PostGIS extension. Hasura supports PostGIS natively and creates a custom GraphQL scalar called geography to store the GPS coordinates. The value of this type is a GeoJSON. See https://hasura.io/docs/latest/schema/postgres/postgresql-types/#geography

We use Hasura as a backend for WunderGraph. Using the schema generated by WunderGraph, suppose I now try to query an image, e.g.

query GetImages {
  hasura_images {
    id
    location
  }
}

where location has geography type. Then WunderGraph would complain that returning location field in the response has incorrect type:

ERROR ResolveGraphQLResponse for query failed {"component": "@wundergraph/node", "error": "invalid value type 'object' for path /data/hasura_images/1/location, expecting string, got: {\"type\":\"Point\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"urn:ogc:def:crs:EPSG::4326\"}},\"coordinates\":[-0.136667,50.818889]}. You can fix this by configuring this field as Int/Float Scalar"}

This kinda makes sense as Hasura returns a GeoJSON object for location but WunderGraph can't know that from introspection alone. The generated wundergraph.api.schema.graphql simply has:

scalar hasura_geography

So it seems we want to override the geography type generated by WunderGraph.

Feature Request

It seems that this is what we want: https://docs.wundergraph.com/docs/guides/extend-json-fields-with-more-specific-types

But currently, it's only exposed to database sources.

It would be great if we can also extend GraphQL schemas from GraphQL sources (and maybe REST as well).

make doesn't work

Bug description

packages/nextjs-testapp build$ pnpm run generate && next build
[1 lines collapsed]
│ > @test/[email protected] generate /Users/jens/repos/wundergraph/packages/nextjs-testapp
│ > cd .wundergraph && wunderctl generate
│ Error: could not find file or directory: base directory "/Users/jens/repos/wundergraph/packages/nextjs-testapp/.wundergraph/.wundergraph" not found

I've had to make this change so that "make" works again:
cff1bf3

@StarpTech it seems like the changes you've made recently assume that we don't cd into .wundergraph because the generated directory is /nextjs-testapp/.wundergraph/.wundergraph. Maybe you missed to check for that case?

How to reproduce

run make

Expected behavior

x

WunderGraph information

x

Environment & setup

x

WunderCtl Version

latest

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.