Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4776afc
commit 538a94e
Showing
5 changed files
with
236 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 62 additions & 0 deletions
62
src/HotChocolate/AspNetCore/src/AspNetCore/HttpGetSchemaMiddleware.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
using System.IO; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Http; | ||
using HotChocolate.AspNetCore.Utilities; | ||
using HotChocolate.Execution; | ||
using HttpRequestDelegate = Microsoft.AspNetCore.Http.RequestDelegate; | ||
|
||
namespace HotChocolate.AspNetCore | ||
{ | ||
public class HttpGetSchemaMiddleware : MiddlewareBase | ||
{ | ||
|
||
public HttpGetSchemaMiddleware( | ||
HttpRequestDelegate next, | ||
IRequestExecutorResolver executorResolver, | ||
IHttpResultSerializer resultSerializer, | ||
NameString schemaName) | ||
: base(next, executorResolver, resultSerializer, schemaName) | ||
{ | ||
} | ||
|
||
public async Task InvokeAsync(HttpContext context) | ||
{ | ||
if (HttpMethods.IsGet(context.Request.Method) && | ||
context.Request.Query.ContainsKey("SDL")) | ||
{ | ||
await HandleRequestAsync(context); | ||
} | ||
else | ||
{ | ||
// if the request is not a get request or if the content type is not correct | ||
// we will just invoke the next middleware and do nothing. | ||
await NextAsync(context); | ||
} | ||
} | ||
|
||
private async Task HandleRequestAsync(HttpContext context) | ||
{ | ||
IRequestExecutor requestExecutor = await GetExecutorAsync(context.RequestAborted); | ||
|
||
string fileName = | ||
requestExecutor.Schema.Name.IsEmpty || | ||
requestExecutor.Schema.Name.Equals(Schema.DefaultName) | ||
? "schema.graphql" | ||
: requestExecutor.Schema.Name + ".schema.graphql"; | ||
|
||
context.Response.ContentType = ContentType.GraphQL; | ||
context.Response.Headers.Add( | ||
"Content-Disposition", | ||
new[] { $"attachment; filename=\"{fileName}\"" }); | ||
|
||
await using var memoryStream = new MemoryStream(); | ||
await using var streamWriter = new StreamWriter(memoryStream); | ||
|
||
SchemaSerializer.Serialize(requestExecutor.Schema, streamWriter); | ||
await streamWriter.FlushAsync().ConfigureAwait(false); | ||
|
||
memoryStream.Seek(0, SeekOrigin.Begin); | ||
await memoryStream.CopyToAsync(context.Response.Body).ConfigureAwait(false); | ||
} | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
src/HotChocolate/AspNetCore/test/AspNetCore.Tests/HttpGetSchemaMiddlewareTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
using System.Net; | ||
using System.Net.Http; | ||
using System.Threading.Tasks; | ||
using HotChocolate.AspNetCore.Utilities; | ||
using Microsoft.AspNetCore.TestHost; | ||
using Snapshooter.Xunit; | ||
using Xunit; | ||
|
||
namespace HotChocolate.AspNetCore | ||
{ | ||
public class HttpGetSchemaMiddlewareTests : ServerTestBase | ||
{ | ||
public HttpGetSchemaMiddlewareTests(TestServerFactory serverFactory) | ||
: base(serverFactory) | ||
{ | ||
} | ||
|
||
[Fact] | ||
public async Task Download_GraphQL_SDL() | ||
{ | ||
// arrange | ||
TestServer server = CreateStarWarsServer(); | ||
var url = TestServerExtensions.CreateUrl("/graphql?sdl"); | ||
var request = new HttpRequestMessage(HttpMethod.Get, url); | ||
|
||
// act | ||
HttpResponseMessage response = await server.CreateClient().SendAsync(request); | ||
|
||
// assert | ||
Assert.Equal(HttpStatusCode.OK, response.StatusCode); | ||
var result = await response.Content.ReadAsStringAsync(); | ||
result.MatchSnapshot(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
131 changes: 131 additions & 0 deletions
131
...est/AspNetCore.Tests/__snapshots__/HttpGetSchemaMiddlewareTests.Download_GraphQL_SDL.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
schema { | ||
query: Query | ||
mutation: Mutation | ||
subscription: Subscription | ||
} | ||
|
||
interface Character { | ||
id: ID! | ||
name: String | ||
friends(first: PaginationAmount after: String last: PaginationAmount before: String): CharacterConnection | ||
appearsIn: [Episode] | ||
height(unit: Unit): Float | ||
} | ||
|
||
"A connection to a list of items." | ||
type CharacterConnection { | ||
"Information to aid in pagination." | ||
pageInfo: PageInfo! | ||
"A list of edges." | ||
edges: [CharacterEdge!] | ||
"A flattened list of the nodes." | ||
nodes: [Character] | ||
totalCount: Int! | ||
} | ||
|
||
"An edge in a connection." | ||
type CharacterEdge { | ||
"A cursor for use in pagination." | ||
cursor: String! | ||
"The item at the end of the edge." | ||
node: Character | ||
} | ||
|
||
type Droid implements Character { | ||
id: ID! | ||
appearsIn: [Episode] | ||
friends(first: PaginationAmount after: String last: PaginationAmount before: String): CharacterConnection | ||
height(unit: Unit): Float | ||
name: String | ||
primaryFunction: String | ||
} | ||
|
||
type Human implements Character { | ||
id: ID! | ||
appearsIn: [Episode] | ||
friends(first: PaginationAmount after: String last: PaginationAmount before: String): CharacterConnection | ||
otherHuman: Human | ||
height(unit: Unit): Float | ||
name: String | ||
homePlanet: String | ||
} | ||
|
||
type Mutation { | ||
createReview(episode: Episode! review: ReviewInput!): Review! | ||
} | ||
|
||
"Information about pagination in a connection." | ||
type PageInfo { | ||
"Indicates whether more edges exist following the set defined by the clients arguments." | ||
hasNextPage: Boolean! | ||
"Indicates whether more edges exist prior the set defined by the clients arguments." | ||
hasPreviousPage: Boolean! | ||
"When paginating backwards, the cursor to continue." | ||
startCursor: String | ||
"When paginating forwards, the cursor to continue." | ||
endCursor: String | ||
} | ||
|
||
type Query { | ||
hero(episode: Episode! = NEW_HOPE): Character | ||
heroes(episodes: [Episode!]): [Character!] | ||
character(characterIds: [String]): [Character!]! | ||
search(text: String): [SearchResult] | ||
human(id: String): Human | ||
droid(id: String): Droid | ||
time: Long! | ||
evict: Boolean! | ||
} | ||
|
||
type Review { | ||
stars: Int! | ||
commentary: String | ||
} | ||
|
||
type Starship { | ||
id: String | ||
name: String | ||
length: Float! | ||
} | ||
|
||
type Subscription { | ||
onReview(episode: Episode!): Review! | ||
} | ||
|
||
union SearchResult = Starship | Human | Droid | ||
|
||
input ReviewInput { | ||
stars: Int! | ||
commentary: String | ||
} | ||
|
||
enum Episode { | ||
NEW_HOPE | ||
EMPIRE | ||
JEDI | ||
} | ||
|
||
enum Unit { | ||
FOOT | ||
METERS | ||
} | ||
|
||
"The `Boolean` scalar type represents `true` or `false`." | ||
scalar Boolean | ||
|
||
"The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http:\/\/en.wikipedia.org\/wiki\/IEEE_floating_point)." | ||
scalar Float | ||
|
||
"The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID." | ||
scalar ID | ||
|
||
"The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." | ||
scalar Int | ||
|
||
"The `Long` scalar type represents non-fractional signed whole 64-bit numeric values. Long can represent values between -(2^63) and 2^63 - 1." | ||
scalar Long | ||
|
||
scalar PaginationAmount | ||
|
||
"The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." | ||
scalar String |