Middleware

Customize processing pipelines by adding middleware components

Dapr allows custom processing pipelines to be defined by chaining a series of middleware components. There are two places that you can use a middleware pipeline;

  1. Building block APIs - HTTP middleware components are executed when invoking any Dapr HTTP APIs.
  2. Service-to-Service invocation - HTTP middleware components are applied to service-to-service invocation calls.

Configuring API middleware pipelines

When launched, a Dapr sidecar constructs a middleware processing pipeline for incoming HTTP calls. By default, the pipeline consists of tracing middleware and CORS middleware. Additional middleware, configured by a Dapr configuration, can be added to the pipeline in the order they are defined. The pipeline applies to all Dapr API endpoints, including state, pub/sub, service invocation, bindings, secrets, configuration, distributed lock, and others.

A request goes through all the defined middleware components before it’s routed to user code, and then goes through the defined middleware, in reverse order, before it’s returned to the client, as shown in the following diagram.

Middleware - 图1

HTTP middleware components are executed when invoking Dapr HTTP APIs using the httpPipeline configuration.

The following configuration example defines a custom pipeline that uses a OAuth 2.0 middleware and an uppercase middleware component. In this case, all requests are authorized through the OAuth 2.0 protocol, and transformed to uppercase text, before they are forwarded to user code.

  1. apiVersion: dapr.io/v1alpha1
  2. kind: Configuration
  3. metadata:
  4. name: pipeline
  5. namespace: default
  6. spec:
  7. httpPipeline:
  8. handlers:
  9. - name: oauth2
  10. type: middleware.http.oauth2
  11. - name: uppercase
  12. type: middleware.http.uppercase

As with other components, middleware components can be found in the supported Middleware reference and in the components-contrib repo.

See all middleware components

Configuring app middleware pipelines

You can also use any middleware components when making service-to-service invocation calls. For example, for token validation in a zero-trust environment, a request transformation for a specific app endpoint, or to apply OAuth policies.

Service-to-service invocation middleware components apply to all outgoing calls from Dapr sidecar to the receiving application (service) as shown in the diagram below.

Middleware - 图2

Any middleware component that can be applied to HTTP middleware can also be applied to service-to-service invocation calls as a middleware component using appHttpPipeline configuration. The example below adds the uppercase middleware component for all outgoing calls from the Dapr sidecar to the application that this configuration is applied to.

  1. apiVersion: dapr.io/v1alpha1
  2. kind: Configuration
  3. metadata:
  4. name: pipeline
  5. namespace: default
  6. spec:
  7. appHttpPipeline:
  8. handlers:
  9. - name: uppercase
  10. type: middleware.http.uppercase

Writing a custom middleware

Dapr uses FastHTTP to implement its HTTP server. Hence, your HTTP middleware needs to be written as a FastHTTP handler. Your middleware needs to implement a middleware interface, which defines a GetHandler method that returns fasthttp.RequestHandler and error:

  1. type Middleware interface {
  2. GetHandler(metadata Metadata) (func(h fasthttp.RequestHandler) fasthttp.RequestHandler, error)
  3. }

Your handler implementation can include any inbound logic, outbound logic, or both:

  1. func (m *customMiddleware) GetHandler(metadata Metadata) (func(fasthttp.RequestHandler) fasthttp.RequestHandler, error) {
  2. var err error
  3. return func(h fasthttp.RequestHandler) fasthttp.RequestHandler {
  4. return func(ctx *fasthttp.RequestCtx) {
  5. // inbound logic
  6. h(ctx) // call the downstream handler
  7. // outbound logic
  8. }
  9. }, err
  10. }

Last modified October 11, 2022: Remove outdated comment on creating a middleware (#2880) (99adf229)