Skip to content

Commit 343b0e9

Browse files
authored
chore: Schema test for graphql (#648)
Automatic testing for changes in GraphQL schema (same as OpenAPI) Renamed `docs/swagger` to `docs/schema` to host the two files in the same npm package. Renamed npm package to `dialogporten-schema` Automatic versioning/publishing of this npm package is being worked on in another branch ## Related Issue(s) - #490 ## Verification - [x] **Your** code builds clean without any errors or warnings - [x] Manual testing done (required) - [x] Relevant automated test added (if you find this hard, leave it and we'll help out) ## Documentation - [ ] Documentation is updated (either in `docs`-directory, Altinnpedia or a separate linked PR in [altinn-studio-docs.](https://github.com/Altinn/altinn-studio-docs), if applicable)
1 parent 66f3eca commit 343b0e9

File tree

14 files changed

+382
-30
lines changed

14 files changed

+382
-30
lines changed

Digdir.Domain.Dialogporten.sln

+7
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Digdir.Domain.Dialogporten.
5555
EndProject
5656
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Digdir.Domain.Dialogporten.GraphQL", "src\Digdir.Domain.Dialogporten.GraphQL\Digdir.Domain.Dialogporten.GraphQL.csproj", "{234FE24D-1047-4E29-A625-1EB406C37A2D}"
5757
EndProject
58+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Digdir.Domain.Dialogporten.GraphQl.Integration.Tests", "tests\Digdir.Domain.Dialogporten.GraphQl.Integration.Tests\Digdir.Domain.Dialogporten.GraphQl.Integration.Tests.csproj", "{1EF1AE42-17F1-4761-ACFE-DF8E8A9B9429}"
59+
EndProject
5860
Global
5961
GlobalSection(SolutionConfigurationPlatforms) = preSolution
6062
Debug|Any CPU = Debug|Any CPU
@@ -129,6 +131,10 @@ Global
129131
{234FE24D-1047-4E29-A625-1EB406C37A2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
130132
{234FE24D-1047-4E29-A625-1EB406C37A2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
131133
{234FE24D-1047-4E29-A625-1EB406C37A2D}.Release|Any CPU.Build.0 = Release|Any CPU
134+
{1EF1AE42-17F1-4761-ACFE-DF8E8A9B9429}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
135+
{1EF1AE42-17F1-4761-ACFE-DF8E8A9B9429}.Debug|Any CPU.Build.0 = Debug|Any CPU
136+
{1EF1AE42-17F1-4761-ACFE-DF8E8A9B9429}.Release|Any CPU.ActiveCfg = Release|Any CPU
137+
{1EF1AE42-17F1-4761-ACFE-DF8E8A9B9429}.Release|Any CPU.Build.0 = Release|Any CPU
132138
EndGlobalSection
133139
GlobalSection(SolutionProperties) = preSolution
134140
HideSolutionNode = FALSE
@@ -154,6 +160,7 @@ Global
154160
{030909AA-5B61-46B4-9B74-0D2D779478FF} = {3C2C775D-F2D1-42A2-B53F-CC6D5FF59633}
155161
{42004236-D45C-4A1F-9FF9-CF12B7388389} = {CADB8189-4AA1-4732-844A-C41DBF3EC8B7}
156162
{234FE24D-1047-4E29-A625-1EB406C37A2D} = {320B47A0-5EB8-4B6E-8C84-90633A1849CA}
163+
{1EF1AE42-17F1-4761-ACFE-DF8E8A9B9429} = {CADB8189-4AA1-4732-844A-C41DBF3EC8B7}
157164
EndGlobalSection
158165
GlobalSection(ExtensibilityGlobals) = postSolution
159166
SolutionGuid = {B2FE67FF-7622-4AFB-AD8E-961B6A39D888}

docs/schema/V1/.npmignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
swagger.received.json
2+
schema.received.graphql

docs/swagger/V1/package.json docs/schema/V1/package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"name": "dialogporten-swagger",
3-
"version": "1.0.4",
4-
"description": "OpenAPI spec for Dialogporten",
2+
"name": "dialogporten-schema",
3+
"version": "1.0.6",
4+
"description": "GraphQl schema and OpenAPI spec for Dialogporten",
55
"author": "DigDir",
66
"repository": {
77
"url": "git+https://github.com/digdir/dialogporten.git"
+242
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
schema {
2+
query: DialogQueries
3+
}
4+
5+
type Activity {
6+
id: UUID!
7+
createdAt: DateTime
8+
extendedType: URL
9+
type: ActivityType!
10+
relatedActivityId: UUID
11+
dialogElementId: UUID
12+
performedBy: [Localization!]
13+
description: [Localization!]!
14+
}
15+
16+
type ApiAction {
17+
id: UUID!
18+
action: String!
19+
authorizationAttribute: String
20+
isAuthorized: Boolean!
21+
dialogElementId: UUID
22+
endpoints: [ApiActionEndpoint!]!
23+
}
24+
25+
type ApiActionEndpoint {
26+
id: UUID!
27+
version: String
28+
url: URL!
29+
httpMethod: HttpVerb!
30+
documentationUrl: URL
31+
requestSchema: URL
32+
responseSchema: URL
33+
deprecated: Boolean!
34+
sunsetAt: DateTime
35+
}
36+
37+
type Content {
38+
type: ContentType!
39+
value: [Localization!]!
40+
}
41+
42+
type Dialog {
43+
id: UUID!
44+
revision: UUID!
45+
org: String!
46+
serviceResource: String!
47+
party: String!
48+
progress: Int
49+
extendedStatus: String
50+
externalReference: String
51+
visibleFrom: DateTime
52+
dueAt: DateTime
53+
expiresAt: DateTime
54+
createdAt: DateTime!
55+
updatedAt: DateTime!
56+
dialogToken: String
57+
status: DialogStatus!
58+
content: [Content!]!
59+
elements: [Element!]!
60+
guiActions: [GuiAction!]!
61+
apiActions: [ApiAction!]!
62+
activities: [Activity!]!
63+
seenSinceLastUpdate: [SeenLog!]!
64+
}
65+
66+
type DialogQueries @authorize(policy: "enduser") {
67+
dialogById(dialogId: UUID!): Dialog!
68+
searchDialogs(input: SearchDialogInput!): SearchDialogsPayload!
69+
}
70+
71+
type Element {
72+
id: UUID!
73+
type: URL
74+
externalReference: String
75+
authorizationAttribute: String
76+
isAuthorized: Boolean!
77+
relatedDialogElementId: UUID
78+
displayName: [Localization!]!
79+
urls: [ElementUrl!]!
80+
}
81+
82+
type ElementUrl {
83+
id: UUID!
84+
url: URL!
85+
mimeType: String
86+
consumerType: ElementUrlConsumer!
87+
}
88+
89+
type GuiAction {
90+
id: UUID!
91+
action: String!
92+
url: URL!
93+
authorizationAttribute: String
94+
isAuthorized: Boolean!
95+
isBackChannel: Boolean!
96+
isDeleteAction: Boolean!
97+
priority: GuiActionPriority!
98+
title: [Localization!]!
99+
}
100+
101+
type Localization {
102+
value: String!
103+
cultureCode: String!
104+
}
105+
106+
type SearchDialog {
107+
id: UUID!
108+
org: String!
109+
serviceResource: String!
110+
party: String!
111+
progress: Int
112+
guiAttachmentCount: Int
113+
extendedStatus: String
114+
createdAt: DateTime!
115+
updatedAt: DateTime!
116+
dueAt: DateTime
117+
status: DialogStatus!
118+
latestActivity: Activity
119+
content: [Content!]!
120+
seenSinceLastUpdate: [SeenLog!]!
121+
}
122+
123+
type SearchDialogsPayload {
124+
items: [SearchDialog!]!
125+
hasNextPage: Boolean!
126+
continuationToken: String
127+
orderBy: String!
128+
}
129+
130+
type SeenLog {
131+
id: UUID!
132+
seenAt: DateTime!
133+
endUserIdHash: String!
134+
endUserName: String
135+
isCurrentEndUser: Boolean!
136+
}
137+
138+
input SearchDialogInput {
139+
"Filter by one or more service owner codes"
140+
org: [String!]
141+
"Filter by one or more service resources"
142+
serviceResource: [String!]
143+
"Filter by one or more owning parties"
144+
party: [String!]
145+
"Filter by one or more extended statuses"
146+
extendedStatus: [String!]
147+
"Filter by external reference"
148+
externalReference: String
149+
"Filter by status"
150+
status: [DialogStatus!]
151+
"Only return dialogs created after this date"
152+
createdAfter: DateTime
153+
"Only return dialogs created before this date"
154+
createdBefore: DateTime
155+
"Only return dialogs updated after this date"
156+
updatedAfter: DateTime
157+
"Only return dialogs updated before this date"
158+
updatedBefore: DateTime
159+
"Only return dialogs with due date after this date"
160+
dueAfter: DateTime
161+
"Only return dialogs with due date before this date"
162+
dueBefore: DateTime
163+
"Search string for free text search. Will attempt to fuzzily match in all free text fields in the aggregate"
164+
search: String
165+
"Limit free text search to texts with this culture code, e.g. \"nb-NO\". Default: search all culture codes"
166+
searchCultureCode: String
167+
}
168+
169+
enum ActivityType {
170+
"Refers to a submission made by a party that has been received by the service provider."
171+
SUBMISSION
172+
"Indicates feedback from the service provider on a submission. Contains a reference to the current submission."
173+
FEEDBACK
174+
"Information from the service provider, not (directly) related to any submission."
175+
INFORMATION
176+
"Used to indicate an error situation, typically on a submission. Contains a service-specific activityErrorCode."
177+
ERROR
178+
"Indicates that the dialog is closed for further changes. This typically happens when the dialog is completed or deleted."
179+
CLOSED
180+
"When the dialog is forwarded (delegated access) by someone with access to others."
181+
FORWARDED
182+
}
183+
184+
enum ApplyPolicy {
185+
BEFORE_RESOLVER
186+
AFTER_RESOLVER
187+
VALIDATION
188+
}
189+
190+
enum ContentType {
191+
TITLE
192+
SENDER_NAME
193+
SUMMARY
194+
ADDITIONAL_INFO
195+
}
196+
197+
enum DialogStatus {
198+
"New"
199+
NEW
200+
"In progress. General status used for dialog services where further user input is expected."
201+
IN_PROGRESS
202+
"Waiting for feedback from the service provider"
203+
WAITING
204+
"The dialog is in a state where it is waiting for signing. Typically the last step after all completion is carried out and validated."
205+
SIGNING
206+
"The dialog was cancelled. This typically removes the dialog from normal GUI views."
207+
CANCELLED
208+
"The dialog was completed. This typically moves the dialog to a GUI archive or similar."
209+
COMPLETED
210+
}
211+
212+
enum ElementUrlConsumer {
213+
GUI
214+
API
215+
}
216+
217+
enum GuiActionPriority {
218+
PRIMARY
219+
SECONDARY
220+
TERTIARY
221+
}
222+
223+
enum HttpVerb {
224+
GET
225+
POST
226+
PUT
227+
PATCH
228+
DELETE
229+
HEAD
230+
OPTIONS
231+
TRACE
232+
CONNECT
233+
}
234+
235+
directive @authorize("The name of the authorization policy that determines access to the annotated resource." policy: String "Roles that are allowed to access the annotated resource." roles: [String!] "Defines when when the authorize directive shall be applied.By default the authorize directives are applied during the validation phase." apply: ApplyPolicy! = BEFORE_RESOLVER) repeatable on OBJECT | FIELD_DEFINITION
236+
237+
"The `DateTime` scalar represents an ISO-8601 compliant date time type."
238+
scalar DateTime @specifiedBy(url: "https:\/\/www.graphql-scalars.com\/date-time")
239+
240+
scalar URL @specifiedBy(url: "https:\/\/tools.ietf.org\/html\/rfc3986")
241+
242+
scalar UUID @specifiedBy(url: "https:\/\/tools.ietf.org\/html\/rfc4122")
File renamed without changes.

docs/swagger/V1/.npmignore

-1
This file was deleted.

src/Digdir.Domain.Dialogporten.GraphQL/EndUser/DialogById/MappingProfile.cs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using AutoMapper;
2-
using Digdir.Domain.Dialogporten.Application.Features.V1.Common.Localizations;
32
using Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.Dialogs.Queries.Get;
43
using Digdir.Domain.Dialogporten.GraphQL.EndUser.Common;
54

src/Digdir.Domain.Dialogporten.GraphQL/EndUser/SearchDialogs/MappingProfile.cs

-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
using AutoMapper;
22
using Digdir.Domain.Dialogporten.Application.Common.Pagination;
3-
using Digdir.Domain.Dialogporten.Application.Features.V1.Common.Localizations;
4-
using Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.Dialogs.Queries.Get;
53
using Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.Dialogs.Queries.Search;
6-
using Digdir.Domain.Dialogporten.GraphQL.EndUser.Common;
74

85
namespace Digdir.Domain.Dialogporten.GraphQL.EndUser.SearchDialogs;
96

src/Digdir.Domain.Dialogporten.GraphQL/Program.cs

+10-20
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@
88
using Digdir.Domain.Dialogporten.GraphQL.Common.Authorization;
99
using Digdir.Domain.Dialogporten.GraphQL.Common.Extensions;
1010
using Digdir.Domain.Dialogporten.Infrastructure;
11-
using Digdir.Domain.Dialogporten.Infrastructure.Persistence;
1211
using Digdir.Domain.Dialogporten.Application.Common.Extensions.OptionExtensions;
1312
using Digdir.Domain.Dialogporten.GraphQL;
14-
using Digdir.Domain.Dialogporten.GraphQL.EndUser;
1513
using Microsoft.ApplicationInsights.Extensibility;
1614
using Serilog;
1715
using FluentValidation;
@@ -82,23 +80,14 @@ static void BuildAndRun(string[] args)
8280
// Clean architecture projects
8381
.AddApplication(builder.Configuration, builder.Environment)
8482
.AddInfrastructure(builder.Configuration, builder.Environment)
85-
8683
.AddAutoMapper(Assembly.GetExecutingAssembly())
8784
.AddApplicationInsightsTelemetry()
8885
.AddScoped<IUser, LocalDevelopmentUser>()
8986
.AddValidatorsFromAssembly(thisAssembly, ServiceLifetime.Transient, includeInternalTypes: true)
9087
.AddAzureAppConfiguration()
9188

9289
// Graph QL
93-
.AddGraphQLServer()
94-
.AddAuthorization()
95-
.AddProjections()
96-
.AddFiltering()
97-
.AddSorting()
98-
.RegisterDbContext<DialogDbContext>()
99-
.AddDiagnosticEventListener<ApplicationInsightEventListener>()
100-
.AddQueryType<DialogQueries>()
101-
.Services
90+
.AddDialogportenGraphQl()
10291

10392
// Auth
10493
.AddDialogportenAuthentication(builder.Configuration)
@@ -110,18 +99,19 @@ static void BuildAndRun(string[] args)
11099
app.UseJwtSchemeSelector()
111100
.UseAuthentication()
112101
.UseAuthorization()
102+
.UseSerilogRequestLogging()
113103
.UseAzureConfiguration();
114104

115105
app.MapGraphQL()
116-
.RequireAuthorization()
117-
.WithOptions(new GraphQLServerOptions
118-
{
119-
EnableSchemaRequests = true,
120-
Tool =
106+
.RequireAuthorization()
107+
.WithOptions(new GraphQLServerOptions
121108
{
122-
Enable = true
123-
}
124-
});
109+
EnableSchemaRequests = true,
110+
Tool =
111+
{
112+
Enable = true
113+
}
114+
});
125115

126116
app.MapHealthChecks("/healthz");
127117

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using Digdir.Domain.Dialogporten.GraphQL.EndUser;
2+
using Digdir.Domain.Dialogporten.Infrastructure.Persistence;
3+
4+
namespace Digdir.Domain.Dialogporten.GraphQL;
5+
6+
public static class ServiceCollectionExtensions
7+
{
8+
public static IServiceCollection AddDialogportenGraphQl(
9+
this IServiceCollection services)
10+
{
11+
return services
12+
.AddGraphQLServer()
13+
.AddAuthorization()
14+
.RegisterDbContext<DialogDbContext>()
15+
.AddDiagnosticEventListener<ApplicationInsightEventListener>()
16+
.AddQueryType<DialogQueries>()
17+
.Services;
18+
}
19+
}

0 commit comments

Comments
 (0)