Merge pull request #11 from TomPallister/develop

merge newest code
This commit is contained in:
geffzhang 2017-02-18 08:27:54 +08:00 committed by GitHub
commit ad01818596
4 changed files with 169 additions and 132 deletions

View File

@ -30,9 +30,6 @@ and retrived as the requests goes back up the Ocelot pipeline. There is a piece
that maps the HttpResponseMessage onto the HttpResponse object and that is returned to the client. that maps the HttpResponseMessage onto the HttpResponse object and that is returned to the client.
That is basically it with a bunch of other features. That is basically it with a bunch of other features.
This is not ready for production yet as uses a lot of rc and beta .net core packages.
Hopefully by the start of 2017 it will be in use.
## Contributing ## Contributing
Pull requests, issues and commentary welcome! No special process just create a request and get in Pull requests, issues and commentary welcome! No special process just create a request and get in
@ -61,11 +58,12 @@ The ReRoutes are the objects that tell Ocelot how to treat an upstream request.
configuration is a bit hacky and allows overrides of ReRoute specific settings. It's useful configuration is a bit hacky and allows overrides of ReRoute specific settings. It's useful
if you don't want to manage lots of ReRoute specific settings. if you don't want to manage lots of ReRoute specific settings.
```json
{ {
"ReRoutes": [], "ReRoutes": [],
"GlobalConfiguration": {} "GlobalConfiguration": {}
} }
```
More information on how to use these options is below.. More information on how to use these options is below..
## Startup ## Startup
@ -73,6 +71,7 @@ More information on how to use these options is below..
An example startup using a json file for configuration can be seen below. An example startup using a json file for configuration can be seen below.
Currently this is the only way to get configuration into Ocelot. Currently this is the only way to get configuration into Ocelot.
```csharp
public class Startup public class Startup
{ {
public Startup(IHostingEnvironment env) public Startup(IHostingEnvironment env)
@ -112,7 +111,7 @@ Currently this is the only way to get configuration into Ocelot.
app.UseOcelot(); app.UseOcelot();
} }
} }
```
This is pretty much all you need to get going.......more to come! This is pretty much all you need to get going.......more to come!
@ -127,14 +126,17 @@ Ocelot always adds a trailing slash to an UpstreamPathTemplate.
Ocelot's describes the routing of one request to another as a ReRoute. In order to get Ocelot's describes the routing of one request to another as a ReRoute. In order to get
anything working in Ocelot you need to set up a ReRoute in the configuration. anything working in Ocelot you need to set up a ReRoute in the configuration.
```json
{ {
"ReRoutes": [ "ReRoutes": [
] ]
} }
```
In order to set up a ReRoute you need to add one to the json array called ReRoutes like In order to set up a ReRoute you need to add one to the json array called ReRoutes like
the following. the following.
```json
{ {
"DownstreamPathTemplate": "/api/posts/{postId}", "DownstreamPathTemplate": "/api/posts/{postId}",
"DownstreamScheme": "https", "DownstreamScheme": "https",
@ -143,6 +145,7 @@ the following.
"UpstreamPathTemplate": "/posts/{postId}", "UpstreamPathTemplate": "/posts/{postId}",
"UpstreamHttpMethod": "Put" "UpstreamHttpMethod": "Put"
} }
```
The DownstreamPathTemplate,Scheme, Port and Host make the URL that this request will be forwarded to. The DownstreamPathTemplate,Scheme, Port and Host make the URL that this request will be forwarded to.
The UpstreamPathTemplate is the URL that Ocelot will use to identity which The UpstreamPathTemplate is the URL that Ocelot will use to identity which
@ -156,7 +159,9 @@ Upstream URL when the request comes in.
At the moment without any configuration Ocelot will default to all ReRoutes being case insensitive. At the moment without any configuration Ocelot will default to all ReRoutes being case insensitive.
In order to change this you can specify on a per ReRoute basis the following setting. In order to change this you can specify on a per ReRoute basis the following setting.
```json
"ReRouteIsCaseSensitive": true "ReRouteIsCaseSensitive": true
```
This means that when Ocelot tries to match the incoming upstream url with an upstream template the This means that when Ocelot tries to match the incoming upstream url with an upstream template the
evaluation will be case sensitive. This setting defaults to false so only set it if you want evaluation will be case sensitive. This setting defaults to false so only set it if you want
@ -176,25 +181,28 @@ At the moment the only supported service discovery provider is Consul. The follo
GlobalConfiguration. The Provider is required and if you do not specify a host and port the Consul default GlobalConfiguration. The Provider is required and if you do not specify a host and port the Consul default
will be used. will be used.
"ServiceDiscoveryProvider": ```json
{ "ServiceDiscoveryProvider": {
"Provider":"Consul", "Provider":"Consul",
"Host":"localhost", "Host":"localhost",
"Port":8500 "Port":8500
} }
```
In order to tell Ocelot a ReRoute is to use the service discovery provider for its host and port you must add the In order to tell Ocelot a ReRoute is to use the service discovery provider for its host and port you must add the
ServiceName and load balancer you wish to use when making requests downstream. At the moment Ocelot has a RoundRobin ServiceName and load balancer you wish to use when making requests downstream. At the moment Ocelot has a RoundRobin
and LeastConnection algorithm you can use. If no load balancer is specified Ocelot will not load balance requests. and LeastConnection algorithm you can use. If no load balancer is specified Ocelot will not load balance requests.
```json
{ {
"DownstreamPathTemplate": "/api/posts/{postId}", "DownstreamPathTemplate": "/api/posts/{postId}",
"DownstreamScheme": "https", "DownstreamScheme": "https",
"UpstreamPathTemplate": "/posts/{postId}", "UpstreamPathTemplate": "/posts/{postId}",
"UpstreamHttpMethod": "Put", "UpstreamHttpMethod": "Put",
"ServiceName": "product" "ServiceName": "product",
"LoadBalancer": "LeastConnection" "LoadBalancer": "LeastConnection"
} }
```
When this is set up Ocelot will lookup the downstream host and port from the service discover provider and load balancer When this is set up Ocelot will lookup the downstream host and port from the service discover provider and load balancer
requests across any available services. requests across any available services.
@ -206,6 +214,7 @@ Ocelot currently supports the use of bearer tokens with Identity Server (more pr
come if required). In order to identity a ReRoute as authenticated it needs the following come if required). In order to identity a ReRoute as authenticated it needs the following
configuration added. configuration added.
```json
"AuthenticationOptions": { "AuthenticationOptions": {
"Provider": "IdentityServer", "Provider": "IdentityServer",
"ProviderRootUrl": "http://localhost:52888", "ProviderRootUrl": "http://localhost:52888",
@ -216,6 +225,7 @@ configuration added.
], ],
"ScopeSecret": "secret" "ScopeSecret": "secret"
} }
```
In this example the Provider is specified as IdentityServer. This string is important In this example the Provider is specified as IdentityServer. This string is important
because it is used to identity the authentication provider (as previously mentioned in because it is used to identity the authentication provider (as previously mentioned in
@ -234,9 +244,11 @@ is 401 unauthorised.
Ocelot supports claims based authorisation which is run post authentication. This means if Ocelot supports claims based authorisation which is run post authentication. This means if
you have a route you want to authorise you can add the following to you ReRoute configuration. you have a route you want to authorise you can add the following to you ReRoute configuration.
```json
"RouteClaimsRequirement": { "RouteClaimsRequirement": {
"UserType": "registered" "UserType": "registered"
}, },
```
In this example when the authorisation middleware is called Ocelot will check to see In this example when the authorisation middleware is called Ocelot will check to see
if the user has the claim type UserType and if the value of that claim is registered. if the user has the claim type UserType and if the value of that claim is registered.
@ -275,10 +287,12 @@ and add whatever was at the index requested to the transform.
Below is an example configuration that will transforms claims to claims Below is an example configuration that will transforms claims to claims
```json
"AddClaimsToRequest": { "AddClaimsToRequest": {
"UserType": "Claims[sub] > value[0] > |", "UserType": "Claims[sub] > value[0] > |",
"UserId": "Claims[sub] > value[1] > |" "UserId": "Claims[sub] > value[1] > |"
}, },
```
This shows a transforms where Ocelot looks at the users sub claim and transforms it into This shows a transforms where Ocelot looks at the users sub claim and transforms it into
UserType and UserId claims. Assuming the sub looks like this "usertypevalue|useridvalue". UserType and UserId claims. Assuming the sub looks like this "usertypevalue|useridvalue".
@ -287,9 +301,11 @@ UserType and UserId claims. Assuming the sub looks like this "usertypevalue|user
Below is an example configuration that will transforms claims to headers Below is an example configuration that will transforms claims to headers
```json
"AddHeadersToRequest": { "AddHeadersToRequest": {
"CustomerId": "Claims[sub] > value[1] > |" "CustomerId": "Claims[sub] > value[1] > |"
}, },
```
This shows a transform where Ocelot looks at the users sub claim and trasnforms it into a This shows a transform where Ocelot looks at the users sub claim and trasnforms it into a
CustomerId header. Assuming the sub looks like this "usertypevalue|useridvalue". CustomerId header. Assuming the sub looks like this "usertypevalue|useridvalue".
@ -298,9 +314,11 @@ CustomerId header. Assuming the sub looks like this "usertypevalue|useridvalue".
Below is an example configuration that will transforms claims to query string parameters Below is an example configuration that will transforms claims to query string parameters
```json
"AddQueriesToRequest": { "AddQueriesToRequest": {
"LocationId": "Claims[LocationId] > value", "LocationId": "Claims[LocationId] > value",
}, },
```
This shows a transform where Ocelot looks at the users LocationId claim and add its as This shows a transform where Ocelot looks at the users LocationId claim and add its as
a query string parameter to be forwarded onto the downstream service. a query string parameter to be forwarded onto the downstream service.
@ -313,11 +331,13 @@ want to use a circuit breaker when making requests to a downstream service. This
Add the following section to a ReRoute configuration. Add the following section to a ReRoute configuration.
```json
"QoSOptions": { "QoSOptions": {
"ExceptionsAllowedBeforeBreaking":3, "ExceptionsAllowedBeforeBreaking":3,
"DurationOfBreak":5, "DurationOfBreak":5,
"TimeoutValue":5000 "TimeoutValue":5000
} }
```
You must set a number greater than 0 against ExceptionsAllowedBeforeBreaking for this rule to be You must set a number greater than 0 against ExceptionsAllowedBeforeBreaking for this rule to be
implemented. Duration of break is how long the circuit breaker will stay open for after it is tripped. implemented. Duration of break is how long the circuit breaker will stay open for after it is tripped.
@ -338,14 +358,18 @@ have an OcelotRequestId.
In order to use the requestid feature in your ReRoute configuration add this setting In order to use the requestid feature in your ReRoute configuration add this setting
```json
"RequestIdKey": "OcRequestId" "RequestIdKey": "OcRequestId"
```
In this example OcRequestId is the request header that contains the clients request id. In this example OcRequestId is the request header that contains the clients request id.
There is also a setting in the GlobalConfiguration section which will override whatever has been There is also a setting in the GlobalConfiguration section which will override whatever has been
set at ReRoute level for the request id. The setting is as fllows. set at ReRoute level for the request id. The setting is as fllows.
```json
"RequestIdKey": "OcRequestId", "RequestIdKey": "OcRequestId",
```
It behaves in exactly the same way as the ReRoute level RequestIdKey settings. It behaves in exactly the same way as the ReRoute level RequestIdKey settings.
@ -364,7 +388,9 @@ and setting a TTL in seconds to expire the cache. More to come!
In orde to use caching on a route in your ReRoute configuration add this setting. In orde to use caching on a route in your ReRoute configuration add this setting.
```json
"FileCacheOptions": { "TtlSeconds": 15 } "FileCacheOptions": { "TtlSeconds": 15 }
```
In this example ttl seconds is set to 15 which means the cache will expire after 15 seconds. In this example ttl seconds is set to 15 which means the cache will expire after 15 seconds.
@ -376,6 +402,7 @@ pipeline and you are using any of the following. Remove them and try again!
When setting up Ocelot in your Startup.cs you can provide some additonal middleware When setting up Ocelot in your Startup.cs you can provide some additonal middleware
and override middleware. This is done as follos. and override middleware. This is done as follos.
```csharp
var configuration = new OcelotMiddlewareConfiguration var configuration = new OcelotMiddlewareConfiguration
{ {
PreErrorResponderMiddleware = async (ctx, next) => PreErrorResponderMiddleware = async (ctx, next) =>
@ -385,6 +412,7 @@ and override middleware. This is done as follos.
}; };
app.UseOcelot(configuration); app.UseOcelot(configuration);
```
In the example above the provided function will run before the first piece of Ocelot middleware. In the example above the provided function will run before the first piece of Ocelot middleware.
This allows a user to supply any behaviours they want before and after the Ocelot pipeline has run. This allows a user to supply any behaviours they want before and after the Ocelot pipeline has run.

View File

@ -1,5 +1,13 @@
{ {
"version": "0.0.0-dev", "version": "0.0.0-dev",
"title": "Ocelot",
"summary": "API Gateway created using .NET core.",
"projectUrl": "https://github.com/TomPallister/Ocelot",
"description": "This project is aimed at people using .NET running a micro services / service orientated architecture that need a unified point of entry into their system. In particular I want easy integration with IdentityServer reference and bearer tokens. We have been unable to find this in my current workplace without having to write our own Javascript middlewares to handle the IdentityServer reference tokens. We would rather use the IdentityServer code that already exists to do this. Ocelot is a bunch of middlewares in a specific order. Ocelot manipulates the HttpRequest object into a state specified by its configuration until it reaches a request builder middleware where it creates a HttpRequestMessage object which is used to make a request to a downstream service. The middleware that makes the request is the last thing in the Ocelot pipeline. It does not call the next middleware. The response from the downstream service is stored in a per request scoped repository and retrived as the requests goes back up the Ocelot pipeline. There is a piece of middleware that maps the HttpResponseMessage onto the HttpResponse object and that is returned to the client. That is basically it with a bunch of other features.",
"tags": [
"API Gateway",
".NET core"
],
"dependencies": { "dependencies": {
"Microsoft.AspNetCore.Server.IISIntegration": "1.1.0", "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0", "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",

View File

@ -29,6 +29,7 @@
"IdentityServer4": "1.0.1", "IdentityServer4": "1.0.1",
"Microsoft.AspNetCore.Mvc": "1.1.0", "Microsoft.AspNetCore.Mvc": "1.1.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.1.0", "Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
"Microsoft.AspNetCore.Server.Kestrel.Https": "1.1.0",
"Microsoft.NETCore.App": "1.1.0", "Microsoft.NETCore.App": "1.1.0",
"Shouldly": "2.8.2", "Shouldly": "2.8.2",
"TestStack.BDDfy": "4.3.2", "TestStack.BDDfy": "4.3.2",

View File

@ -5,7 +5,7 @@
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHost": "localhost", "DownstreamHost": "localhost",
"DownstreamPort": 52876, "DownstreamPort": 52876,
"UpstreamTemplate": "/identityserverexample", "UpstreamPathTemplate": "/identityserverexample",
"UpstreamHttpMethod": "Get", "UpstreamHttpMethod": "Get",
"QoSOptions": { "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3, "ExceptionsAllowedBeforeBreaking": 3,
@ -47,10 +47,10 @@
}, },
{ {
"DownstreamPathTemplate": "/posts", "DownstreamPathTemplate": "/posts",
"DownstreamScheme": "http", "DownstreamScheme": "https",
"DownstreamHost": "jsonplaceholder.typicode.com", "DownstreamHost": "jsonplaceholder.typicode.com",
"DownstreamPort": 80, "DownstreamPort": 443,
"UpstreamTemplate": "/posts", "UpstreamPathTemplate": "/posts",
"UpstreamHttpMethod": "Get", "UpstreamHttpMethod": "Get",
"QoSOptions": { "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3, "ExceptionsAllowedBeforeBreaking": 3,
@ -63,7 +63,7 @@
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHost": "jsonplaceholder.typicode.com", "DownstreamHost": "jsonplaceholder.typicode.com",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/posts/{postId}", "UpstreamPathTemplate": "/posts/{postId}",
"UpstreamHttpMethod": "Get", "UpstreamHttpMethod": "Get",
"QoSOptions": { "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3, "ExceptionsAllowedBeforeBreaking": 3,
@ -76,7 +76,7 @@
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHost": "jsonplaceholder.typicode.com", "DownstreamHost": "jsonplaceholder.typicode.com",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/posts/{postId}/comments", "UpstreamPathTemplate": "/posts/{postId}/comments",
"UpstreamHttpMethod": "Get", "UpstreamHttpMethod": "Get",
"QoSOptions": { "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3, "ExceptionsAllowedBeforeBreaking": 3,
@ -89,7 +89,7 @@
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHost": "jsonplaceholder.typicode.com", "DownstreamHost": "jsonplaceholder.typicode.com",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/comments", "UpstreamPathTemplate": "/comments",
"UpstreamHttpMethod": "Get", "UpstreamHttpMethod": "Get",
"QoSOptions": { "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3, "ExceptionsAllowedBeforeBreaking": 3,
@ -102,7 +102,7 @@
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHost": "jsonplaceholder.typicode.com", "DownstreamHost": "jsonplaceholder.typicode.com",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/posts", "UpstreamPathTemplate": "/posts",
"UpstreamHttpMethod": "Post", "UpstreamHttpMethod": "Post",
"QoSOptions": { "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3, "ExceptionsAllowedBeforeBreaking": 3,
@ -115,7 +115,7 @@
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHost": "jsonplaceholder.typicode.com", "DownstreamHost": "jsonplaceholder.typicode.com",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/posts/{postId}", "UpstreamPathTemplate": "/posts/{postId}",
"UpstreamHttpMethod": "Put", "UpstreamHttpMethod": "Put",
"QoSOptions": { "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3, "ExceptionsAllowedBeforeBreaking": 3,
@ -128,7 +128,7 @@
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHost": "jsonplaceholder.typicode.com", "DownstreamHost": "jsonplaceholder.typicode.com",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/posts/{postId}", "UpstreamPathTemplate": "/posts/{postId}",
"UpstreamHttpMethod": "Patch", "UpstreamHttpMethod": "Patch",
"QoSOptions": { "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3, "ExceptionsAllowedBeforeBreaking": 3,
@ -141,7 +141,7 @@
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHost": "jsonplaceholder.typicode.com", "DownstreamHost": "jsonplaceholder.typicode.com",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/posts/{postId}", "UpstreamPathTemplate": "/posts/{postId}",
"UpstreamHttpMethod": "Delete", "UpstreamHttpMethod": "Delete",
"QoSOptions": { "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3, "ExceptionsAllowedBeforeBreaking": 3,
@ -154,7 +154,7 @@
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHost": "jsonplaceholder.typicode.com", "DownstreamHost": "jsonplaceholder.typicode.com",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/products", "UpstreamPathTemplate": "/products",
"UpstreamHttpMethod": "Get", "UpstreamHttpMethod": "Get",
"QoSOptions": { "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3, "ExceptionsAllowedBeforeBreaking": 3,
@ -168,7 +168,7 @@
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHost": "jsonplaceholder.typicode.com", "DownstreamHost": "jsonplaceholder.typicode.com",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/products/{productId}", "UpstreamPathTemplate": "/products/{productId}",
"UpstreamHttpMethod": "Get", "UpstreamHttpMethod": "Get",
"FileCacheOptions": { "TtlSeconds": 15 } "FileCacheOptions": { "TtlSeconds": 15 }
}, },
@ -177,7 +177,7 @@
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHost": "products20161126090340.azurewebsites.net", "DownstreamHost": "products20161126090340.azurewebsites.net",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/products", "UpstreamPathTemplate": "/products",
"UpstreamHttpMethod": "Post", "UpstreamHttpMethod": "Post",
"QoSOptions": { "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3, "ExceptionsAllowedBeforeBreaking": 3,
@ -190,7 +190,7 @@
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHost": "products20161126090340.azurewebsites.net", "DownstreamHost": "products20161126090340.azurewebsites.net",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/products/{productId}", "UpstreamPathTemplate": "/products/{productId}",
"UpstreamHttpMethod": "Put", "UpstreamHttpMethod": "Put",
"QoSOptions": { "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3, "ExceptionsAllowedBeforeBreaking": 3,
@ -204,7 +204,7 @@
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHost": "products20161126090340.azurewebsites.net", "DownstreamHost": "products20161126090340.azurewebsites.net",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/products/{productId}", "UpstreamPathTemplate": "/products/{productId}",
"UpstreamHttpMethod": "Delete", "UpstreamHttpMethod": "Delete",
"QoSOptions": { "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3, "ExceptionsAllowedBeforeBreaking": 3,
@ -218,7 +218,7 @@
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHost": "customers20161126090811.azurewebsites.net", "DownstreamHost": "customers20161126090811.azurewebsites.net",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/customers", "UpstreamPathTemplate": "/customers",
"UpstreamHttpMethod": "Get", "UpstreamHttpMethod": "Get",
"QoSOptions": { "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3, "ExceptionsAllowedBeforeBreaking": 3,
@ -232,7 +232,7 @@
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHost": "customers20161126090811.azurewebsites.net", "DownstreamHost": "customers20161126090811.azurewebsites.net",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/customers/{customerId}", "UpstreamPathTemplate": "/customers/{customerId}",
"UpstreamHttpMethod": "Get", "UpstreamHttpMethod": "Get",
"QoSOptions": { "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3, "ExceptionsAllowedBeforeBreaking": 3,
@ -246,7 +246,7 @@
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHost": "customers20161126090811.azurewebsites.net", "DownstreamHost": "customers20161126090811.azurewebsites.net",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/customers", "UpstreamPathTemplate": "/customers",
"UpstreamHttpMethod": "Post", "UpstreamHttpMethod": "Post",
"QoSOptions": { "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3, "ExceptionsAllowedBeforeBreaking": 3,
@ -260,7 +260,7 @@
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHost": "customers20161126090811.azurewebsites.net", "DownstreamHost": "customers20161126090811.azurewebsites.net",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/customers/{customerId}", "UpstreamPathTemplate": "/customers/{customerId}",
"UpstreamHttpMethod": "Put", "UpstreamHttpMethod": "Put",
"QoSOptions": { "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3, "ExceptionsAllowedBeforeBreaking": 3,
@ -274,7 +274,7 @@
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHost": "customers20161126090811.azurewebsites.net", "DownstreamHost": "customers20161126090811.azurewebsites.net",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/customers/{customerId}", "UpstreamPathTemplate": "/customers/{customerId}",
"UpstreamHttpMethod": "Delete", "UpstreamHttpMethod": "Delete",
"QoSOptions": { "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3, "ExceptionsAllowedBeforeBreaking": 3,
@ -288,7 +288,7 @@
"DownstreamScheme": "http", "DownstreamScheme": "http",
"DownstreamHost": "jsonplaceholder.typicode.com", "DownstreamHost": "jsonplaceholder.typicode.com",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/posts/", "UpstreamPathTemplate": "/posts/",
"UpstreamHttpMethod": "Get", "UpstreamHttpMethod": "Get",
"QoSOptions": { "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3, "ExceptionsAllowedBeforeBreaking": 3,