@webda/graphql 4.0.0-beta.2 → 4.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,14 +1,136 @@
1
- # @webda/graphql
1
+ # @webda/graphql module
2
2
 
3
- Implements the GraphQL protocol with subscriptions and mutations
3
+ This module is part of Webda Application Framework that allows you to quickly develop applications with all modern prerequisites: Security, Extensibility, GraphQL, REST, CloudNative [https://webda.io](https://webda.io)
4
4
 
5
+ <img src="https://webda.io/images/webda.svg" width="128" />
6
+
7
+ ![CI](https://github.com/loopingz/webda.io/workflows/CI/badge.svg)
8
+
9
+ [![Join the chat at https://gitter.im/loopingz/webda](https://badges.gitter.im/loopingz/webda.svg)](https://gitter.im/loopingz/webda?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
10
+ [![codecov](https://codecov.io/gh/loopingz/webda.io/branch/main/graph/badge.svg?token=8N9DNM3K3O)](https://codecov.io/gh/loopingz/webda.io)
11
+ [![SonarCloud.io](https://sonarcloud.io/api/project_badges/measure?project=loopingz_webda.io&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=loopingz_webda.io)
12
+ ![CodeQL](https://github.com/loopingz/webda.io/workflows/CodeQL/badge.svg)
13
+
14
+ <!-- README_HEADER -->
15
+
16
+ ## @webda/graphql
17
+
18
+ Auto-generates a fully functional GraphQL API — queries, mutations, **and subscriptions** — from your Webda domain models. Zero hand-written SDL required.
19
+
20
+ ### When to use it
21
+
22
+ Add `@webda/graphql` when you want a GraphQL endpoint alongside (or instead of) the REST endpoint. It reads your model graph from `@webda/compiler`'s model manifest and builds the GraphQL schema dynamically. Subscriptions over WebSocket (`graphql-ws`) are enabled by default.
23
+
24
+ ### Install
25
+
26
+ ```bash
27
+ npm install @webda/graphql
5
28
  ```
6
- // Add a ping to subscription (useful for testing)
7
- setInterval(() => this.emit("Ping", Date.now()), this.parameters.pingInterval);
8
- subscriptions["Ping"] = {
9
- type: GraphQLLong,
10
- subscribe: async (source, args, context: any, info: GraphQLResolveInfo) => {
11
- return new EventIterator(this, "Ping", "Ping", Date.now()).iterate();
29
+
30
+ ### Configuration
31
+
32
+ Add the `GraphQLService` to your `webda.config.json`:
33
+
34
+ ```json
35
+ {
36
+ "services": {
37
+ "GraphQLService": {
38
+ "type": "Webda/GraphQLService",
39
+ "url": "/graphql",
40
+ "exposeGraphiQL": true,
41
+ "globalSubscription": true
12
42
  }
13
- };
43
+ }
44
+ }
45
+ ```
46
+
47
+ ### Auto-generated operations
48
+
49
+ For every exposed model (e.g. `Post`) the service generates:
50
+
51
+ | Operation | Type | Description |
52
+ |-----------|------|-------------|
53
+ | `Post(uuid)` | Query | Fetch one by primary key |
54
+ | `Posts(query, limit, offset)` | Query | List / filter all |
55
+ | `createPost(Post: PostInput)` | Mutation | Create new instance |
56
+ | `updatePost(uuid, Post: PostInput)` | Mutation | Replace by primary key |
57
+ | `deletePost(uuid)` | Mutation | Delete by primary key |
58
+ | `PostEvents` | Subscription | Stream events for all posts |
59
+ | `PostEvent(uuid)` | Subscription | Stream events for a specific post |
60
+
61
+ Custom `@Operation()` methods on the model become additional mutations or queries automatically.
62
+
63
+ ### Quick usage
64
+
65
+ ```graphql
66
+ # Query all published posts
67
+ { Posts { results { slug title status viewCount } } }
68
+
69
+ # Create a post
70
+ mutation {
71
+ createPost(Post: {
72
+ title: "Hello World"
73
+ slug: "hello-world"
74
+ content: "My first post content with enough text."
75
+ status: "draft"
76
+ viewCount: 0
77
+ }) {
78
+ slug
79
+ title
80
+ }
81
+ }
14
82
  ```
83
+
84
+ ### Subscriptions (graphql-ws)
85
+
86
+ ```graphql
87
+ subscription {
88
+ PostEvents {
89
+ Created { object { slug title } }
90
+ Updated { object { slug title } }
91
+ Deleted { object_id }
92
+ }
93
+ }
94
+ ```
95
+
96
+ The subscription server uses `graphql-ws` over WebSocket (same port as the HTTP server when TLS is enabled via `autoTls`).
97
+
98
+ ### GraphiQL
99
+
100
+ Set `exposeGraphiQL: true` (the default) to enable the in-browser GraphiQL IDE at `/graphql`. Useful for development and introspection.
101
+
102
+ ### Parameters
103
+
104
+ | Parameter | Default | Description |
105
+ |-----------|---------|-------------|
106
+ | `url` | `/graphql` | HTTP endpoint path |
107
+ | `exposeGraphiQL` | `true` | Serve the GraphiQL explorer UI |
108
+ | `exposeMe` | `true` | Expose `{ me { ... } }` query for current user |
109
+ | `globalSubscription` | `true` | Expose aggregate `AggregateSubscriptions` subscription |
110
+ | `userModel` | `User` | Short name of the User model for `me` query |
111
+
112
+ ### See also
113
+
114
+ - [Schema Generation](../../docs/pages/Modules/graphql/Schema-Generation.md)
115
+ - [Queries and Mutations](../../docs/pages/Modules/graphql/Queries-And-Mutations.md)
116
+ - [Subscriptions](../../docs/pages/Modules/graphql/Subscriptions.md)
117
+ - [@webda/core DomainService](../core/README.md) — base class for model-serving services
118
+
119
+ <!-- README_FOOTER -->
120
+ ## Sponsors
121
+
122
+ <!--
123
+ Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor](mailto:sponsor@webda.io)
124
+ -->
125
+
126
+ Arize AI is a machine learning observability and model monitoring platform. It helps you visualize, monitor, and explain your machine learning models. [Learn more](https://arize.com)
127
+
128
+ [<img src="https://arize.com/hubfs/arize/brand/arize-logomark-1.png" width="200">](https://arize.com)
129
+
130
+ Loopingz is a software development company that provides consulting and development services. [Learn more](https://loopingz.com)
131
+
132
+ [<img src="https://loopingz.com/images/logo.png" width="200">](https://loopingz.com)
133
+
134
+ Tellae is an innovative consulting firm specialized in cities transportation issues. We provide our clients, both public and private, with solutions to support your strategic and operational decisions. [Learn more](https://tellae.fr)
135
+
136
+ [<img src="https://tellae.fr/" width="200">](https://tellae.fr)
@@ -0,0 +1,205 @@
1
+ import { Application, DomainService, DomainServiceParameters, ModelDefinition, WebContext } from "@webda/core";
2
+ import type { ModelGraph } from "@webda/compiler";
3
+ import * as WebdaQL from "@webda/ql";
4
+ import { FieldNode, GraphQLFieldConfig, GraphQLObjectType, GraphQLResolveInfo, GraphQLSchema, GraphQLType, ThunkObjMap } from "graphql";
5
+ import { Handler } from "graphql-http";
6
+ import { Server as GraphQLWSServer } from "graphql-ws";
7
+ import { JSONSchema7 } from "json-schema";
8
+ import { WebSocketServer } from "ws";
9
+ export interface GraphQLContextExtension {
10
+ /**
11
+ * Get the current count of operation for this request
12
+ */
13
+ count?: number;
14
+ }
15
+ /**
16
+ * Parameters for the GraphQL service
17
+ */
18
+ export declare class GraphQLParameters extends DomainServiceParameters {
19
+ /**
20
+ * URL for the GraphQL endpoint
21
+ * @default /graphql
22
+ */
23
+ url: string;
24
+ /**
25
+ * Max number of requests allowed within a graphql query or mutation
26
+ *
27
+ * @default 10
28
+ */
29
+ maxOperationsPerRequest: number;
30
+ /**
31
+ * User model to expose
32
+ * @default User
33
+ */
34
+ userModel: string;
35
+ /**
36
+ * Expose current user in the context with me
37
+ * @default true
38
+ */
39
+ exposeMe: boolean;
40
+ /**
41
+ * Expose the schema
42
+ */
43
+ exposeGraphiQL: boolean;
44
+ /**
45
+ * Expose a aggregation of all available subscriptions
46
+ */
47
+ globalSubscription: boolean;
48
+ /**
49
+ * Load parameters with defaults
50
+ * @param params - raw configuration values
51
+ * @returns this for chaining
52
+ */
53
+ load(params?: any): this;
54
+ }
55
+ /**
56
+ * Implement a GraphQL service
57
+ *
58
+ * It will expose all your exposed models as GraphQL types
59
+ * Dynamically generate the schema
60
+ *
61
+ * @WebdaModda
62
+ */
63
+ export declare class GraphQLService<T extends GraphQLParameters = GraphQLParameters> extends DomainService<T> {
64
+ schema: GraphQLSchema;
65
+ handler: Handler;
66
+ modelsMap: {
67
+ [key: string]: GraphQLObjectType;
68
+ };
69
+ app: Application;
70
+ wss: WebSocketServer;
71
+ wsHandler: GraphQLWSServer;
72
+ modelListeners: any;
73
+ /**
74
+ * Load and initialize GraphQL service parameters
75
+ * @param params - raw partial configuration
76
+ * @returns initialized GraphQLParameters
77
+ */
78
+ loadParameters(params: any): GraphQLParameters;
79
+ /**
80
+ * Resolve a JSON Schema property by following $ref pointers
81
+ * @param prop - JSON Schema property that may contain $ref
82
+ * @param definitions - schema definitions map for resolving references
83
+ * @returns the resolved JSON Schema (or a null type if unresolvable)
84
+ */
85
+ getJsonSchemaDefinition(prop: JSONSchema7, definitions?: {}): JSONSchema7;
86
+ /**
87
+ * Convert a JSON Schema to a GraphQL type definition
88
+ * @param schema - JSON Schema to convert
89
+ * @param defaultName - fallback name for anonymous types
90
+ * @param input - if true, generate GraphQLInputObjectType instead of GraphQLObjectType
91
+ * @returns object with the GraphQL type and optional description, or undefined for null types
92
+ */
93
+ getGraphQLSchemaFromSchema(schema: JSONSchema7, defaultName: string, input?: boolean): {
94
+ type: GraphQLType;
95
+ description?: string;
96
+ };
97
+ /**
98
+ * Get or create a GraphQL query result wrapper type with results array and continuationToken
99
+ * @param type - GraphQL object type to wrap in a query result
100
+ * @returns GraphQL object type with results and continuationToken fields
101
+ */
102
+ getGraphQLQueryResult(type: any): GraphQLObjectType<any, any>;
103
+ /**
104
+ * Build GraphQL field definitions from a JSON Schema, enriching with relation resolvers from the model graph
105
+ * @param schema - JSON Schema describing the model properties
106
+ * @param defaultName - fallback name for generated types
107
+ * @param webdaGraph - model relation graph (links, maps, queries, parent)
108
+ * @param input - if true, generate input types (skip readonly fields, skip relation resolvers)
109
+ * @returns map of field names to GraphQL field configs
110
+ */
111
+ getGraphQLFieldsFromSchema(schema: JSONSchema7, defaultName: string, webdaGraph?: ModelGraph, input?: boolean): any;
112
+ /**
113
+ * Load a model instance, optimizing to skip store reads when all requested fields are already known
114
+ * @param knownFieldsOrId - UUID string or object with known field values
115
+ * @param model - model class to load from
116
+ * @param context - web context for permission checks
117
+ * @param info - GraphQL field node describing the selection set
118
+ * @param filter - optional WebdaQL filter to apply to the result
119
+ * @returns the model instance, or null if filtered out
120
+ */
121
+ loadModelInstance(knownFieldsOrId: string | {
122
+ uuid: string;
123
+ [key: string]: any;
124
+ }, model: ModelDefinition<any>, context: WebContext, info?: FieldNode, filter?: WebdaQL.PartialValidator): Promise<any>;
125
+ /**
126
+ * Increment the operation counter and throw if the per-request limit is exceeded
127
+ * @param context - web context holding the graphql extension with the counter
128
+ * @param increment - number of operations to add (default 1)
129
+ */
130
+ countOperation(context: WebContext, increment?: number): void;
131
+ /**
132
+ * Set up WebSocket server for GraphQL subscriptions and register upgrade handler
133
+ * @returns this instance for chaining
134
+ */
135
+ resolve(): this;
136
+ /**
137
+ * Generate GraphQL schema
138
+ */
139
+ generateSchema(): void;
140
+ /**
141
+ * Extract the list of event names from the GraphQL selection set (excluding latestEventTime)
142
+ * @param info - GraphQL resolve info containing field selections
143
+ * @returns array of event name strings the client subscribed to
144
+ */
145
+ getSubscribedEvents(info: GraphQLResolveInfo): string[];
146
+ /**
147
+ * Create an async iterator that streams query results, updating when store events occur
148
+ * @param model - model class to query
149
+ * @param plural - plural name used as the iterator prefix key
150
+ * @param query - WebdaQL query string
151
+ * @param context - web context for permission checks
152
+ * @returns async iterator yielding updated query results on store changes
153
+ */
154
+ registerAsyncIteratorQuery(model: ModelDefinition<any>, plural: string, query: string, context: any): Promise<AsyncIterator<any>>;
155
+ /**
156
+ * Create an async iterator that streams a single model instance, updating on store events
157
+ * @param model - model class the instance belongs to
158
+ * @param uuid - UUID of the specific instance to watch
159
+ * @param context - web context for permission checks
160
+ * @param identifier - optional key used as the iterator prefix (defaults to model identifier)
161
+ * @returns async iterator yielding the updated model on each store change
162
+ */
163
+ registerAsyncIterator(model: ModelDefinition<any>, uuid: any, context: any, identifier?: string): Promise<AsyncIterator<any>>;
164
+ /**
165
+ * Create an async iterator for raw model events (not full objects), filtered by event name and UUID
166
+ * @param model - model class to listen on
167
+ * @param uuid - UUID to filter events for, or null for all instances
168
+ * @param events - list of event names the client wants to receive
169
+ * @param context - web context for authorization checks
170
+ * @param identifier - key used as the iterator prefix
171
+ * @returns async iterator yielding event payloads with latestEventTime
172
+ */
173
+ registerAsyncEventIterator(model: ModelDefinition<any>, uuid: string | null, events: string[], context: any, identifier: string): Promise<AsyncIterator<any>>;
174
+ /**
175
+ * Assemble the final GraphQLSchema from root query fields, mutations, and subscriptions
176
+ * @param rootFields - top-level query fields
177
+ * @param mutations - mutation fields
178
+ * @param subscription - subscription fields
179
+ * @returns the constructed GraphQLSchema
180
+ */
181
+ getGraphQLSchema(rootFields: ThunkObjMap<GraphQLFieldConfig<any, any, any>>, mutations?: ThunkObjMap<GraphQLFieldConfig<any, any, any>>, subscription?: ThunkObjMap<GraphQLFieldConfig<any, any, any>>): GraphQLSchema;
182
+ /**
183
+ * @override
184
+ */
185
+ init(): Promise<this>;
186
+ /**
187
+ * Check whether a model should be handled by this service (always returns true)
188
+ * @param model - model class to check
189
+ * @param name - display name of the model
190
+ * @param context - request context
191
+ * @returns true if the model should be processed
192
+ */
193
+ handleModel(model: ModelDefinition<any>, name: string, context: any): boolean;
194
+ /**
195
+ * Serve the GraphQL schema as text or the GraphiQL IDE as HTML
196
+ * @param ctx - incoming web context
197
+ */
198
+ schemaRoute(ctx: WebContext<any>): Promise<void>;
199
+ /**
200
+ * Handle POST requests to the GraphQL endpoint
201
+ * @param ctx - incoming web context with the GraphQL query body
202
+ */
203
+ endpoint(ctx: WebContext<any>): Promise<void>;
204
+ }
205
+ //# sourceMappingURL=graphql.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graphql.service.d.ts","sourceRoot":"","sources":["../src/graphql.service.ts"],"names":[],"mappings":"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"}