mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-06-19 02:18:15 +08:00
Feature/graphql (#312)
* #298 initial hacking around better aggregation * #298 bit more hacking around * #298 abstraction over httpresponsemessage * #298 tidying up * #298 docs * #298 missed this * #306 example of how to do GraphQL
This commit is contained in:
18
samples/OcelotGraphQL/OcelotGraphQL.csproj
Normal file
18
samples/OcelotGraphQL/OcelotGraphQL.csproj
Normal file
@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Update="configuration.json;appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="wwwroot\"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.6"/>
|
||||
<PackageReference Include="Ocelot" Version="5.5.1"/>
|
||||
<PackageReference Include="GraphQL" Version="2.0.0-alpha-870"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
131
samples/OcelotGraphQL/Program.cs
Normal file
131
samples/OcelotGraphQL/Program.cs
Normal file
@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ocelot.Middleware;
|
||||
using Ocelot.DependencyInjection;
|
||||
using GraphQL.Types;
|
||||
using GraphQL;
|
||||
using Ocelot.Requester;
|
||||
using Ocelot.Responses;
|
||||
using System.Net.Http;
|
||||
using System.Net;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Threading;
|
||||
|
||||
namespace OcelotGraphQL
|
||||
{
|
||||
public class Hero
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
public class Query
|
||||
{
|
||||
private List<Hero> _heroes = new List<Hero>
|
||||
{
|
||||
new Hero { Id = 1, Name = "R2-D2" },
|
||||
new Hero { Id = 2, Name = "Batman" },
|
||||
new Hero { Id = 3, Name = "Wonder Woman" },
|
||||
new Hero { Id = 4, Name = "Tom Pallister" }
|
||||
};
|
||||
|
||||
[GraphQLMetadata("hero")]
|
||||
public Hero GetHero(int id)
|
||||
{
|
||||
return _heroes.FirstOrDefault(x => x.Id == id);
|
||||
}
|
||||
}
|
||||
|
||||
public class GraphQlDelegatingHandler : DelegatingHandler
|
||||
{
|
||||
private readonly ISchema _schema;
|
||||
|
||||
public GraphQlDelegatingHandler(ISchema schema)
|
||||
{
|
||||
_schema = schema;
|
||||
}
|
||||
|
||||
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
//try get query from body, could check http method :)
|
||||
var query = await request.Content.ReadAsStringAsync();
|
||||
|
||||
//if not body try query string, dont hack like this in real world..
|
||||
if(query.Length == 0)
|
||||
{
|
||||
var decoded = WebUtility.UrlDecode(request.RequestUri.Query);
|
||||
query = decoded.Replace("?query=", "");
|
||||
}
|
||||
|
||||
var result = _schema.Execute(_ =>
|
||||
{
|
||||
_.Query = query;
|
||||
});
|
||||
|
||||
//maybe check for errors and headers etc in real world?
|
||||
var response = new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StringContent(result)
|
||||
};
|
||||
|
||||
//ocelot will treat this like any other http request...
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var schema = Schema.For(@"
|
||||
type Hero {
|
||||
id: Int
|
||||
name: String
|
||||
}
|
||||
|
||||
type Query {
|
||||
hero(id: Int): Hero
|
||||
}
|
||||
", _ => {
|
||||
_.Types.Include<Query>();
|
||||
});
|
||||
|
||||
new WebHostBuilder()
|
||||
.UseKestrel()
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.ConfigureAppConfiguration((hostingContext, config) =>
|
||||
{
|
||||
config
|
||||
.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
|
||||
.AddJsonFile("appsettings.json", true, true)
|
||||
.AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true)
|
||||
.AddJsonFile("configuration.json")
|
||||
.AddEnvironmentVariables();
|
||||
})
|
||||
.ConfigureServices(s => {
|
||||
s.AddSingleton<ISchema>(schema);
|
||||
s.AddOcelot()
|
||||
.AddSingletonDelegatingHandler<GraphQlDelegatingHandler>();
|
||||
})
|
||||
.ConfigureLogging((hostingContext, logging) =>
|
||||
{
|
||||
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
|
||||
logging.AddConsole();
|
||||
})
|
||||
.UseIISIntegration()
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseOcelot().Wait();
|
||||
})
|
||||
.Build()
|
||||
.Run();
|
||||
}
|
||||
}
|
||||
}
|
71
samples/OcelotGraphQL/README.md
Normal file
71
samples/OcelotGraphQL/README.md
Normal file
@ -0,0 +1,71 @@
|
||||
# Ocelot using GraphQL example
|
||||
|
||||
Loads of people keep asking me if Ocelot will every support GraphQL, in my mind Ocelot and GraphQL are two different things that can work together.
|
||||
I would not try and implement GraphQL in Ocelot instead I would either have Ocelot in front of GraphQL to handle things like authorisation / authentication or I would
|
||||
bring in the awesome [graphql-dotnet](https://github.com/graphql-dotnet/graphql-dotnet) library and use it in a [DelegatingHandler](http://ocelot.readthedocs.io/en/latest/features/delegatinghandlers.html). This way you could have Ocelot and GraphQL without the extra hop to GraphQL. This same is an example of how to do that.
|
||||
|
||||
## Example
|
||||
|
||||
If you run this project with
|
||||
|
||||
$ dotnet run
|
||||
|
||||
Use postman or something to make the following requests and you can see Ocelot and GraphQL in action together...
|
||||
|
||||
GET http://localhost:5000/graphql?query={ hero(id: 4) { id name } }
|
||||
|
||||
RESPONSE
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"hero": {
|
||||
"id": 4,
|
||||
"name": "Tom Pallister"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
POST http://localhost:5000/graphql
|
||||
|
||||
BODY
|
||||
```json
|
||||
{ hero(id: 4) { id name } }
|
||||
```
|
||||
|
||||
RESPONSE
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"hero": {
|
||||
"id": 4,
|
||||
"name": "Tom Pallister"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
Please note this project never goes out to another service, it just gets the data for GraphQL in memory. You would need to add the details of your GraphQL server in configuration.json e.g.
|
||||
|
||||
```json
|
||||
{
|
||||
"ReRoutes": [
|
||||
{
|
||||
"DownstreamPathTemplate": "/graphql",
|
||||
"DownstreamScheme": "http",
|
||||
"DownstreamHostAndPorts": [
|
||||
{
|
||||
"Host": "yourgraphqlhost.com",
|
||||
"Port": 80
|
||||
}
|
||||
],
|
||||
"UpstreamPathTemplate": "/graphql",
|
||||
"DelegatingHandlers": [
|
||||
"GraphQlDelegatingHandler"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
19
samples/OcelotGraphQL/configuration.json
Normal file
19
samples/OcelotGraphQL/configuration.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"ReRoutes": [
|
||||
{
|
||||
"DownstreamPathTemplate": "/",
|
||||
"DownstreamScheme": "http",
|
||||
"DownstreamHostAndPorts": [
|
||||
{
|
||||
"Host": "jsonplaceholder.typicode.com",
|
||||
"Port": 80
|
||||
}
|
||||
],
|
||||
"UpstreamPathTemplate": "/graphql",
|
||||
"DelegatingHandlers": [
|
||||
"GraphQlDelegatingHandler"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Reference in New Issue
Block a user