# Table of Contents - [Echo](#echo) - [Echo](#echo) - [Echo](#echo) - [Guide | Echo](#guide-echo) - [Echo](#echo) - [Echo](#echo) - [Echo](#echo) - [CORS | Echo](#cors-echo) - [CRUD | Echo](#crud-echo) - [File Download | Echo](#file-download-echo) - [Embed Resources | Echo](#embed-resources-echo) - [File Upload | Echo](#file-upload-echo) - [Google App Engine | Echo](#google-app-engine-echo) - [Graceful Shutdown | Echo](#graceful-shutdown-echo) - [Hello World | Echo](#hello-world-echo) - [HTTP/2 Server | Echo](#http-2-server-echo) - [HTTP/2 Server Push | Echo](#http-2-server-push-echo) - [JSONP | Echo](#jsonp-echo) - [Cookies | Echo](#cookies-echo) - [Customization | Echo](#customization-echo) - [JWT | Echo](#jwt-echo) - [Load Balancing | Echo](#load-balancing-echo) - [IP Address | Echo](#ip-address-echo) - [Error Handling | Echo](#error-handling-echo) - [Middleware | Echo](#middleware-echo) - [Reverse Proxy | Echo](#reverse-proxy-echo) - [Server-Sent-Events (SSE) | Echo](#server-sent-events-sse-echo) - [Streaming Response | Echo](#streaming-response-echo) - [Subdomain | Echo](#subdomain-echo) - [WebSocket | Echo](#websocket-echo) - [Timeout | Echo](#timeout-echo) - [Twitter Like API | Echo](#twitter-like-api-echo) - [Request | Echo](#request-echo) - [Quick Start | Echo](#quick-start-echo) - [Routing | Echo](#routing-echo) - [Body Limit | Echo](#body-limit-echo) - [Body Dump | Echo](#body-dump-echo) - [Static Files | Echo](#static-files-echo) - [Basic Auth | Echo](#basic-auth-echo) - [Start Server | Echo](#start-server-echo) - [Templates | Echo](#templates-echo) - [Context Timeout | Echo](#context-timeout-echo) - [Response | Echo](#response-echo) - [Testing | Echo](#testing-echo) - [Casbin Auth | Echo](#casbin-auth-echo) - [CORS | Echo](#cors-echo) - [Decompress | Echo](#decompress-echo) - [CSRF | Echo](#csrf-echo) - [Gzip | Echo](#gzip-echo) - [Method Override | Echo](#method-override-echo) - [Key Auth | Echo](#key-auth-echo) - [Recover | Echo](#recover-echo) - [Jaeger | Echo](#jaeger-echo) - [JWT | Echo](#jwt-echo) - [Rate Limiter | Echo](#rate-limiter-echo) - [Proxy | Echo](#proxy-echo) - [Redirect | Echo](#redirect-echo) - [Secure | Echo](#secure-echo) - [Request ID | Echo](#request-id-echo) - [Logger | Echo](#logger-echo) - [Trailing Slash | Echo](#trailing-slash-echo) - [Prometheus | Echo](#prometheus-echo) - [Rewrite | Echo](#rewrite-echo) - [Static | Echo](#static-echo) - [Session | Echo](#session-echo) --- # Echo [Skip to main content](https://echo.labstack.com/docs#__docusaurus_skipToContent_fallback) On this page ![LabStack](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAACZCAYAAACoujFIAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAEVFJREFUeNrsXcGS1DgSFRV9p4cPGIo7MVsEJ064z3ug5guo/oItPoBoE3wAxZkD7i+gOMyZ6stypHt/YMx+QfXsjQiiV2lSPSpjSWlbsiVZGeGYCWiqy9ZzZr7Mp9Sdm5sb5tpev369ePny5SVLFox9/vx5zf+T86vk1/rJkyc7F7/njksAcuBl/D8Fv+7z6wJuJAHRe+DBmm349Y/aX50jEPfeA5ADb47Ae9rw12/hzeJA3Kfl9gp4cwTeM82PXcPacRBuvAQgB94xuu1/GX70GkG4SUs/OvBgzdZ43SX+sytbYdkaADn48pY3AfaVXysOxF2CwijgW6LXu9/xI3qH5d4A5MDrexMM80MAYplgMVi4VaVIba1XWO4MQGC2CLynFp/NK/jMlB86DbeUFKmLdQrLrQGIeR4A77mj53SNbLlIkLEKvhWu213Hv+ocPWJpFYAIvLbJau83KuWHvYGXseayiksDJ7LhIMytAJCDb4Wu+/4Iz/AjAjHlh+3zvNxhpCKTTF1Y1gIQC8m55Tyv8xuV8kMy+LpUJJw7kaaw3AhALCSP/fao3qg85YdK4NmoSAwalg8AKOV5Z54/6wsEYsoP/2a3Ww8iFdWJLDkQq5bsrPaXIYCP4YMu8IVJ9sN2AX3PvTIEY943NGtq68pTmUZNPEz93DGj1lp4PiMJQeY7RN3IGhFBj3gcK2PGkkpVkdDV2UYqvWjTJRUTNrFgl5XzNnaOOV+p+a5CvwYvTFQdlYbWGanONmDxWUkY+XfURqo77MPV6mb5m/aHHLXdyG5bpyGsaQ6jCtWSUuVMs8jaOltHtYtz4IH9879sDgAEF1h1HTgQdwYgDkXzjSoZLBVR8p0ghbAtvdcFArE0eFHwmC5bqBv0zHsT8PC73ALwINRxIJaGsOyKLRu9Vo/ff46fvfcceBnrXvx/ZQJAz8/v/HsReHVvfFEH4C2SOQhzgze0ybhInQ4LHthbISyGShsij6/INrcED5v3jGZk4QEHX9PvawTgwY1wIG4NQFTlYDYJhu0c1CshrLQByGaORgnLXfND42dLwNN5XC0AD36ZLiwjSPKWN0IhGK5Z+KhCBwyHBXObU1PCMjU/1JZUFHme7jNJABT2FvPDvQEwpjBC8j61soprG7RsM0LBmBqWVd6K9O8VeR6zBcBbkkAo22Ts50IoqSwyYifGudCBUFYZoqxlDJ1SfsioJRVNnmcVgAeumFC2EV+oIBCMob3CoGUbS0n/oKyVahx4XXP0zgA8KG3owrLJRlBaU83K/mUOvLGK+KRoRvVumnDbh7n3BiC5bOOorDLEInUq21gsqwzi8esiAQL4cgtOwwoAD8iFKSxL4NuxMPRrYNApWrZhyxyAGzZ+D518fxyACyLwbDqNi5nFm4Av9OnO9j87fs0JP5/j2+e7fe1SquELCt7hBP+9z/d2SgEf5Hn8AqfxwWbEsukB6/aIe0OjWx95w1MvVvzu3bvfHj58+BeBVQ5ZUiKnTZRdawi+wlEqYdUD1o2kVoYF5tccmdm1J4vzCr6ToSedf/v27d/8fy9xE5DOG0LImiNp84FczangQ3OWx7r0gCf1fJCH5mNCITsfKXdq3Y/+5Zdf2OPHjw9yYFOXwJEYgGLKnWkED+gKIxdDAxAefMYMrb0RaoKUfjR8p0IGTg2ArRZ6QLEoqX2GtbzlH7+yfEgAHo3gaWAB/+RgVLb2EAjLAfYlU4DX1ivDS5MBC9aFOai/8Z/ZOvT4JGForZY3OCmcsfEMHnrJgbjW5Ic7fgEITy2zSXjQJ/yzVwbwgZcqOwAEvNoZB1iJIVcFwj2y5QcWF7/KYfnnzgngW+P9jVarPGLjGizUGw5CWGilIhvJQNFxBqFspHkzFvvRVWmKg1Dbg8U/zyxsLH+LXs8kDLV1f0F7QNngQUANcaurIXLg5B3ZZFXv4v9+YZL58wvA/sny4lRpB7Bl7JCoPCKE5EWHigDknQ/Am+rABxIpfm0d3F/wAJTzJ8gPc2DMChDuIXQSwxYs4gtTSUWUVaCk4jgcnWHZZmkIyzkC8SMlleA/v9SRHsjzsHV2yTzbM3zE/DRYqDXkhyrpF+ZumUb6RRpmZEHR3SUsfyCG5aVCtNpm55nX/XZfASjyw/dIUnT5Ifz5Quqo7Bhh85Fhkv9g1QAOMK00Cssnc+ymwFVQisg9JFKD2hh1wK5izI8IxLLPl7K5q09RB+xaMiEpjgnA61PMv/jjV5Y1fKazOuCMhWPG/JAAPlFW8W0AkwjLO5TrdwXfumPZKJGQlvlhiaUbKvDmKP96z/wSvarC8rol8DJ+AcF44/n9RQFAOT8E6Vdm+mEkLBCWrgK4t3PMTSnAm6NSxZuyShcA+qJC6eoxoH5YEEAIXRVIzK11VY6OrHI4UctbUfZqSGWV5yxc281QSj9nfkiFuhp5EbAeuLDx4t27d88GkEm1vAbwnYUWbuv3DMKHKgSDIIBfkFM9YmGolM30nodmfi0UINxjV2Ux4osH4P2dgy7TKVVwg3csVt0zMG1+7X7KAUHBzC/IqX5nfkvJKQb38YWDcKPpqpTYVRnyxQOve4pigS0hvysiAF7VkeKgm/NrayQhMA+GX/DmvQg4PxRGUd1courG5R6Oawz7FJVKDPmdsOqeOfAadxbOsDjMFEAUUvK3gT8Eobq51LFmJCpzJCo2X7xzBF5uEAss+VUGnt/J9/wA8jx+7VVeHjzgGV8U8BBLBQghP7StWRvLhOqmMKhuCnzx+hKVCwqzxXALOZHVHWcjE4wVv0rF/YoddoUIwVUlXrelElpgmB/6vtWQypovdd6/J1ERzDYjqFQgyvzJwtkjTSYYivuFl/uLuN96Dijk8srEHfq7mB/aDlNjhGWt9+9AVMQ+24ywBwM+s2QBtc3aEoza/Taqr2eGxH2lyQ/lMBWyGb1/jag0VQiqRSDK4DMMP763BXsTDOl+AXiNbcKZwUO81yXumB/mmB9+DPxhGr0/AnGLROXF9+/f/ycx240BeMdS2yz0cEsiGPiifdLltZRekkjclQPM8c+WCNQ88AcM3n+lE8MiECvBK+UDLQ3y8YVg5KocT7xorIUcrI0YwZi4Y36YYX5YBp4fvjeVbQjAyyIpqxgJRi3PI+e1Rx0W5gxzQ+UkLNME1QDLNq3mIGL7rIgg1FYGBMP0orGO2xq6yrHaTsIK3Z4jKcsJeV4eSVmF9KJR8jwXAKwn7lSVcuhhGbz/VuMFRLiNHXjW6pe2BKkklTKG5tAZs+pFywLP8yDNWBHAt2IW65czyx7CqFLGjgoUfk9YJNKvCJittnUmESoQSFitX7qQ5AuV8sLgDXcRtfZCZbYnJmaL4HM2TWH0AZW11l4Conur9IjYOtsR/42zaQqDbkqCnqvKM0J+GJEG0VfgidZZ4cuXGnpXHIDvC8qhVGIHoUF8lYBolWDMDa2zDJlt1AAUJupqawUI95Fslhrbqp12SDB0PVuR4y2mAkDBmt8QxA5A+x8kIHZitkuNKFQumo82McuHjemySlkVlksEYirdmJktpWcLZTAoqYxeNPdpMoKx3VUr3VwlvDUyW50odOGb9N+30RyySjkzANHqlIOYma3UOruVwk+VBVNNiB20I3ul0s1p14lZgTPbhY7ZIvi8nph15PlDro48AJWy7jTOiORfJGs6y6OprMI8GUQeogdUheVlSveMwPNuEHnoAJTD8ocWGsQiEsa8IwLP20HksQBQGEmDWNvHHCIQbydIEcAnl1XSgMqBrDrywBSWa/tUQmDMbVQqwU9UmAVeypDD8rEBiL6LHapN7RSVSkQTFaoBlZArWRnYOGZYpm4Y8lDsIGp5ixYqFSithDxR4XZfsTygMmdxTMKqDHPExjqidL9jDqhk+KyVKhUMsTmLxyCvfSSrr2cNCyMmYcXQ/H+GeWIjYZF6zENP/hIqlbUCeHKIzSIBnshrLw9yQMPCxND8v2siLDXGfDXAQuhUKvDcSxb+0CI5r1USKvCAyt1sEoOMYWQvZQSdqx4zZXSZk00/HhCqQnO/VQ5IGUK0jWQkG2O0EXSCMfclKkaVSgxnfbQhVLUhTZmcAxqnh9ZGssUyO3qlYcw56zaCjqpSgc+PbRa0Tvb/04zApkK0dghRZHL5tiPoKPdL3X9RsunMglbOCDzSJe7oHWAoz7ZpYdiPMWawOBsWUP+xwagj6FaagvclLkSp8Xjw0hYsjrkx1XnHhPvVYsPUiqPOjo5l0gFlBF3jWw45HnH/xdMIgCdKKiUhvdA6JmovmDo7OgbGbFX+JZVVQh9aRN1v0iq9aCtINU4PxXC9ZeGb8P5VqGl7UDYKQvNIwu2pqU3YNb2YdfQQ5KNSI7BWI+gimwUt0ovCcL+d04tZz4XRbqeMzMQIuqUh7ykjKatQvHzv7Z029ICk6aFoReClG/D+aw34YiirUIBnTYc4s7gwlO2UaYO5vwaOYUlIL6zqEG0rouXZ0Tq5fEw95tDNOD+mxuatiiRcSfLh7TAOuonsWNjQzKjMkcAH4daJSMKLPSE1lXIyt0aq5zU4FCc29IDKlcWea7J2RlHmRD+ebc4M54skouIEeFpljjS0aDIDKqfU2hub2er2nPx0fu9UAChMaPLWiahYJximyaiN5/dODYCM/T0p1VRDTESFzmwzjTJHSP/fMA+K5j5NRjCeP5eIipbZnhr2nHg5tMjH0RzG5n8iKgcE44Vh84/XQ4t8ng1jPH+uRlSmZHuJ2SqZawhDi3wfUCmkX5AwrzXnE2+nhD4d6ERZBUsq3svBQpmOJfZsbFucT1xOLR77PAs6dAAKe8aI4lBUbIeeI1ZqbCL4vJ4FHQsAyflhLUcM7URO0sYfH8sqXQAYapfBuKe3BkQI3b7PQjSWU2pllYIFPlFhZmkEhQ/5oXFbgMezEI3lFAW7DVn6X53QLuYD5izwSQf1/bqaGqJPsxCvKeWUBluwcKX/BzMCZ7WFgZxq6Fl5rmyNXZWFBohjzkI0HjQjJkhFQtLl2deXShJSm5UXugoFShFfDKqbobsqP00JNeR3WeBroD2hfUZI3GNQoVAmYbmWf10xxZTQGvhyFsfELNKEMGMZRlKhhD47msSaHcxCFMx2YTpCNbKJWcZz7EgAbMiXPgb+cIxzECXG3KdCUHkAE7ON4ayPNulFJwDW8iUxCSv083pJk7A6VghuhzVqgBfTxKyvlPSiNwBr+dKChT+ylzQJq1YhUAkfjhlhWCOCDz5LhNtoCQbFeqlhIEyBQID9GFexDjh3IU3Cwj9vrNfBkQumXxLRxKxrfA4bU47nxAMqwtTYh77YKttoN0t1scgmZpEJxiAArOWHKxaHStlYtmkBvpzFMTGrNcFwHoJV+SGL43QfUbYBEOYqMawh3BYRMFuGBGPn4oNnLBklLJPnIEpllU+RgI+5Al8CYDsTcxDXEyirDGZDAxCYU8gdFQjLqnINADP0sso2agBGeBpnLCbql9OYDTPiManJBmC2weSANelXAuJwRlLmRA9ACYhpEtYwRlLmTA6AEhC3gWweCs1IypzJA1ACIjwkHzcPhWhGZU4CoJoxw0ObszSSrQ+ztdKznRwAG4CYSjd0ZnsyJrONCoA1xrxicaiyXRGMk5bT7xMAOwIxlvOJbTLbeUjACxaAEhB3EW0f7cxs2Q9tXhHqTRyFvgook5pPDHzQs934TC4mA8Ap2tjdixSCaVYmqCYAjhmaCxZ+6aaaIJUAGC4IQ92nIh80UyYARkBUAmHMskplEinEpCT5Hk9K9U6lkgDoPj/0QezgrUolAdA9CPcjT4b1WqWSADgsEFdsuB5zECqVBMBxGLPLHvPo+y8SAMNizLa2B3iz/yIBMCwg9p2UOllmmwBonzHPWzDmKFQqQ9mdm5ub9BSoD+vHbJglgvLAcCwH/H0iFy3s/wIMANB/BS3NqiGGAAAAAElFTkSuQmCC) Echo Project[​](https://echo.labstack.com/docs#labstack-echo-project "Direct link to labstack-echo-project") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- The Echo project is a powerful and versatile web framework for building scalable and high-performance web applications in the Go programming language. It follows the principles of simplicity, flexibility, and performance to provide developers with an efficient toolkit for building robust web applications. Key Features[​](https://echo.labstack.com/docs#key-features "Direct link to Key Features") ------------------------------------------------------------------------------------------- * **Fast and Lightweight**: Echo is designed for speed and efficiency, ensuring minimal overhead and high performance for handling HTTP requests and responses. * **Routing**: The framework offers a flexible and intuitive routing system that allows developers to define routes with parameters, query strings, and custom handlers. * **Middleware Support**: Echo provides extensive middleware support, enabling developers to easily implement cross-cutting concerns such as logging, authentication, error handling, and more. * **Context-based Request Handling**: With its context-based request handling, Echo offers easy access to request-specific data and parameters, simplifying the development of web applications. * **Powerful Template Rendering**: Echo includes a powerful template rendering engine that supports various template languages, allowing developers to generate dynamic HTML content effortlessly. * **Validation and Binding**: The framework provides robust validation and data binding capabilities, making it straightforward to validate incoming request data and bind it to Go structs. * **Extensibility**: Echo is highly extensible, with support for custom middleware, template engines, and other components, enabling developers to tailor the framework to their specific needs. * **Community and Ecosystem**: The Echo project benefits from a vibrant and active community that contributes libraries, plugins, and extensions, fostering an ecosystem of reusable components. Resources and Documentation[​](https://echo.labstack.com/docs#resources-and-documentation "Direct link to Resources and Documentation") ---------------------------------------------------------------------------------------------------------------------------------------- To learn more about the Echo project, you can refer to the following resources: * Official Website: [https://echo.labstack.com](https://echo.labstack.com/) * GitHub Repository: [https://github.com/labstack/echo](https://github.com/labstack/echo) * Documentation: [https://echo.labstack.com/docs](https://echo.labstack.com/guide) * Community Forum: [https://github.com/labstack/echo/discussions](https://github.com/labstack/echo/discussions) The Echo project offers an array of features that empower developers to build robust web applications. Its fast and lightweight nature ensures optimal performance, while the flexible routing system and middleware support streamline development processes. Developers can leverage the context-based request handling, powerful template rendering, and validation capabilities to create dynamic and secure web applications. Additionally, the extensibility of Echo allows developers to customize and enhance the framework to suit their specific needs. Join the vibrant community of Echo developers, explore the vast ecosystem of plugins and extensions, and unleash the power of Echo for your web development needs. * [LabStack Echo Project](https://echo.labstack.com/docs#labstack-echo-project) * [Key Features](https://echo.labstack.com/docs#key-features) * [Resources and Documentation](https://echo.labstack.com/docs#resources-and-documentation) --- # Echo [Skip to main content](https://echo.labstack.com/docs/binding#__docusaurus_skipToContent_fallback) On this page Parsing request data is a crucial part of a web application. In Echo this is done with a process called _binding_. This is done with information passed by the client in the following parts of an HTTP request: * URL Path parameter * URL Query parameter * Header * Request body Echo provides different ways to perform binding, each described in the sections below. Struct Tag Binding[​](https://echo.labstack.com/docs/binding#struct-tag-binding "Direct link to Struct Tag Binding") --------------------------------------------------------------------------------------------------------------------- With struct binding you define a Go struct with tags specifying the data source and corresponding key. In your request handler you simply call `Context#Bind(i interface{})` with a pointer to your struct. The tags tell the binder everything it needs to know to load data from the request. In this example a struct type `User` tells the binder to bind the query string parameter `id` to its string field `ID`: type User struct { ID string `query:"id"`}// in the handler for /users?id=var user Usererr := c.Bind(&user); if err != nil { return c.String(http.StatusBadRequest, "bad request")} ### Data Sources[​](https://echo.labstack.com/docs/binding#data-sources "Direct link to Data Sources") Echo supports the following tags specifying data sources: * `query` - query parameter * `param` - path parameter (also called route) * `header` - header parameter * `json` - request body. Uses builtin Go [json](https://golang.org/pkg/encoding/json/) package for unmarshalling. * `xml` - request body. Uses builtin Go [xml](https://golang.org/pkg/encoding/xml/) package for unmarshalling. * `form` - form data. Values are taken from query and request body. Uses Go standard library form parsing. ### Data Types[​](https://echo.labstack.com/docs/binding#data-types "Direct link to Data Types") When decoding the request body, the following data types are supported as specified by the `Content-Type` header: * `application/json` * `application/xml` * `application/x-www-form-urlencoded` When binding path parameter, query parameter, header, or form data, tags must be explicitly set on each struct field. However, JSON and XML binding is done on the struct field name if the tag is omitted. This is according to the behaviour of [Go's json package](https://pkg.go.dev/encoding/json#Unmarshal) . For form data, Echo uses Go standard library form parsing. This parses form data from both the request URL and body if content type is not `MIMEMultipartForm`. See documentation for [non-MIMEMultipartForm](https://golang.org/pkg/net/http/#Request.ParseForm) and [MIMEMultipartForm](https://golang.org/pkg/net/http/#Request.ParseMultipartForm) ### Multiple Sources[​](https://echo.labstack.com/docs/binding#multiple-sources "Direct link to Multiple Sources") It is possible to specify multiple sources on the same field. In this case request data is bound in this order: 1. Path parameters 2. Query parameters (only for GET/DELETE methods) 3. Request body type User struct { ID string `param:"id" query:"id" form:"id" json:"id" xml:"id"`} Note that binding at each stage will overwrite data bound in a previous stage. This means if your JSON request contains the query param `name=query` and body `{"name": "body"}` then the result will be `User{Name: "body"}`. ### Direct Source[​](https://echo.labstack.com/docs/binding#direct-source "Direct link to Direct Source") It is also possible to bind data directly from a specific source: Request body: err := (&DefaultBinder{}).BindBody(c, &payload) Query parameters: err := (&DefaultBinder{}).BindQueryParams(c, &payload) Path parameters: err := (&DefaultBinder{}).BindPathParams(c, &payload) Header parameters: err := (&DefaultBinder{}).BindHeaders(c, &payload) Note that headers is not one of the included sources with `Context#Bind`. The only way to bind header data is by calling `BindHeaders` directly. ### Security[​](https://echo.labstack.com/docs/binding#security "Direct link to Security") To keep your application secure, avoid passing bound structs directly to other methods if these structs contain fields that should not be bindable. It is advisable to have a separate struct for binding and map it explicitly to your business struct. Consider what will happen if your bound struct has an Exported field `IsAdmin bool` and the request body contains `{IsAdmin: true, Name: "hacker"}`. ### Example[​](https://echo.labstack.com/docs/binding#example "Direct link to Example") In this example we define a `User` struct type with field tags to bind from `json`, `form`, or `query` request data: type UserDTO struct { Name string `json:"name" form:"name" query:"name"` Email string `json:"email" form:"email" query:"email"`}type User struct { Name string Email string IsAdmin bool} And a handler at the POST `/users` route binds request data to the struct: e.POST("/users", func(c echo.Context) (err error) { u := new(UserDTO) if err := c.Bind(u); err != nil { return c.String(http.StatusBadRequest, "bad request") } // Load into separate struct for security user := User{ Name: u.Name, Email: u.Email, IsAdmin: false // avoids exposing field that should not be bound } executeSomeBusinessLogic(user) return c.JSON(http.StatusOK, u)}) #### JSON Data[​](https://echo.labstack.com/docs/binding#json-data "Direct link to JSON Data") curl -X POST http://localhost:1323/users \ -H 'Content-Type: application/json' \ -d '{"name":"Joe","email":"joe@labstack"}' #### Form Data[​](https://echo.labstack.com/docs/binding#form-data "Direct link to Form Data") curl -X POST http://localhost:1323/users \ -d 'name=Joe' \ -d 'email=joe@labstack.com' #### Query Parameters[​](https://echo.labstack.com/docs/binding#query-parameters "Direct link to Query Parameters") curl -X GET 'http://localhost:1323/users?name=Joe&email=joe@labstack.com' Fluent Binding[​](https://echo.labstack.com/docs/binding#fluent-binding "Direct link to Fluent Binding") --------------------------------------------------------------------------------------------------------- Echo provides an interface to bind explicit data types from a specified source. It uses method chaining, also known as a [Fluent Interface](https://en.wikipedia.org/wiki/Fluent_interface) . The following methods provide a handful of methods for binding to Go data type. These binders offer a fluent syntax and can be chained to configure & execute binding, and handle errors. * `echo.QueryParamsBinder(c)` - binds query parameters (source URL) * `echo.PathParamsBinder(c)` - binds path parameters (source URL) * `echo.FormFieldBinder(c)` - binds form fields (source URL + body). See also [Request.ParseForm](https://golang.org/pkg/net/http/#Request.ParseForm) . ### Error Handling[​](https://echo.labstack.com/docs/binding#error-handling "Direct link to Error Handling") A binder is usually completed by calling `BindError()` or `BindErrors()`. If any errors have occurred, `BindError()` returns the first error encountered, while`BindErrors()` returns all bind errors. Any errors stored in the binder are also reset. With `FailFast(true)` the binder can be configured to stop binding on the first error, or with `FailFast(false)` execute the entire binder call chain. Fail fast is enabled by default and should be disabled when using `BindErrors()`. ### Example[​](https://echo.labstack.com/docs/binding#example-1 "Direct link to Example") // url = "/api/search?active=true&id=1&id=2&id=3&length=25"var opts struct { IDs []int64 Active bool}length := int64(50) // default length is 50// creates query params binder that stops binding at first errorerr := echo.QueryParamsBinder(c). Int64("length", &length). Int64s("ids", &opts.IDs). Bool("active", &opts.Active). BindError() // returns first binding error ### Supported Data Types[​](https://echo.labstack.com/docs/binding#supported-data-types "Direct link to Supported Data Types") | Data Type | Notes | | --- | --- | | `bool` | | | `float32` | | | `float64` | | | `int` | | | `int8` | | | `int16` | | | `int32` | | | `int64` | | | `uint` | | | `uint8/byte` | Does not support `bytes()`. Use `BindUnmarshaler`/`CustomFunc` to convert value from base64 etc to `[]byte{}`. | | `uint16` | | | `uint32` | | | `uint64` | | | `string` | | | `time` | | | `duration` | | | `BindUnmarshaler()` | binds to a type implementing BindUnmarshaler interface | | `TextUnmarshaler()` | binds to a type implementing encoding.TextUnmarshaler interface | | `JsonUnmarshaler()` | binds to a type implementing json.Unmarshaler interface | | `UnixTime()` | converts Unix time (integer) to `time.Time` | | `UnixTimeMilli()` | converts Unix time with millisecond precision (integer) to `time.Time` | | `UnixTimeNano()` | converts Unix time with nanosecond precision (integer) to `time.Time` | | `CustomFunc()` | callback function for your custom conversion logic | Each supported type has the following methods: * `("param", &destination)` - if parameter value exists then binds it to given destination of that type i.e `Int64(...)`. * `Must("param", &destination)` - parameter value is required to exist, binds it to given destination of that type i.e `MustInt64(...)`. * `s("param", &destination)` - (for slices) if parameter values exists then binds it to given destination of that type i.e `Int64s(...)`. * `Musts("param", &destination)` - (for slices) parameter value is required to exist, binds it to given destination of that type i.e `MustInt64s(...)`. For certain slice types `BindWithDelimiter("param", &dest, ",")` supports splitting parameter values before type conversion is done. For example binding an integer slice from the URL `/api/search?id=1,2,3&id=1` will result in `[]int64{1,2,3,1}`. Custom Binding[​](https://echo.labstack.com/docs/binding#custom-binding "Direct link to Custom Binding") --------------------------------------------------------------------------------------------------------- A custom binder can be registered using `Echo#Binder`. type CustomBinder struct {}func (cb *CustomBinder) Bind(i interface{}, c echo.Context) (err error) { // You may use default binder db := new(echo.DefaultBinder) if err := db.Bind(i, c); err != echo.ErrUnsupportedMediaType { return } // Define your custom implementation here return} * [Struct Tag Binding](https://echo.labstack.com/docs/binding#struct-tag-binding) * [Data Sources](https://echo.labstack.com/docs/binding#data-sources) * [Data Types](https://echo.labstack.com/docs/binding#data-types) * [Multiple Sources](https://echo.labstack.com/docs/binding#multiple-sources) * [Direct Source](https://echo.labstack.com/docs/binding#direct-source) * [Security](https://echo.labstack.com/docs/binding#security) * [Example](https://echo.labstack.com/docs/binding#example) * [Fluent Binding](https://echo.labstack.com/docs/binding#fluent-binding) * [Error Handling](https://echo.labstack.com/docs/binding#error-handling) * [Example](https://echo.labstack.com/docs/binding#example-1) * [Supported Data Types](https://echo.labstack.com/docs/binding#supported-data-types) * [Custom Binding](https://echo.labstack.com/docs/binding#custom-binding) --- # Echo [Skip to main content](https://echo.labstack.com/docs/context#__docusaurus_skipToContent_fallback) On this page `echo.Context` represents the context of the current HTTP request. It holds request and response reference, path, path parameters, data, registered handler and APIs to read request and write response. As Context is an interface, it is easy to extend it with custom APIs. Extending[​](https://echo.labstack.com/docs/context#extending "Direct link to Extending") ------------------------------------------------------------------------------------------ **Define a custom context** type CustomContext struct { echo.Context}func (c *CustomContext) Foo() { println("foo")}func (c *CustomContext) Bar() { println("bar")} **Create a middleware to extend default context** e.Use(func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { cc := &CustomContext{c} return next(cc) }}) caution This middleware should be registered before any other middleware. caution Custom context cannot be defined in a middleware before the router ran (Pre) **Use in handler** e.GET("/", func(c echo.Context) error { cc := c.(*CustomContext) cc.Foo() cc.Bar() return cc.String(200, "OK")}) Concurrency[​](https://echo.labstack.com/docs/context#concurrency "Direct link to Concurrency") ------------------------------------------------------------------------------------------------ caution `Context` must not be accessed out of the goroutine handling the request. There are two reasons: 1. `Context` has functions that are dangerous to execute from multiple goroutines. Therefore, only one goroutine should access it. 2. Echo uses a pool to create `Context`'s. When the request handling finishes, Echo returns the `Context` to the pool. See issue [1908](https://github.com/labstack/echo/issues/1908) for a "cautionary tale" caused by this reason. Concurrency is complicated. Beware of this pitfall when working with goroutines. ### Solution[​](https://echo.labstack.com/docs/context#solution "Direct link to Solution") Use a channel func(c echo.Context) error { ca := make(chan string, 1) // To prevent this channel from blocking, size is set to 1. r := c.Request() method := r.Method go func() { // This function must not touch the Context. fmt.Printf("Method: %s\n", method) // Do some long running operations... ca <- "Hey!" }() select { case result := <-ca: return c.String(http.StatusOK, "Result: "+result) case <-c.Request().Context().Done(): // Check context. // If it reaches here, this means that context was canceled (a timeout was reached, etc.). return nil }} * [Extending](https://echo.labstack.com/docs/context#extending) * [Concurrency](https://echo.labstack.com/docs/context#concurrency) * [Solution](https://echo.labstack.com/docs/context#solution) --- # Guide | Echo [Skip to main content](https://echo.labstack.com/docs/category/guide#__docusaurus_skipToContent_fallback) [📄️ Quick Start\ ---------------\ \ Quick start](https://echo.labstack.com/docs/quick-start) [📄️ Customization\ -----------------\ \ Customization](https://echo.labstack.com/docs/customization) [📄️ Binding\ -----------\ \ Binding request data](https://echo.labstack.com/docs/binding) [📄️ Context\ -----------\ \ Context in Echo](https://echo.labstack.com/docs/context) [📄️ Cookies\ -----------\ \ Handling cookie](https://echo.labstack.com/docs/cookies) [📄️ Error Handling\ ------------------\ \ Error handling](https://echo.labstack.com/docs/error-handling) [📄️ Start Server\ ----------------\ \ Starting server](https://echo.labstack.com/docs/start-server) [📄️ IP Address\ --------------\ \ IP address](https://echo.labstack.com/docs/ip-address) [📄️ Request\ -----------\ \ Handling request](https://echo.labstack.com/docs/request) [📄️ Response\ ------------\ \ Sending response](https://echo.labstack.com/docs/response) [📄️ Routing\ -----------\ \ Routing requests](https://echo.labstack.com/docs/routing) [📄️ Static Files\ ----------------\ \ Serving static files](https://echo.labstack.com/docs/static-files) [📄️ Templates\ -------------\ \ Using templates](https://echo.labstack.com/docs/templates) [📄️ Testing\ -----------\ \ Testing handler and middleware](https://echo.labstack.com/docs/testing) --- # Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/auto-tls#__docusaurus_skipToContent_fallback) On this page This recipe demonstrates how to obtain TLS certificates for a domain automatically from Let's Encrypt. `Echo#StartAutoTLS` accepts an address which should listen on port `443`. Browse to `https://`. If everything goes fine, you should see a welcome message with TLS enabled on the website. tip * For added security you should specify host policy in auto TLS manager * Cache certificates to avoid issues with rate limits ([https://letsencrypt.org/docs/rate-limits](https://letsencrypt.org/docs/rate-limits) ) * To redirect HTTP traffic to HTTPS, you can use [redirect middleware](https://echo.labstack.com/docs/middleware/redirect#https-redirect) Server[​](https://echo.labstack.com/docs/cookbook/auto-tls#server "Direct link to Server") ------------------------------------------------------------------------------------------- cookbook/auto-tls/server.go loading... * [Server](https://echo.labstack.com/docs/cookbook/auto-tls#server) --- # Echo [Skip to main content](https://echo.labstack.com/docs/category/cookbook#__docusaurus_skipToContent_fallback) [📄️ Auto TLS\ ------------\ \ Automatic TLS certificates from Let's Encrypt recipe](https://echo.labstack.com/docs/cookbook/auto-tls) [📄️ CORS\ --------\ \ CORS recipe](https://echo.labstack.com/docs/cookbook/cors) [📄️ CRUD\ --------\ \ CRUD (Create, read, update and delete) recipe](https://echo.labstack.com/docs/cookbook/crud) [📄️ Embed Resources\ -------------------\ \ Embed resources recipe](https://echo.labstack.com/docs/cookbook/embed-resources) [📄️ File Download\ -----------------\ \ File download recipe](https://echo.labstack.com/docs/cookbook/file-download) [📄️ File Upload\ ---------------\ \ File upload recipe](https://echo.labstack.com/docs/cookbook/file-upload) [📄️ Google App Engine\ ---------------------\ \ Google App Engine recipe](https://echo.labstack.com/docs/cookbook/google-app-engine) [📄️ Graceful Shutdown\ ---------------------\ \ Graceful shutdown recipe](https://echo.labstack.com/docs/cookbook/graceful-shutdown) [📄️ Hello World\ ---------------\ \ Hello world recipe](https://echo.labstack.com/docs/cookbook/hello-world) [📄️ HTTP/2 Server Push\ ----------------------\ \ HTTP/2 server push recipe](https://echo.labstack.com/docs/cookbook/http2-server-push) [📄️ HTTP/2 Server\ -----------------\ \ HTTP/2 server recipe](https://echo.labstack.com/docs/cookbook/http2) [📄️ JSONP\ ---------\ \ JSONP recipe](https://echo.labstack.com/docs/cookbook/jsonp) [📄️ JWT\ -------\ \ JWT recipe](https://echo.labstack.com/docs/cookbook/jwt) [📄️ Load Balancing\ ------------------\ \ Load balancing recipe](https://echo.labstack.com/docs/cookbook/load-balancing) [📄️ Middleware\ --------------\ \ Middleware recipe](https://echo.labstack.com/docs/cookbook/middleware) [📄️ Reverse Proxy\ -----------------\ \ Reverse proxy recipe](https://echo.labstack.com/docs/cookbook/reverse-proxy) [📄️ Server-Sent-Events (SSE)\ ----------------------------\ \ SSE recipe](https://echo.labstack.com/docs/cookbook/sse) [📄️ Streaming Response\ ----------------------\ \ Streaming response recipe](https://echo.labstack.com/docs/cookbook/streaming-response) [📄️ Subdomain\ -------------\ \ Subdomain recipe](https://echo.labstack.com/docs/cookbook/subdomain) [📄️ Timeout\ -----------\ \ Timeout recipe](https://echo.labstack.com/docs/cookbook/timeout) [📄️ Twitter Like API\ --------------------\ \ Twitter like API recipe](https://echo.labstack.com/docs/cookbook/twitter) [📄️ WebSocket\ -------------\ \ WebSocket recipe](https://echo.labstack.com/docs/cookbook/websocket) --- # Echo [Skip to main content](https://echo.labstack.com/docs/category/middleware#__docusaurus_skipToContent_fallback) [📄️ Basic Auth\ --------------\ \ Basic auth middleware](https://echo.labstack.com/docs/middleware/basic-auth) [📄️ Body Dump\ -------------\ \ Body dump middleware](https://echo.labstack.com/docs/middleware/body-dump) [📄️ Body Limit\ --------------\ \ Body limit middleware](https://echo.labstack.com/docs/middleware/body-limit) [📄️ Casbin Auth\ ---------------\ \ Casbin auth middleware](https://echo.labstack.com/docs/middleware/casbin-auth) [📄️ Context Timeout\ -------------------\ \ Context Timeout middleware](https://echo.labstack.com/docs/middleware/context-timeout) [📄️ CORS\ --------\ \ CORS middleware](https://echo.labstack.com/docs/middleware/cors) [📄️ CSRF\ --------\ \ CSRF middleware](https://echo.labstack.com/docs/middleware/csrf) [📄️ Decompress\ --------------\ \ Decompress middleware](https://echo.labstack.com/docs/middleware/decompress) [📄️ Gzip\ --------\ \ Gzip middleware](https://echo.labstack.com/docs/middleware/gzip) [📄️ Jaeger\ ----------\ \ Jaeager tracing middleware](https://echo.labstack.com/docs/middleware/jaeger) [📄️ JWT\ -------\ \ JWT middleware](https://echo.labstack.com/docs/middleware/jwt) [📄️ Key Auth\ ------------\ \ Key auth middleware](https://echo.labstack.com/docs/middleware/key-auth) [📄️ Logger\ ----------\ \ Logger middleware](https://echo.labstack.com/docs/middleware/logger) [📄️ Method Override\ -------------------\ \ Method override middleware](https://echo.labstack.com/docs/middleware/method-override) [📄️ Prometheus\ --------------\ \ Prometheus metrics middleware](https://echo.labstack.com/docs/middleware/prometheus) [📄️ Proxy\ ---------\ \ Reverse proxy middleware](https://echo.labstack.com/docs/middleware/proxy) [📄️ Rate Limiter\ ----------------\ \ Rate limiter middleware](https://echo.labstack.com/docs/middleware/rate-limiter) [📄️ Recover\ -----------\ \ Recover middleware](https://echo.labstack.com/docs/middleware/recover) [📄️ Redirect\ ------------\ \ Redirect middleware](https://echo.labstack.com/docs/middleware/redirect) [📄️ Request ID\ --------------\ \ Request ID middleware](https://echo.labstack.com/docs/middleware/request-id) [📄️ Rewrite\ -----------\ \ Rewrite middleware](https://echo.labstack.com/docs/middleware/rewrite) [📄️ Secure\ ----------\ \ Secure middleware](https://echo.labstack.com/docs/middleware/secure) [📄️ Session\ -----------\ \ Session middleware](https://echo.labstack.com/docs/middleware/session) [📄️ Static\ ----------\ \ Static middleware](https://echo.labstack.com/docs/middleware/static) [📄️ Trailing Slash\ ------------------\ \ Trailing slash middleware](https://echo.labstack.com/docs/middleware/trailing-slash) --- # CORS | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/cors#__docusaurus_skipToContent_fallback) On this page Server using a list of allowed origins[​](https://echo.labstack.com/docs/cookbook/cors#server-using-a-list-of-allowed-origins "Direct link to Server using a list of allowed origins") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- cookbook/cors/origin-list/server.go loading... Server using a custom function to allow origins[​](https://echo.labstack.com/docs/cookbook/cors#server-using-a-custom-function-to-allow-origins "Direct link to Server using a custom function to allow origins") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ cookbook/cors/origin-func/server.go loading... * [Server using a list of allowed origins](https://echo.labstack.com/docs/cookbook/cors#server-using-a-list-of-allowed-origins) * [Server using a custom function to allow origins](https://echo.labstack.com/docs/cookbook/cors#server-using-a-custom-function-to-allow-origins) --- # CRUD | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/crud#__docusaurus_skipToContent_fallback) On this page Server[​](https://echo.labstack.com/docs/cookbook/crud#server "Direct link to Server") --------------------------------------------------------------------------------------- cookbook/crud/server.go loading... Client[​](https://echo.labstack.com/docs/cookbook/crud#client "Direct link to Client") --------------------------------------------------------------------------------------- ### Create user[​](https://echo.labstack.com/docs/cookbook/crud#create-user "Direct link to Create user") #### Request[​](https://echo.labstack.com/docs/cookbook/crud#request "Direct link to Request") curl -X POST \ -H 'Content-Type: application/json' \ -d '{"name":"Joe Smith"}' \ localhost:1323/users #### Response[​](https://echo.labstack.com/docs/cookbook/crud#response "Direct link to Response") { "id": 1, "name": "Joe Smith"} ### Get user[​](https://echo.labstack.com/docs/cookbook/crud#get-user "Direct link to Get user") #### Request[​](https://echo.labstack.com/docs/cookbook/crud#request-1 "Direct link to Request") curl localhost:1323/users/1 #### Response[​](https://echo.labstack.com/docs/cookbook/crud#response-1 "Direct link to Response") { "id": 1, "name": "Joe Smith"} ### Update user[​](https://echo.labstack.com/docs/cookbook/crud#update-user "Direct link to Update user") #### Request[​](https://echo.labstack.com/docs/cookbook/crud#request-2 "Direct link to Request") curl -X PUT \ -H 'Content-Type: application/json' \ -d '{"name":"Joe"}' \ localhost:1323/users/1 #### Response[​](https://echo.labstack.com/docs/cookbook/crud#response-2 "Direct link to Response") { "id": 1, "name": "Joe"} ### Delete user[​](https://echo.labstack.com/docs/cookbook/crud#delete-user "Direct link to Delete user") #### Request[​](https://echo.labstack.com/docs/cookbook/crud#request-3 "Direct link to Request") curl -X DELETE localhost:1323/users/1 #### Response[​](https://echo.labstack.com/docs/cookbook/crud#response-3 "Direct link to Response") `NoContent - 204` * [Server](https://echo.labstack.com/docs/cookbook/crud#server) * [Client](https://echo.labstack.com/docs/cookbook/crud#client) * [Create user](https://echo.labstack.com/docs/cookbook/crud#create-user) * [Get user](https://echo.labstack.com/docs/cookbook/crud#get-user) * [Update user](https://echo.labstack.com/docs/cookbook/crud#update-user) * [Delete user](https://echo.labstack.com/docs/cookbook/crud#delete-user) --- # File Download | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/file-download#__docusaurus_skipToContent_fallback) On this page Download file[​](https://echo.labstack.com/docs/cookbook/file-download#download-file "Direct link to Download file") --------------------------------------------------------------------------------------------------------------------- ### Server[​](https://echo.labstack.com/docs/cookbook/file-download#server "Direct link to Server") cookbook/file-download/server.go loading... ### Client[​](https://echo.labstack.com/docs/cookbook/file-download#client "Direct link to Client") cookbook/file-download/index.html loading... Download file as inline[​](https://echo.labstack.com/docs/cookbook/file-download#download-file-as-inline "Direct link to Download file as inline") --------------------------------------------------------------------------------------------------------------------------------------------------- ### Server[​](https://echo.labstack.com/docs/cookbook/file-download#server-1 "Direct link to Server") cookbook/file-download/inline/server.go loading... ### Client[​](https://echo.labstack.com/docs/cookbook/file-download#client-1 "Direct link to Client") cookbook/file-download/inline/index.html loading... Download file as attachment[​](https://echo.labstack.com/docs/cookbook/file-download#download-file-as-attachment "Direct link to Download file as attachment") --------------------------------------------------------------------------------------------------------------------------------------------------------------- ### Server[​](https://echo.labstack.com/docs/cookbook/file-download#server-2 "Direct link to Server") cookbook/file-download/attachment/server.go loading... ### Client[​](https://echo.labstack.com/docs/cookbook/file-download#client-2 "Direct link to Client") cookbook/file-download/attachment/index.html loading... * [Download file](https://echo.labstack.com/docs/cookbook/file-download#download-file) * [Server](https://echo.labstack.com/docs/cookbook/file-download#server) * [Client](https://echo.labstack.com/docs/cookbook/file-download#client) * [Download file as inline](https://echo.labstack.com/docs/cookbook/file-download#download-file-as-inline) * [Server](https://echo.labstack.com/docs/cookbook/file-download#server-1) * [Client](https://echo.labstack.com/docs/cookbook/file-download#client-1) * [Download file as attachment](https://echo.labstack.com/docs/cookbook/file-download#download-file-as-attachment) * [Server](https://echo.labstack.com/docs/cookbook/file-download#server-2) * [Client](https://echo.labstack.com/docs/cookbook/file-download#client-2) --- # Embed Resources | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/embed-resources#__docusaurus_skipToContent_fallback) On this page With go 1.16 embed feature[​](https://echo.labstack.com/docs/cookbook/embed-resources#with-go-116-embed-feature "Direct link to With go 1.16 embed feature") ------------------------------------------------------------------------------------------------------------------------------------------------------------- cookbook/embed/server.go loading... With go.rice[​](https://echo.labstack.com/docs/cookbook/embed-resources#with-gorice "Direct link to With go.rice") ------------------------------------------------------------------------------------------------------------------- cookbook/embed-resources/server.go loading... * [With go 1.16 embed feature](https://echo.labstack.com/docs/cookbook/embed-resources#with-go-116-embed-feature) * [With go.rice](https://echo.labstack.com/docs/cookbook/embed-resources#with-gorice) --- # File Upload | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/file-upload#__docusaurus_skipToContent_fallback) On this page Upload single file with parameters[​](https://echo.labstack.com/docs/cookbook/file-upload#upload-single-file-with-parameters "Direct link to Upload single file with parameters") ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### Server[​](https://echo.labstack.com/docs/cookbook/file-upload#server "Direct link to Server") cookbook/file-upload/single/server.go loading... ### Client[​](https://echo.labstack.com/docs/cookbook/file-upload#client "Direct link to Client") cookbook/file-upload/single/public/index.html loading... Upload multiple files with parameters[​](https://echo.labstack.com/docs/cookbook/file-upload#upload-multiple-files-with-parameters "Direct link to Upload multiple files with parameters") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### Server[​](https://echo.labstack.com/docs/cookbook/file-upload#server-1 "Direct link to Server") cookbook/file-upload/multiple/server.go loading... ### Client[​](https://echo.labstack.com/docs/cookbook/file-upload#client-1 "Direct link to Client") cookbook/file-upload/multiple/public/index.html loading... * [Upload single file with parameters](https://echo.labstack.com/docs/cookbook/file-upload#upload-single-file-with-parameters) * [Server](https://echo.labstack.com/docs/cookbook/file-upload#server) * [Client](https://echo.labstack.com/docs/cookbook/file-upload#client) * [Upload multiple files with parameters](https://echo.labstack.com/docs/cookbook/file-upload#upload-multiple-files-with-parameters) * [Server](https://echo.labstack.com/docs/cookbook/file-upload#server-1) * [Client](https://echo.labstack.com/docs/cookbook/file-upload#client-1) --- # Google App Engine | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/google-app-engine#__docusaurus_skipToContent_fallback) On this page Google App Engine (GAE) provides a range of hosting options from pure PaaS (App Engine Classic) through Managed VMs to fully self-managed or container-driven Compute Engine instances. Echo works great with all of these but requires a few changes to the usual examples to run on the AppEngine Classic and Managed VM options. With a small amount of effort though it's possible to produce a codebase that will run on these and also non-managed platforms automatically. We'll walk through the changes needed to support each option. Standalone[​](https://echo.labstack.com/docs/cookbook/google-app-engine#standalone "Direct link to Standalone") ---------------------------------------------------------------------------------------------------------------- Wait? What? I thought this was about AppEngine! Bear with me - the easiest way to show the changes required is to start with a setup for standalone and work from there plus there's no reason we wouldn't want to retain the ability to run our app anywhere, right? We take advantage of the go [build constraints or tags](https://golang.org/pkg/go/build/) to change how we create and run the Echo server for each platform while keeping the rest of the application (e.g. handler wireup) the same across all of them. First, we have the normal setup based on the examples but we split it into two files - `app.go` will be common to all variations and holds the Echo instance variable. We initialise it from a function and because it is a `var` this will happen _before_ any `init()` functions run - a feature that we'll use to connect our handlers later. cookbook/google-app-engine/app.go loading... A separate source file contains the function to create the Echo instance and add the static file handlers and middleware. Note the build tag on the first line which says to use this when _not_ building with appengine or appenginevm tags (which those platforms automatically add for us). We also have the `main()` function to start serving our app as normal. This should all be very familiar. cookbook/google-app-engine/app-standalone.go loading... The handler-wireup that would normally also be a part of this Echo setup moves to separate files which take advantage of the ability to have multiple `init()` functions which run _after_ the `e` Echo var is initialized but _before_ the `main()` function is executed. These allow additional handlers to attach themselves to the instance - I've found the `Group` feature naturally fits into this pattern with a file per REST endpoint, often with a higher-level `api` group created that they attach to instead of the root Echo instance directly (so things like CORS middleware can be added at this higher common-level). cookbook/google-app-engine/users.go loading... If we run our app it should execute as it did before when everything was in one file although we have at least gained the ability to organize our handlers a little more cleanly. AppEngine Classic and Managed VM(s)[​](https://echo.labstack.com/docs/cookbook/google-app-engine#appengine-classic-and-managed-vms "Direct link to AppEngine Classic and Managed VM(s)") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- So far we've seen how to split apart the Echo creation and setup but still have the same app that still only runs standalone. Now we'll see how those changes allow us to add support for AppEngine hosting. Refer to the [AppEngine site](https://cloud.google.com/appengine/docs/go/) for full configuration and deployment information. ### Configuration file[​](https://echo.labstack.com/docs/cookbook/google-app-engine#configuration-file "Direct link to Configuration file") Both of these are Platform as as Service options running on either sandboxed micro-containers or managed Compute Engine instances. Both require an `app.yaml` file to describe the app to the service. While the app _could_ still serve all it's static files itself, one of the benefits of the platform is having Google's infrastructure handle that for us so it can be offloaded and the app only has to deal with dynamic requests. The platform also handles logging and http gzip compression so these can be removed from the codebase as well. The yaml file also contains other options to control instance size and auto-scaling so for true deployment freedom you would likely have separate `app-classic.yaml` and `app-vm.yaml` files and this can help when making the transition from AppEngine Classic to Managed VMs. cookbook/google-app-engine/app-engine.yaml loading... ### Router configuration[​](https://echo.labstack.com/docs/cookbook/google-app-engine#router-configuration "Direct link to Router configuration") We'll now use the [build constraints](https://golang.org/pkg/go/build/) again like we did when creating our `app-standalone.go` instance but this time with the opposite tags to use this file _if_ the build has the appengine or appenginevm tags (added automatically when deploying to these platforms). This allows us to replace the `createMux()` function to create our Echo server _without_ any of the static file handling and logging + gzip middleware which is no longer required. Also worth nothing is that GAE classic provides a wrapper to handle serving the app so instead of a `main()` function where we run the server, we instead wire up the router to the default `http.Handler` instead. cookbook/google-app-engine/app-engine.go loading... Managed VMs are slightly different. They are expected to respond to requests on port 8080 as well as special health-check requests used by the service to detect if an instance is still running in order to provide automated failover and instance replacement. The `google.golang.org/appengine` package provides this for us so we have a slightly different version for Managed VMs: cookbook/google-app-engine/app-managed.go loading... So now we have three different configurations. We can build and run our app as normal so it can be executed locally, on a full Compute Engine instance or any other traditional hosting provider (including EC2, Docker etc...). This build will ignore the code in appengine and appenginevm tagged files and the `app.yaml` file is meaningless to anything other than the AppEngine platform. We can also run locally using the [Google AppEngine SDK for Go](https://cloud.google.com/appengine/downloads) either emulating [AppEngine Classic](https://cloud.google.com/appengine/docs/go/tools/devserver) : goapp serve Or [Managed VM(s)](https://cloud.google.com/appengine/docs/managed-vms/sdk#run-local) : gcloud config set project \[your project id\] gcloud preview app run . And of course we can deploy our app to both of these platforms for easy and inexpensive auto-scaling joy. Depending on what your app actually does it's possible you may need to make other changes to allow switching between AppEngine provided service such as Datastore and alternative storage implementations such as MongoDB. A combination of go interfaces and build constraints can make this fairly straightforward but is outside the scope of this example. * [Standalone](https://echo.labstack.com/docs/cookbook/google-app-engine#standalone) * [AppEngine Classic and Managed VM(s)](https://echo.labstack.com/docs/cookbook/google-app-engine#appengine-classic-and-managed-vms) * [Configuration file](https://echo.labstack.com/docs/cookbook/google-app-engine#configuration-file) * [Router configuration](https://echo.labstack.com/docs/cookbook/google-app-engine#router-configuration) --- # Graceful Shutdown | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/graceful-shutdown#__docusaurus_skipToContent_fallback) On this page Using [http.Server#Shutdown()](https://golang.org/pkg/net/http/#Server.Shutdown) [​](https://echo.labstack.com/docs/cookbook/graceful-shutdown#using-httpservershutdown "Direct link to using-httpservershutdown") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- cookbook/graceful-shutdown/server.go loading... note Requires go1.16+ * [Using http.Server#Shutdown()](https://echo.labstack.com/docs/cookbook/graceful-shutdown#using-httpservershutdown) --- # Hello World | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/hello-world#__docusaurus_skipToContent_fallback) On this page Server[​](https://echo.labstack.com/docs/cookbook/hello-world#server "Direct link to Server") ---------------------------------------------------------------------------------------------- cookbook/hello-world/server.go loading... * [Server](https://echo.labstack.com/docs/cookbook/hello-world#server) --- # HTTP/2 Server | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/http2#__docusaurus_skipToContent_fallback) On this page 1) Generate a self-signed X.509 TLS certificate[​](https://echo.labstack.com/docs/cookbook/http2#1-generate-a-self-signed-x509-tls-certificate "Direct link to 1) Generate a self-signed X.509 TLS certificate") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Run the following command to generate `cert.pem` and `key.pem` files: go run $GOROOT/src/crypto/tls/generate_cert.go --host localhost note For demo purpose, we are using a self-signed certificate. Ideally, you should obtain a certificate from [CA](https://en.wikipedia.org/wiki/Certificate_authority) . 2) Create a handler which simply outputs the request information to the client[​](https://echo.labstack.com/docs/cookbook/http2#2-create-a-handler-which-simply-outputs-the-request-information-to-the-client "Direct link to 2) Create a handler which simply outputs the request information to the client") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- e.GET("/request", func(c echo.Context) error { req := c.Request() format := ` Protocol: %s
Host: %s
Remote Address: %s
Method: %s
Path: %s
` return c.HTML(http.StatusOK, fmt.Sprintf(format, req.Proto, req.Host, req.RemoteAddr, req.Method, req.URL.Path))}) 3) Start TLS server using cert.pem and key.pem[​](https://echo.labstack.com/docs/cookbook/http2#3-start-tls-server-using-certpem-and-keypem "Direct link to 3) Start TLS server using cert.pem and key.pem") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- if err := e.StartTLS(":1323", "cert.pem", "key.pem"); err != http.ErrServerClosed { log.Fatal(err)} or use customized HTTP server with your own TLSConfig s := http.Server{ Addr: ":8443", Handler: e, // set Echo as handler TLSConfig: &tls.Config{ //Certificates: nil, // <-- s.ListenAndServeTLS will populate this field }, //ReadTimeout: 30 * time.Second, // use custom timeouts}if err := s.ListenAndServeTLS("cert.pem", "key.pem"); err != http.ErrServerClosed { log.Fatal(err)} 4) Start the server and browse to [https://localhost:1323/request](https://localhost:1323/request) to see the following output[​](https://echo.labstack.com/docs/cookbook/http2#4-start-the-server-and-browse-to-httpslocalhost1323request-to-see-the-following-output "Direct link to 4-start-the-server-and-browse-to-httpslocalhost1323request-to-see-the-following-output") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Protocol: HTTP/2.0Host: localhost:1323Remote Address: [::1]:60288Method: GETPath: / Source Code[​](https://echo.labstack.com/docs/cookbook/http2#source-code "Direct link to Source Code") ------------------------------------------------------------------------------------------------------- cookbook/http2/server.go loading... * [1) Generate a self-signed X.509 TLS certificate](https://echo.labstack.com/docs/cookbook/http2#1-generate-a-self-signed-x509-tls-certificate) * [2) Create a handler which simply outputs the request information to the client](https://echo.labstack.com/docs/cookbook/http2#2-create-a-handler-which-simply-outputs-the-request-information-to-the-client) * [3) Start TLS server using cert.pem and key.pem](https://echo.labstack.com/docs/cookbook/http2#3-start-tls-server-using-certpem-and-keypem) * [4) Start the server and browse to https://localhost:1323/request to see the following output](https://echo.labstack.com/docs/cookbook/http2#4-start-the-server-and-browse-to-httpslocalhost1323request-to-see-the-following-output) * [Source Code](https://echo.labstack.com/docs/cookbook/http2#source-code) --- # HTTP/2 Server Push | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/http2-server-push#__docusaurus_skipToContent_fallback) On this page note Requires go1.8+ Send web assets using HTTP/2 server push[​](https://echo.labstack.com/docs/cookbook/http2-server-push#send-web-assets-using-http2-server-push "Direct link to Send web assets using HTTP/2 server push") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### [Generate a self-signed X.509 TLS certificate](https://echo.labstack.com/docs/cookbook/http2#step-1-generate-a-self-signed-x-509-tls-certificate) [​](https://echo.labstack.com/docs/cookbook/http2-server-push#generate-a-self-signed-x509-tls-certificate "Direct link to generate-a-self-signed-x509-tls-certificate") ### 1) Register a route to serve web assets[​](https://echo.labstack.com/docs/cookbook/http2-server-push#1-register-a-route-to-serve-web-assets "Direct link to 1) Register a route to serve web assets") e.Static("/", "static") ### 2) Create a handler to serve index.html and push it's dependencies[​](https://echo.labstack.com/docs/cookbook/http2-server-push#2-create-a-handler-to-serve-indexhtml-and-push-its-dependencies "Direct link to 2) Create a handler to serve index.html and push it's dependencies") e.GET("/", func(c echo.Context) (err error) { pusher, ok := c.Response().Writer.(http.Pusher) if ok { if err = pusher.Push("/app.css", nil); err != nil { return } if err = pusher.Push("/app.js", nil); err != nil { return } if err = pusher.Push("/echo.png", nil); err != nil { return } } return c.File("index.html")}) info If `http.Pusher` is supported, web assets are pushed; otherwise, client makes separate requests to get them. ### 3) Start TLS server using cert.pem and key.pem[​](https://echo.labstack.com/docs/cookbook/http2-server-push#3-start-tls-server-using-certpem-and-keypem "Direct link to 3) Start TLS server using cert.pem and key.pem") if err := e.StartTLS(":1323", "cert.pem", "key.pem"); err != http.ErrServerClosed { log.Fatal(err)} or use customized HTTP server with your own TLSConfig s := http.Server{ Addr: ":8443", Handler: e, // set Echo as handler TLSConfig: &tls.Config{ //Certificates: nil, // <-- s.ListenAndServeTLS will populate this field }, //ReadTimeout: 30 * time.Second, // use custom timeouts}if err := s.ListenAndServeTLS("cert.pem", "key.pem"); err != http.ErrServerClosed { log.Fatal(err)} ### 4) Start the server and browse to [https://localhost:1323](https://localhost:1323/) [​](https://echo.labstack.com/docs/cookbook/http2-server-push#4-start-the-server-and-browse-to-httpslocalhost1323 "Direct link to 4-start-the-server-and-browse-to-httpslocalhost1323") Protocol: HTTP/2.0Host: localhost:1323Remote Address: [::1]:60288Method: GETPath: / Source Code[​](https://echo.labstack.com/docs/cookbook/http2-server-push#source-code "Direct link to Source Code") ------------------------------------------------------------------------------------------------------------------- cookbook/http2-server-push/index.html loading... cookbook/http2-server-push/server.go loading... * [Send web assets using HTTP/2 server push](https://echo.labstack.com/docs/cookbook/http2-server-push#send-web-assets-using-http2-server-push) * [Generate a self-signed X.509 TLS certificate](https://echo.labstack.com/docs/cookbook/http2-server-push#generate-a-self-signed-x509-tls-certificate) * [1) Register a route to serve web assets](https://echo.labstack.com/docs/cookbook/http2-server-push#1-register-a-route-to-serve-web-assets) * [2) Create a handler to serve index.html and push it's dependencies](https://echo.labstack.com/docs/cookbook/http2-server-push#2-create-a-handler-to-serve-indexhtml-and-push-its-dependencies) * [3) Start TLS server using cert.pem and key.pem](https://echo.labstack.com/docs/cookbook/http2-server-push#3-start-tls-server-using-certpem-and-keypem) * [4) Start the server and browse to https://localhost:1323](https://echo.labstack.com/docs/cookbook/http2-server-push#4-start-the-server-and-browse-to-httpslocalhost1323) * [Source Code](https://echo.labstack.com/docs/cookbook/http2-server-push#source-code) --- # JSONP | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/jsonp#__docusaurus_skipToContent_fallback) On this page JSONP is a method that allows cross-domain server calls. You can read more about it at the JSON versus JSONP Tutorial. Server[​](https://echo.labstack.com/docs/cookbook/jsonp#server "Direct link to Server") ---------------------------------------------------------------------------------------- cookbook/jsonp/server.go loading... Client[​](https://echo.labstack.com/docs/cookbook/jsonp#client "Direct link to Client") ---------------------------------------------------------------------------------------- cookbook/jsonp/public/index.html loading... * [Server](https://echo.labstack.com/docs/cookbook/jsonp#server) * [Client](https://echo.labstack.com/docs/cookbook/jsonp#client) --- # Cookies | Echo [Skip to main content](https://echo.labstack.com/docs/cookies#__docusaurus_skipToContent_fallback) On this page Cookie is a small piece of data sent from a website server and stored in the user's web browser while browsing. Every time the user loads the website, the browser sends the cookies back to the server to notify the server of user's latest activity. Cookies were designed to be a reliable mechanism for websites to remember stateful information (e.g. items added to the shopping cart in an online store) or to record the user's browsing activity (such as clicking particular buttons, logging in, or user previously visited pages of the website). Cookies can also store form content a user has previously entered, such as username, gender, age, address, etc. Cookie Attributes[​](https://echo.labstack.com/docs/cookies#cookie-attributes "Direct link to Cookie Attributes") ------------------------------------------------------------------------------------------------------------------ | Attribute | Optional | | --- | --- | | `Name` | No | | `Value` | No | | `Path` | Yes | | `Domain` | Yes | | `Expires` | Yes | | `Secure` | Yes | | `HttpOnly` | Yes | Echo uses go standard `http.Cookie` object to add/retrieve cookies from the context received in the handler function. Create a Cookie[​](https://echo.labstack.com/docs/cookies#create-a-cookie "Direct link to Create a Cookie") ------------------------------------------------------------------------------------------------------------ func writeCookie(c echo.Context) error { cookie := new(http.Cookie) cookie.Name = "username" cookie.Value = "jon" cookie.Expires = time.Now().Add(24 * time.Hour) c.SetCookie(cookie) return c.String(http.StatusOK, "write a cookie")} * Cookie is created using `new(http.Cookie)`. * Attributes for the cookie are set assigning to the `http.Cookie` instance public attributes. * Finally `c.SetCookie(cookie)` adds a `Set-Cookie` header in HTTP response. Read a Cookie[​](https://echo.labstack.com/docs/cookies#read-a-cookie "Direct link to Read a Cookie") ------------------------------------------------------------------------------------------------------ func readCookie(c echo.Context) error { cookie, err := c.Cookie("username") if err != nil { return err } fmt.Println(cookie.Name) fmt.Println(cookie.Value) return c.String(http.StatusOK, "read a cookie")} * Cookie is read by name using `c.Cookie("username")` from the HTTP request. * Cookie attributes are accessed using `Getter` function. Read all the Cookies[​](https://echo.labstack.com/docs/cookies#read-all-the-cookies "Direct link to Read all the Cookies") --------------------------------------------------------------------------------------------------------------------------- func readAllCookies(c echo.Context) error { for _, cookie := range c.Cookies() { fmt.Println(cookie.Name) fmt.Println(cookie.Value) } return c.String(http.StatusOK, "read all the cookies")} * [Cookie Attributes](https://echo.labstack.com/docs/cookies#cookie-attributes) * [Create a Cookie](https://echo.labstack.com/docs/cookies#create-a-cookie) * [Read a Cookie](https://echo.labstack.com/docs/cookies#read-a-cookie) * [Read all the Cookies](https://echo.labstack.com/docs/cookies#read-all-the-cookies) --- # Customization | Echo [Skip to main content](https://echo.labstack.com/docs/customization#__docusaurus_skipToContent_fallback) On this page Debug[​](https://echo.labstack.com/docs/customization#debug "Direct link to Debug") ------------------------------------------------------------------------------------ `Echo#Debug` can be used to enable / disable debug mode. Debug mode sets the log level to `DEBUG`. Logging[​](https://echo.labstack.com/docs/customization#logging "Direct link to Logging") ------------------------------------------------------------------------------------------ The default format for logging is JSON, which can be changed by modifying the header. ### Log Header[​](https://echo.labstack.com/docs/customization#log-header "Direct link to Log Header") `Echo#Logger.SetHeader(string)` can be used to set the header for the logger. Default value: {"time":"${time_rfc3339_nano}","level":"${level}","prefix":"${prefix}","file":"${short_file}","line":"${line}"} _Example_ import "github.com/labstack/gommon/log"/* ... */if l, ok := e.Logger.(*log.Logger); ok { l.SetHeader("${time_rfc3339} ${level}")} 2018-05-08T20:30:06-07:00 INFO info #### Available Tags[​](https://echo.labstack.com/docs/customization#available-tags "Direct link to Available Tags") * `time_rfc3339` * `time_rfc3339_nano` * `level` * `prefix` * `long_file` * `short_file` * `line` ### Log Output[​](https://echo.labstack.com/docs/customization#log-output "Direct link to Log Output") `Echo#Logger.SetOutput(io.Writer)` can be used to set the output destination for the logger. Default value is `os.Stdout` To completely disable logs use `Echo#Logger.SetOutput(io.Discard)` or `Echo#Logger.SetLevel(log.OFF)` ### Log Level[​](https://echo.labstack.com/docs/customization#log-level "Direct link to Log Level") `Echo#Logger.SetLevel(log.Lvl)` can be used to set the log level for the logger. Default value is `ERROR`. Possible values: * `DEBUG` * `INFO` * `WARN` * `ERROR` * `OFF` ### Custom Logger[​](https://echo.labstack.com/docs/customization#custom-logger "Direct link to Custom Logger") Logging is implemented using `echo.Logger` interface which allows you to register a custom logger using `Echo#Logger`. Startup Banner[​](https://echo.labstack.com/docs/customization#startup-banner "Direct link to Startup Banner") --------------------------------------------------------------------------------------------------------------- `Echo#HideBanner` can be used to hide the startup banner. Listener Port[​](https://echo.labstack.com/docs/customization#listener-port "Direct link to Listener Port") ------------------------------------------------------------------------------------------------------------ `Echo#HidePort` can be used to hide the listener port message. Custom Listener[​](https://echo.labstack.com/docs/customization#custom-listener "Direct link to Custom Listener") ------------------------------------------------------------------------------------------------------------------ `Echo#*Listener` can be used to run a custom listener. _Example_ l, err := net.Listen("tcp", ":1323")if err != nil { e.Logger.Fatal(err)}e.Listener = le.Logger.Fatal(e.Start("")) Disable HTTP/2[​](https://echo.labstack.com/docs/customization#disable-http2 "Direct link to Disable HTTP/2") -------------------------------------------------------------------------------------------------------------- `Echo#DisableHTTP2` can be used to disable HTTP/2 protocol. Read Timeout[​](https://echo.labstack.com/docs/customization#read-timeout "Direct link to Read Timeout") --------------------------------------------------------------------------------------------------------- `Echo#*Server#ReadTimeout` can be used to set the maximum duration before timing out read of the request. Write Timeout[​](https://echo.labstack.com/docs/customization#write-timeout "Direct link to Write Timeout") ------------------------------------------------------------------------------------------------------------ `Echo#*Server#WriteTimeout` can be used to set the maximum duration before timing out write of the response. Validator[​](https://echo.labstack.com/docs/customization#validator "Direct link to Validator") ------------------------------------------------------------------------------------------------ `Echo#Validator` can be used to register a validator for performing data validation on request payload. [Learn more](https://echo.labstack.com/docs/request#validate-data) Custom Binder[​](https://echo.labstack.com/docs/customization#custom-binder "Direct link to Custom Binder") ------------------------------------------------------------------------------------------------------------ `Echo#Binder` can be used to register a custom binder for binding request payload. [Learn more](https://echo.labstack.com/docs/binding#custom-binding) Custom JSON Serializer[​](https://echo.labstack.com/docs/customization#custom-json-serializer "Direct link to Custom JSON Serializer") --------------------------------------------------------------------------------------------------------------------------------------- `Echo#JSONSerializer` can be used to register a custom JSON serializer. Have a look at `DefaultJSONSerializer` on [json.go](https://github.com/labstack/echo/blob/master/json.go) . Renderer[​](https://echo.labstack.com/docs/customization#renderer "Direct link to Renderer") --------------------------------------------------------------------------------------------- `Echo#Renderer` can be used to register a renderer for template rendering. [Learn more](https://echo.labstack.com/docs/templates) HTTP Error Handler[​](https://echo.labstack.com/docs/customization#http-error-handler "Direct link to HTTP Error Handler") --------------------------------------------------------------------------------------------------------------------------- `Echo#HTTPErrorHandler` can be used to register a custom http error handler. [Learn more](https://echo.labstack.com/docs/error-handling) * [Debug](https://echo.labstack.com/docs/customization#debug) * [Logging](https://echo.labstack.com/docs/customization#logging) * [Log Header](https://echo.labstack.com/docs/customization#log-header) * [Log Output](https://echo.labstack.com/docs/customization#log-output) * [Log Level](https://echo.labstack.com/docs/customization#log-level) * [Custom Logger](https://echo.labstack.com/docs/customization#custom-logger) * [Startup Banner](https://echo.labstack.com/docs/customization#startup-banner) * [Listener Port](https://echo.labstack.com/docs/customization#listener-port) * [Custom Listener](https://echo.labstack.com/docs/customization#custom-listener) * [Disable HTTP/2](https://echo.labstack.com/docs/customization#disable-http2) * [Read Timeout](https://echo.labstack.com/docs/customization#read-timeout) * [Write Timeout](https://echo.labstack.com/docs/customization#write-timeout) * [Validator](https://echo.labstack.com/docs/customization#validator) * [Custom Binder](https://echo.labstack.com/docs/customization#custom-binder) * [Custom JSON Serializer](https://echo.labstack.com/docs/customization#custom-json-serializer) * [Renderer](https://echo.labstack.com/docs/customization#renderer) * [HTTP Error Handler](https://echo.labstack.com/docs/customization#http-error-handler) --- # JWT | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/jwt#__docusaurus_skipToContent_fallback) On this page [JWT middleware](https://echo.labstack.com/docs/middleware/jwt) configuration can be found [here](https://echo.labstack.com/docs/middleware/jwt#configuration) . This is cookbook for: * JWT authentication using HS256 algorithm. * JWT is retrieved from `Authorization` request header. Server[​](https://echo.labstack.com/docs/cookbook/jwt#server "Direct link to Server") -------------------------------------------------------------------------------------- ### Using custom claims[​](https://echo.labstack.com/docs/cookbook/jwt#using-custom-claims "Direct link to Using custom claims") cookbook/jwt/custom-claims/server.go loading... ### Using a user-defined KeyFunc[​](https://echo.labstack.com/docs/cookbook/jwt#using-a-user-defined-keyfunc "Direct link to Using a user-defined KeyFunc") cookbook/jwt/user-defined-keyfunc/server.go loading... Client[​](https://echo.labstack.com/docs/cookbook/jwt#client "Direct link to Client") -------------------------------------------------------------------------------------- ### Login[​](https://echo.labstack.com/docs/cookbook/jwt#login "Direct link to Login") Login using username and password to retrieve a token. curl -X POST -d 'username=jon' -d 'password=shhh!' localhost:1323/login ### Response[​](https://echo.labstack.com/docs/cookbook/jwt#response "Direct link to Response") { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NjE5NTcxMzZ9.RB3arc4-OyzASAaUhC2W3ReWaXAt_z2Fd3BN4aWTgEY"} ### Request[​](https://echo.labstack.com/docs/cookbook/jwt#request "Direct link to Request") Request a restricted resource using the token in `Authorization` request header. curl localhost:1323/restricted -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NjE5NTcxMzZ9.RB3arc4-OyzASAaUhC2W3ReWaXAt_z2Fd3BN4aWTgEY" ### Response[​](https://echo.labstack.com/docs/cookbook/jwt#response-1 "Direct link to Response") Welcome Jon Snow! * [Server](https://echo.labstack.com/docs/cookbook/jwt#server) * [Using custom claims](https://echo.labstack.com/docs/cookbook/jwt#using-custom-claims) * [Using a user-defined KeyFunc](https://echo.labstack.com/docs/cookbook/jwt#using-a-user-defined-keyfunc) * [Client](https://echo.labstack.com/docs/cookbook/jwt#client) * [Login](https://echo.labstack.com/docs/cookbook/jwt#login) * [Response](https://echo.labstack.com/docs/cookbook/jwt#response) * [Request](https://echo.labstack.com/docs/cookbook/jwt#request) * [Response](https://echo.labstack.com/docs/cookbook/jwt#response-1) --- # Load Balancing | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/load-balancing#__docusaurus_skipToContent_fallback) On this page This recipe demonstrates how you can use Nginx as a reverse proxy server and load balance between multiple Echo servers. Echo[​](https://echo.labstack.com/docs/cookbook/load-balancing#echo "Direct link to Echo") ------------------------------------------------------------------------------------------- cookbook/load-balancing/upstream/server.go loading... ### Start servers[​](https://echo.labstack.com/docs/cookbook/load-balancing#start-servers "Direct link to Start servers") * `cd upstream` * `go run server.go server1 :8081` * `go run server.go server2 :8082` Nginx[​](https://echo.labstack.com/docs/cookbook/load-balancing#nginx "Direct link to Nginx") ---------------------------------------------------------------------------------------------- ### 1) Install Nginx[​](https://echo.labstack.com/docs/cookbook/load-balancing#1-install-nginx "Direct link to 1) Install Nginx") [https://www.nginx.com/resources/wiki/start/topics/tutorials/install](https://www.nginx.com/resources/wiki/start/topics/tutorials/install) ### 2) Configure Nginx[​](https://echo.labstack.com/docs/cookbook/load-balancing#2-configure-nginx "Direct link to 2) Configure Nginx") Create a file `/etc/nginx/sites-enabled/localhost` with the following content: https://github.com/labstack/echox/blob/master/cookbook/load-balancing/nginx.conf info Change listen, server\_name, access\_log per your need. ### 3) Restart Nginx[​](https://echo.labstack.com/docs/cookbook/load-balancing#3-restart-nginx "Direct link to 3) Restart Nginx") service nginx restart Browse to [https://localhost:8080](https://localhost:8080/) , and you should see a webpage being served from either "server 1" or "server 2". Hello from upstream server server1 * [Echo](https://echo.labstack.com/docs/cookbook/load-balancing#echo) * [Start servers](https://echo.labstack.com/docs/cookbook/load-balancing#start-servers) * [Nginx](https://echo.labstack.com/docs/cookbook/load-balancing#nginx) * [1) Install Nginx](https://echo.labstack.com/docs/cookbook/load-balancing#1-install-nginx) * [2) Configure Nginx](https://echo.labstack.com/docs/cookbook/load-balancing#2-configure-nginx) * [3) Restart Nginx](https://echo.labstack.com/docs/cookbook/load-balancing#3-restart-nginx) --- # IP Address | Echo [Skip to main content](https://echo.labstack.com/docs/ip-address#__docusaurus_skipToContent_fallback) On this page IP address plays a fundamental role in HTTP; it's used for access control, auditing, geo-based access analysis, and more. Echo provides a handy method [`Context#RealIP()`](https://godoc.org/github.com/labstack/echo#Context) for that. However, it is not trivial to retrieve the _real_ IP address from requests especially when you put L7 proxies before the application. In such situations, _real_ IP needs to be relayed on the HTTP layer from proxies to your app, however, you must not trust HTTP headers unconditionally. Otherwise you might give someone a chance of deceiving you. **A security risk!** To retrieve IP address reliably/securely, you must let your application be aware of the entire architecture of your infrastructrure. In Echo, this can be done by configuring `Echo#IPExtractor` appropriately. This guides show you why and how. caution Note: if you don't set `Echo#IPExtractor` explicitly, Echo fallback to legacy behavior, which is not a good choice. Let's start from two questions to know the right direction: 1. Do you put any HTTP (L7) proxy in front of the application? * It includes both cloud solutions (such as AWS ALB or GCP HTTP LB) and OSS ones (such as Nginx, Envoy or Istio ingress gateway). 2. If yes, what HTTP header do your proxies use to pass client IP to the application? Case 1. With no proxy[​](https://echo.labstack.com/docs/ip-address#case-1-with-no-proxy "Direct link to Case 1. With no proxy") -------------------------------------------------------------------------------------------------------------------------------- If you put no proxy (e.g.: directory facing to the internet), all you need to (and have to) see is IP address from network layer. Any HTTP header is untrustable because the clients have full control what headers to be set. In this case, use `echo.ExtractIPDirect()`. e.IPExtractor = echo.ExtractIPDirect() Case 2. With proxies using X-Forwarded-For header[​](https://echo.labstack.com/docs/ip-address#case-2-with-proxies-using-x-forwarded-for-header "Direct link to Case 2. With proxies using X-Forwarded-For header") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [`X-Forwarded-For` (XFF)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) is the popular header to relay clients' IP addresses. At each hop on the proxies, they append the request IP address at the end of the header. Following example diagram illustrates this behavior. ┌──────────┐ ┌──────────┐ ┌──────────┐───────────>│ Proxy 1 │───────────>│ Proxy 2 │───────────>│ Your app │ │ (IP: b) │ │ (IP: c) │ │ │ └──────────┘ └──────────┘ └──────────┘Case 1.XFF: "" "a" "a, b" ~~~~~~Case 2.XFF: "x" "x, a" "x, a, b" ~~~~~~~~~ ↑ What your app will see In this case, use **first _untrustable_ IP reading from right**. Never use first one reading from left, as it is configurable by client. Here "trustable" means "you are sure the IP address belongs to your infrastructure". In above example, if `b` and `c` are trustable, the IP address of the client is `a` for both cases, never be `x`. In Echo, use `ExtractIPFromXFFHeader(...TrustOption)`. e.IPExtractor = echo.ExtractIPFromXFFHeader() By default, it trusts internal IP addresses (loopback, link-local unicast, private-use and unique local address from [RFC6890](https://tools.ietf.org/html/rfc6890) , [RFC4291](https://tools.ietf.org/html/rfc4291) and [RFC4193](https://tools.ietf.org/html/rfc4193) ). To control this behavior, use [`TrustOption`](https://godoc.org/github.com/labstack/echo#TrustOption) s. E.g.: e.IPExtractor = echo.ExtractIPFromXFFHeader( echo.TrustLoopback(false), // e.g. ipv4 start with 127. echo.TrustLinkLocal(false), // e.g. ipv4 start with 169.254 echo.TrustPrivateNet(false), // e.g. ipv4 start with 10. or 192.168 echo.TrustIPRange(lbIPRange),) * Ref: [https://godoc.org/github.com/labstack/echo#TrustOption](https://godoc.org/github.com/labstack/echo#TrustOption) Case 3. With proxies using X-Real-IP header[​](https://echo.labstack.com/docs/ip-address#case-3-with-proxies-using-x-real-ip-header "Direct link to Case 3. With proxies using X-Real-IP header") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- `X-Real-IP` is another HTTP header to relay clients' IP addresses, but it carries only one address unlike XFF. If your proxies set this header, use `ExtractIPFromRealIPHeader(...TrustOption)`. e.IPExtractor = echo.ExtractIPFromRealIPHeader() Again, it trusts internal IP addresses by default (loopback, link-local unicast, private-use and unique local address from [RFC6890](https://tools.ietf.org/html/rfc6890) , [RFC4291](https://tools.ietf.org/html/rfc4291) and [RFC4193](https://tools.ietf.org/html/rfc4193) ). To control this behavior, use [`TrustOption`](https://godoc.org/github.com/labstack/echo#TrustOption) s. * Ref: [https://godoc.org/github.com/labstack/echo#TrustOption](https://godoc.org/github.com/labstack/echo#TrustOption) > **Never forget** to configure the outermost proxy (i.e.; at the edge of your infrastructure) **not to pass through incoming headers**. Otherwise there is a chance of fraud, as it is what clients can control. About default behavior[​](https://echo.labstack.com/docs/ip-address#about-default-behavior "Direct link to About default behavior") ------------------------------------------------------------------------------------------------------------------------------------ In default behavior, Echo sees all of first XFF header, X-Real-IP header and IP from network layer. As you might already notice, after reading this article, this is not good. Sole reason this is default is just backward compatibility. * [Case 1. With no proxy](https://echo.labstack.com/docs/ip-address#case-1-with-no-proxy) * [Case 2. With proxies using X-Forwarded-For header](https://echo.labstack.com/docs/ip-address#case-2-with-proxies-using-x-forwarded-for-header) * [Case 3. With proxies using X-Real-IP header](https://echo.labstack.com/docs/ip-address#case-3-with-proxies-using-x-real-ip-header) * [About default behavior](https://echo.labstack.com/docs/ip-address#about-default-behavior) --- # Error Handling | Echo [Skip to main content](https://echo.labstack.com/docs/error-handling#__docusaurus_skipToContent_fallback) On this page Echo advocates for centralized HTTP error handling by returning error from middleware and handlers. Centralized error handler allows us to log errors to external services from a unified location and send a customized HTTP response to the client. You can return a standard `error` or `echo.*HTTPError`. For example, when basic auth middleware finds invalid credentials it returns 401 - Unauthorized error, aborting the current HTTP request. e.Use(func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { // Extract the credentials from HTTP request header and perform a security // check // For invalid credentials return echo.NewHTTPError(http.StatusUnauthorized, "Please provide valid credentials") // For valid credentials call next // return next(c) }}) You can also use `echo.NewHTTPError()` without a message, in that case status text is used as an error message. For example, "Unauthorized". Default HTTP Error Handler[​](https://echo.labstack.com/docs/error-handling#default-http-error-handler "Direct link to Default HTTP Error Handler") ---------------------------------------------------------------------------------------------------------------------------------------------------- Echo provides a default HTTP error handler which sends error in a JSON format. { "message": "error connecting to redis"} For a standard `error`, response is sent as `500 - Internal Server Error`; however, if you are running in a debug mode, the original error message is sent. If error is `*HTTPError`, response is sent with the provided status code and message. If logging is on, the error message is also logged. Custom HTTP Error Handler[​](https://echo.labstack.com/docs/error-handling#custom-http-error-handler "Direct link to Custom HTTP Error Handler") ------------------------------------------------------------------------------------------------------------------------------------------------- Custom HTTP error handler can be set via `e.HTTPErrorHandler` For most cases default error HTTP handler should be sufficient; however, a custom HTTP error handler can come handy if you want to capture different type of errors and take action accordingly e.g. send notification email or log error to a centralized system. You can also send customized response to the client e.g. error page or just a JSON response. ### Error Pages[​](https://echo.labstack.com/docs/error-handling#error-pages "Direct link to Error Pages") The following custom HTTP error handler shows how to display error pages for different type of errors and logs the error. The name of the error page should be like `.html` e.g. `500.html`. You can look into this project [https://github.com/AndiDittrich/HttpErrorPages](https://github.com/AndiDittrich/HttpErrorPages) for pre-built error pages. func customHTTPErrorHandler(err error, c echo.Context) { if c.Response().Committed { return } code := http.StatusInternalServerError if he, ok := err.(*echo.HTTPError); ok { code = he.Code } c.Logger().Error(err) errorPage := fmt.Sprintf("%d.html", code) if err := c.File(errorPage); err != nil { c.Logger().Error(err) }}e.HTTPErrorHandler = customHTTPErrorHandler tip Instead of writing logs to the logger, you can also write them to an external service like Elasticsearch or Splunk. * [Default HTTP Error Handler](https://echo.labstack.com/docs/error-handling#default-http-error-handler) * [Custom HTTP Error Handler](https://echo.labstack.com/docs/error-handling#custom-http-error-handler) * [Error Pages](https://echo.labstack.com/docs/error-handling#error-pages) --- # Middleware | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/middleware#__docusaurus_skipToContent_fallback) On this page Write a custom middleware[​](https://echo.labstack.com/docs/cookbook/middleware#write-a-custom-middleware "Direct link to Write a custom middleware") ------------------------------------------------------------------------------------------------------------------------------------------------------ * Middleware to collect request count, statuses and uptime. * Middleware to write custom `Server` header to the response. ### Server[​](https://echo.labstack.com/docs/cookbook/middleware#server "Direct link to Server") cookbook/middleware/server.go loading... ### Response[​](https://echo.labstack.com/docs/cookbook/middleware#response "Direct link to Response") #### Headers[​](https://echo.labstack.com/docs/cookbook/middleware#headers "Direct link to Headers") Content-Length:122Content-Type:application/json; charset=utf-8Date:Thu, 14 Apr 2016 20:31:46 GMTServer:Echo/3.0 #### Body[​](https://echo.labstack.com/docs/cookbook/middleware#body "Direct link to Body") { "uptime": "2016-04-14T13:28:48.486548936-07:00", "requestCount": 5, "statuses": { "200": 4, "404": 1 }} * [Write a custom middleware](https://echo.labstack.com/docs/cookbook/middleware#write-a-custom-middleware) * [Server](https://echo.labstack.com/docs/cookbook/middleware#server) * [Response](https://echo.labstack.com/docs/cookbook/middleware#response) --- # Reverse Proxy | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/reverse-proxy#__docusaurus_skipToContent_fallback) On this page This recipe demonstrates how you can use Echo as a reverse proxy server and load balancer in front of your favorite applications like WordPress, Node.js, Java, Python, Ruby or even Go. For simplicity, I will use Go upstream servers with WebSocket. 1) Identify upstream target URL(s)[​](https://echo.labstack.com/docs/cookbook/reverse-proxy#1-identify-upstream-target-urls "Direct link to 1) Identify upstream target URL(s)") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- url1, err := url.Parse("http://localhost:8081")if err != nil { e.Logger.Fatal(err)}url2, err := url.Parse("http://localhost:8082")if err != nil { e.Logger.Fatal(err)}targets := []*middleware.ProxyTarget{ { URL: url1, }, { URL: url2, },} 2) Setup proxy middleware with upstream targets[​](https://echo.labstack.com/docs/cookbook/reverse-proxy#2-setup-proxy-middleware-with-upstream-targets "Direct link to 2) Setup proxy middleware with upstream targets") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- In the following code snippet we are using round-robin load balancing technique. You may also use `middleware.NewRandomBalancer()`. e.Use(middleware.Proxy(middleware.NewRoundRobinBalancer(targets))) To setup proxy for a sub-route use `Echo#Group()`. g := e.Group("/blog")g.Use(middleware.Proxy(...)) 3) Start upstream servers[​](https://echo.labstack.com/docs/cookbook/reverse-proxy#3-start-upstream-servers "Direct link to 3) Start upstream servers") -------------------------------------------------------------------------------------------------------------------------------------------------------- * `cd upstream` * `go run server.go server1 :8081` * `go run server.go server2 :8082` 4) Start the proxy server[​](https://echo.labstack.com/docs/cookbook/reverse-proxy#4-start-the-proxy-server "Direct link to 4) Start the proxy server") -------------------------------------------------------------------------------------------------------------------------------------------------------- go run server.go Browse to [http://localhost:1323](http://localhost:1323/) , and you should see a webpage with an HTTP request being served from "server 1" and a WebSocket request being served from "server 2." HTTPHello from upstream server server1WebSocketHello from upstream server server2!Hello from upstream server server2!Hello from upstream server server2! Source Code[​](https://echo.labstack.com/docs/cookbook/reverse-proxy#source-code "Direct link to Source Code") --------------------------------------------------------------------------------------------------------------- cookbook/reverse-proxy/upstream/server.go loading... cookbook/reverse-proxy/server.go loading... * [1) Identify upstream target URL(s)](https://echo.labstack.com/docs/cookbook/reverse-proxy#1-identify-upstream-target-urls) * [2) Setup proxy middleware with upstream targets](https://echo.labstack.com/docs/cookbook/reverse-proxy#2-setup-proxy-middleware-with-upstream-targets) * [3) Start upstream servers](https://echo.labstack.com/docs/cookbook/reverse-proxy#3-start-upstream-servers) * [4) Start the proxy server](https://echo.labstack.com/docs/cookbook/reverse-proxy#4-start-the-proxy-server) * [Source Code](https://echo.labstack.com/docs/cookbook/reverse-proxy#source-code) --- # Server-Sent-Events (SSE) | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/sse#__docusaurus_skipToContent_fallback) On this page [Server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#event_stream_format) can be used in different ways. This example here is per connection - per handler SSE. If your requirements need more complex broadcasting logic see [https://github.com/r3labs/sse](https://github.com/r3labs/sse) library. Using SSE[​](https://echo.labstack.com/docs/cookbook/sse#using-sse "Direct link to Using SSE") ----------------------------------------------------------------------------------------------- ### Server[​](https://echo.labstack.com/docs/cookbook/sse#server "Direct link to Server") cookbook/sse/simple/server.go loading... ### Event structure and Marshal method[​](https://echo.labstack.com/docs/cookbook/sse#event-structure-and-marshal-method "Direct link to Event structure and Marshal method") cookbook/sse/simple/serversentevent.go loading... ### HTML serving SSE[​](https://echo.labstack.com/docs/cookbook/sse#html-serving-sse "Direct link to HTML serving SSE") cookbook/sse/simple/index.html loading... Using 3rd party library [r3labs/sse](https://github.com/r3labs/sse) to broadcast events[​](https://echo.labstack.com/docs/cookbook/sse#using-3rd-party-library-r3labssse-to-broadcast-events "Direct link to using-3rd-party-library-r3labssse-to-broadcast-events") ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### Server[​](https://echo.labstack.com/docs/cookbook/sse#server-1 "Direct link to Server") cookbook/sse/broadcast/server.go loading... ### HTML serving SSE[​](https://echo.labstack.com/docs/cookbook/sse#html-serving-sse-1 "Direct link to HTML serving SSE") cookbook/sse/broadcast/index.html loading... * [Using SSE](https://echo.labstack.com/docs/cookbook/sse#using-sse) * [Server](https://echo.labstack.com/docs/cookbook/sse#server) * [Event structure and Marshal method](https://echo.labstack.com/docs/cookbook/sse#event-structure-and-marshal-method) * [HTML serving SSE](https://echo.labstack.com/docs/cookbook/sse#html-serving-sse) * [Using 3rd party library r3labs/sse to broadcast events](https://echo.labstack.com/docs/cookbook/sse#using-3rd-party-library-r3labssse-to-broadcast-events) * [Server](https://echo.labstack.com/docs/cookbook/sse#server-1) * [HTML serving SSE](https://echo.labstack.com/docs/cookbook/sse#html-serving-sse-1) --- # Streaming Response | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/streaming-response#__docusaurus_skipToContent_fallback) On this page * Send data as it is produced * Streaming JSON response with chunked transfer encoding Server[​](https://echo.labstack.com/docs/cookbook/streaming-response#server "Direct link to Server") ----------------------------------------------------------------------------------------------------- cookbook/streaming-response/server.go loading... Client[​](https://echo.labstack.com/docs/cookbook/streaming-response#client "Direct link to Client") ----------------------------------------------------------------------------------------------------- $ curl localhost:1323 ### Output[​](https://echo.labstack.com/docs/cookbook/streaming-response#output "Direct link to Output") {"Altitude":-97,"Latitude":37.819929,"Longitude":-122.478255}{"Altitude":1899,"Latitude":39.096849,"Longitude":-120.032351}{"Altitude":2619,"Latitude":37.865101,"Longitude":-119.538329}{"Altitude":42,"Latitude":33.812092,"Longitude":-117.918974}{"Altitude":15,"Latitude":37.77493,"Longitude":-122.419416} * [Server](https://echo.labstack.com/docs/cookbook/streaming-response#server) * [Client](https://echo.labstack.com/docs/cookbook/streaming-response#client) * [Output](https://echo.labstack.com/docs/cookbook/streaming-response#output) --- # Subdomain | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/subdomain#__docusaurus_skipToContent_fallback) On this page Server[​](https://echo.labstack.com/docs/cookbook/subdomain#server "Direct link to Server") -------------------------------------------------------------------------------------------- cookbook/subdomain/server.go loading... * [Server](https://echo.labstack.com/docs/cookbook/subdomain#server) --- # WebSocket | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/websocket#__docusaurus_skipToContent_fallback) On this page Using net WebSocket[​](https://echo.labstack.com/docs/cookbook/websocket#using-net-websocket "Direct link to Using net WebSocket") ----------------------------------------------------------------------------------------------------------------------------------- ### Server[​](https://echo.labstack.com/docs/cookbook/websocket#server "Direct link to Server") cookbook/websocket/net/server.go loading... Using gorilla WebSocket[​](https://echo.labstack.com/docs/cookbook/websocket#using-gorilla-websocket "Direct link to Using gorilla WebSocket") ----------------------------------------------------------------------------------------------------------------------------------------------- ### Server[​](https://echo.labstack.com/docs/cookbook/websocket#server-1 "Direct link to Server") cookbook/websocket/gorilla/server.go loading... Client[​](https://echo.labstack.com/docs/cookbook/websocket#client "Direct link to Client") -------------------------------------------------------------------------------------------- cookbook/websocket/public/index.html loading... Output[​](https://echo.labstack.com/docs/cookbook/websocket#output "Direct link to Output") -------------------------------------------------------------------------------------------- Hello, Client!Hello, Client!Hello, Client!Hello, Client!Hello, Client! Hello, Server!Hello, Server!Hello, Server!Hello, Server!Hello, Server! * [Using net WebSocket](https://echo.labstack.com/docs/cookbook/websocket#using-net-websocket) * [Server](https://echo.labstack.com/docs/cookbook/websocket#server) * [Using gorilla WebSocket](https://echo.labstack.com/docs/cookbook/websocket#using-gorilla-websocket) * [Server](https://echo.labstack.com/docs/cookbook/websocket#server-1) * [Client](https://echo.labstack.com/docs/cookbook/websocket#client) * [Output](https://echo.labstack.com/docs/cookbook/websocket#output) --- # Timeout | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/timeout#__docusaurus_skipToContent_fallback) On this page Server[​](https://echo.labstack.com/docs/cookbook/timeout#server "Direct link to Server") ------------------------------------------------------------------------------------------ cookbook/timeout/server.go loading... * [Server](https://echo.labstack.com/docs/cookbook/timeout#server) --- # Twitter Like API | Echo [Skip to main content](https://echo.labstack.com/docs/cookbook/twitter#__docusaurus_skipToContent_fallback) On this page This recipe demonstrates how to create a Twitter like REST API using MongoDB (Database), JWT (API security) and JSON (Data exchange). Models[​](https://echo.labstack.com/docs/cookbook/twitter#models "Direct link to Models") ------------------------------------------------------------------------------------------ cookbook/twitter/model/user.go loading... cookbook/twitter/model/post.go loading... Handlers[​](https://echo.labstack.com/docs/cookbook/twitter#handlers "Direct link to Handlers") ------------------------------------------------------------------------------------------------ cookbook/twitter/handler/handler.go loading... cookbook/twitter/handler/user.go loading... cookbook/twitter/handler/post.go loading... Server[​](https://echo.labstack.com/docs/cookbook/twitter#server "Direct link to Server") ------------------------------------------------------------------------------------------ cookbook/twitter/server.go loading... API[​](https://echo.labstack.com/docs/cookbook/twitter#api "Direct link to API") --------------------------------------------------------------------------------- ### Signup[​](https://echo.labstack.com/docs/cookbook/twitter#signup "Direct link to Signup") User signup * Retrieve user credentials from the body and validate against database. * For invalid email or password, send `400 - Bad Request` response. * For valid email and password, save user in database and send `201 - Created` response. #### Request[​](https://echo.labstack.com/docs/cookbook/twitter#request "Direct link to Request") curl \ -X POST \ http://localhost:1323/signup \ -H "Content-Type: application/json" \ -d '{"email":"[email protected]","password":"shhh!"}' #### Response[​](https://echo.labstack.com/docs/cookbook/twitter#response "Direct link to Response") `201 - Created` { "id": "58465b4ea6fe886d3215c6df", "email": "[email protected]", "password": "shhh!"} ### Login[​](https://echo.labstack.com/docs/cookbook/twitter#login "Direct link to Login") User login * Retrieve user credentials from the body and validate against database. * For invalid credentials, send `401 - Unauthorized` response. * For valid credentials, send `200 - OK` response: * Generate JWT for the user and send it as response. * Each subsequent request must include JWT in the `Authorization` header. `POST` `/login` #### Request[​](https://echo.labstack.com/docs/cookbook/twitter#request-1 "Direct link to Request") curl \ -X POST \ http://localhost:1323/login \ -H "Content-Type: application/json" \ -d '{"email":"[email protected]","password":"shhh!"}' #### Response[​](https://echo.labstack.com/docs/cookbook/twitter#response-1 "Direct link to Response") `200 - OK` { "id": "58465b4ea6fe886d3215c6df", "email": "[email protected]", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0ODEyNjUxMjgsImlkIjoiNTg0NjViNGVhNmZlODg2ZDMyMTVjNmRmIn0.1IsGGxko1qMCsKkJDQ1NfmrZ945XVC9uZpcvDnKwpL0"} tip Client should store the token, for browsers, you may use local storage. ### Follow[​](https://echo.labstack.com/docs/cookbook/twitter#follow "Direct link to Follow") Follow a user * For invalid token, send `400 - Bad Request` response. * For valid token: * If user is not found, send `404 - Not Found` response. * Add a follower to the specified user in the path parameter and send `200 - OK` response. `POST` `/follow/:id` #### Request[​](https://echo.labstack.com/docs/cookbook/twitter#request-2 "Direct link to Request") curl \ -X POST \ http://localhost:1323/follow/58465b4ea6fe886d3215c6df \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0ODEyNjUxMjgsImlkIjoiNTg0NjViNGVhNmZlODg2ZDMyMTVjNmRmIn0.1IsGGxko1qMCsKkJDQ1NfmrZ945XVC9uZpcvDnKwpL0" #### Response[​](https://echo.labstack.com/docs/cookbook/twitter#response-2 "Direct link to Response") `200 - OK` ### Post[​](https://echo.labstack.com/docs/cookbook/twitter#post "Direct link to Post") Post a message to specified user * For invalid request payload, send `400 - Bad Request` response. * If user is not found, send `404 - Not Found` response. * Otherwise save post in the database and return it via `201 - Created` response. `POST` `/posts` #### Request[​](https://echo.labstack.com/docs/cookbook/twitter#request-3 "Direct link to Request") curl \ -X POST \ http://localhost:1323/posts \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0ODEyNjUxMjgsImlkIjoiNTg0NjViNGVhNmZlODg2ZDMyMTVjNmRmIn0.1IsGGxko1qMCsKkJDQ1NfmrZ945XVC9uZpcvDnKwpL0" \ -H "Content-Type: application/json" \ -d '{"to":"58465b4ea6fe886d3215c6df","message":"hello"}' #### Response[​](https://echo.labstack.com/docs/cookbook/twitter#response-3 "Direct link to Response") `201 - Created` { "id": "584661b9a6fe8871a3804cba", "to": "58465b4ea6fe886d3215c6df", "from": "58465b4ea6fe886d3215c6df", "message": "hello"} ### Feed[​](https://echo.labstack.com/docs/cookbook/twitter#feed "Direct link to Feed") List most recent messages based on optional `page` and `limit` query parameters `GET` `/feed?page=1&limit=5` #### Request[​](https://echo.labstack.com/docs/cookbook/twitter#request-4 "Direct link to Request") curl \ -X GET \ http://localhost:1323/feed \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0ODEyNjUxMjgsImlkIjoiNTg0NjViNGVhNmZlODg2ZDMyMTVjNmRmIn0.1IsGGxko1qMCsKkJDQ1NfmrZ945XVC9uZpcvDnKwpL0" #### Response[​](https://echo.labstack.com/docs/cookbook/twitter#response-4 "Direct link to Response") `200 - OK` [ { "id": "584661b9a6fe8871a3804cba", "to": "58465b4ea6fe886d3215c6df", "from": "58465b4ea6fe886d3215c6df", "message": "hello" }] * [Models](https://echo.labstack.com/docs/cookbook/twitter#models) * [Handlers](https://echo.labstack.com/docs/cookbook/twitter#handlers) * [Server](https://echo.labstack.com/docs/cookbook/twitter#server) * [API](https://echo.labstack.com/docs/cookbook/twitter#api) * [Signup](https://echo.labstack.com/docs/cookbook/twitter#signup) * [Login](https://echo.labstack.com/docs/cookbook/twitter#login) * [Follow](https://echo.labstack.com/docs/cookbook/twitter#follow) * [Post](https://echo.labstack.com/docs/cookbook/twitter#post) * [Feed](https://echo.labstack.com/docs/cookbook/twitter#feed) --- # Request | Echo [Skip to main content](https://echo.labstack.com/docs/request#__docusaurus_skipToContent_fallback) On this page Retrieve Data[​](https://echo.labstack.com/docs/request#retrieve-data "Direct link to Retrieve Data") ------------------------------------------------------------------------------------------------------ ### Form Data[​](https://echo.labstack.com/docs/request#form-data "Direct link to Form Data") Form data can be retrieved by name using `Context#FormValue(name string)`. // Handlerfunc(c echo.Context) error { name := c.FormValue("name") return c.String(http.StatusOK, name)} curl -X POST http://localhost:1323 -d 'name=Joe' To bind a custom data type, you can implement `Echo#BindUnmarshaler` interface. type Timestamp time.Timefunc (t *Timestamp) UnmarshalParam(src string) error { ts, err := time.Parse(time.RFC3339, src) *t = Timestamp(ts) return err} ### Query Parameters[​](https://echo.labstack.com/docs/request#query-parameters "Direct link to Query Parameters") Query parameters can be retrieved by name using `Context#QueryParam(name string)`. // Handlerfunc(c echo.Context) error { name := c.QueryParam("name") return c.String(http.StatusOK, name)}) curl \ -X GET \ http://localhost:1323\?name\=Joe Similar to form data, custom data type can be bind using `Context#QueryParam(name string)`. ### Path Parameters[​](https://echo.labstack.com/docs/request#path-parameters "Direct link to Path Parameters") Registered path parameters can be retrieved by name using `Context#Param(name string) string`. e.GET("/users/:name", func(c echo.Context) error { name := c.Param("name") return c.String(http.StatusOK, name)}) curl http://localhost:1323/users/Joe ### Binding Data[​](https://echo.labstack.com/docs/request#binding-data "Direct link to Binding Data") Also binding of request data to native Go structs and variables is supported. See [Binding Data](https://echo.labstack.com/docs/binding) Validate Data[​](https://echo.labstack.com/docs/request#validate-data "Direct link to Validate Data") ------------------------------------------------------------------------------------------------------ Echo doesn't have built-in data validation capabilities, however, you can register a custom validator using `Echo#Validator` and leverage third-party [libraries](https://github.com/avelino/awesome-go#validation) . Example below uses [https://github.com/go-playground/validator](https://github.com/go-playground/validator) framework for validation: package mainimport ( "net/http" "github.com/go-playground/validator" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware")type ( User struct { Name string `json:"name" validate:"required"` Email string `json:"email" validate:"required,email"` } CustomValidator struct { validator *validator.Validate })func (cv *CustomValidator) Validate(i interface{}) error { if err := cv.validator.Struct(i); err != nil { // Optionally, you could return the error to give each route more control over the status code return echo.NewHTTPError(http.StatusBadRequest, err.Error()) } return nil}func main() { e := echo.New() e.Validator = &CustomValidator{validator: validator.New()} e.POST("/users", func(c echo.Context) (err error) { u := new(User) if err = c.Bind(u); err != nil { return echo.NewHTTPError(http.StatusBadRequest, err.Error()) } if err = c.Validate(u); err != nil { return err } return c.JSON(http.StatusOK, u) }) e.Logger.Fatal(e.Start(":1323"))} curl -X POST http://localhost:1323/users \ -H 'Content-Type: application/json' \ -d '{"name":"Joe","email":"joe@invalid-domain"}'{"message":"Key: 'User.Email' Error:Field validation for 'Email' failed on the 'email' tag"} * [Retrieve Data](https://echo.labstack.com/docs/request#retrieve-data) * [Form Data](https://echo.labstack.com/docs/request#form-data) * [Query Parameters](https://echo.labstack.com/docs/request#query-parameters) * [Path Parameters](https://echo.labstack.com/docs/request#path-parameters) * [Binding Data](https://echo.labstack.com/docs/request#binding-data) * [Validate Data](https://echo.labstack.com/docs/request#validate-data) --- # Quick Start | Echo [Skip to main content](https://echo.labstack.com/docs/quick-start#__docusaurus_skipToContent_fallback) On this page Installation[​](https://echo.labstack.com/docs/quick-start#installation "Direct link to Installation") ------------------------------------------------------------------------------------------------------- ### Requirements[​](https://echo.labstack.com/docs/quick-start#requirements "Direct link to Requirements") To install Echo [Go](https://go.dev/doc/install) 1.13 or higher is required. Go 1.12 has limited support and some middlewares will not be available. Make sure your project folder is outside your $GOPATH. $ mkdir myapp && cd myapp$ go mod init myapp$ go get github.com/labstack/echo/v4 If you are working with Go v1.14 or earlier use: $ GO111MODULE=on go get github.com/labstack/echo/v4 Hello, World![​](https://echo.labstack.com/docs/quick-start#hello-world "Direct link to Hello, World!") -------------------------------------------------------------------------------------------------------- Create `server.go` package mainimport ( "net/http" "github.com/labstack/echo/v4")func main() { e := echo.New() e.GET("/", func(c echo.Context) error { return c.String(http.StatusOK, "Hello, World!") }) e.Logger.Fatal(e.Start(":1323"))} Start server $ go run server.go Browse to [http://localhost:1323](http://localhost:1323/) and you should see Hello, World! on the page. Routing[​](https://echo.labstack.com/docs/quick-start#routing "Direct link to Routing") ---------------------------------------------------------------------------------------- e.POST("/users", saveUser)e.GET("/users/:id", getUser)e.PUT("/users/:id", updateUser)e.DELETE("/users/:id", deleteUser) Path Parameters[​](https://echo.labstack.com/docs/quick-start#path-parameters "Direct link to Path Parameters") ---------------------------------------------------------------------------------------------------------------- // e.GET("/users/:id", getUser)func getUser(c echo.Context) error { // User ID from path `users/:id` id := c.Param("id") return c.String(http.StatusOK, id)} Browse to [http://localhost:1323/users/joe](http://localhost:1323/users/joe) and you should see 'joe' on the page. Query Parameters[​](https://echo.labstack.com/docs/quick-start#query-parameters "Direct link to Query Parameters") ------------------------------------------------------------------------------------------------------------------- `/show?team=x-men&member=wolverine` //e.GET("/show", show)func show(c echo.Context) error { // Get team and member from the query string team := c.QueryParam("team") member := c.QueryParam("member") return c.String(http.StatusOK, "team:" + team + ", member:" + member)} Browse to [http://localhost:1323/show?team=x-men&member=wolverine](http://localhost:1323/show?team=x-men&member=wolverine) and you should see 'team:x-men, member:wolverine' on the page. Form application/x-www-form-urlencoded[​](https://echo.labstack.com/docs/quick-start#form-applicationx-www-form-urlencoded "Direct link to Form application/x-www-form-urlencoded") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ `POST` `/save` | name | value | | --- | --- | | name | Joe Smith | | email | [\[email protected\]](https://echo.labstack.com/cdn-cgi/l/email-protection#cba1a4ae8ba7aaa9b8bfaaa8a0e5a8a4a6) | // e.POST("/save", save)func save(c echo.Context) error { // Get name and email name := c.FormValue("name") email := c.FormValue("email") return c.String(http.StatusOK, "name:" + name + ", email:" + email)} Run the following command: $ curl -d "name=Joe Smith" -d "[email protected]" http://localhost:1323/save// => name:Joe Smith, email:[email protected] Form multipart/form-data[​](https://echo.labstack.com/docs/quick-start#form-multipartform-data "Direct link to Form multipart/form-data") ------------------------------------------------------------------------------------------------------------------------------------------ `POST` `/save` | name | value | | --- | --- | | name | Joe Smith | | avatar | avatar | func save(c echo.Context) error { // Get name name := c.FormValue("name") // Get avatar avatar, err := c.FormFile("avatar") if err != nil { return err } // Source src, err := avatar.Open() if err != nil { return err } defer src.Close() // Destination dst, err := os.Create(avatar.Filename) if err != nil { return err } defer dst.Close() // Copy if _, err = io.Copy(dst, src); err != nil { return err } return c.HTML(http.StatusOK, "Thank you! " + name + "")} Run the following command. $ curl -F "name=Joe Smith" -F "avatar=@/path/to/your/avatar.png" http://localhost:1323/save// => Thank you! Joe Smith For checking uploaded image, run the following command. cd ls avatar.png// => avatar.png Handling Request[​](https://echo.labstack.com/docs/quick-start#handling-request "Direct link to Handling Request") ------------------------------------------------------------------------------------------------------------------- * Bind `json`, `xml`, `form` or `query` payload into Go struct based on `Content-Type` request header. * Render response as `json` or `xml` with status code. type User struct { Name string `json:"name" xml:"name" form:"name" query:"name"` Email string `json:"email" xml:"email" form:"email" query:"email"`}e.POST("/users", func(c echo.Context) error { u := new(User) if err := c.Bind(u); err != nil { return err } return c.JSON(http.StatusCreated, u) // or // return c.XML(http.StatusCreated, u)}) Static Content[​](https://echo.labstack.com/docs/quick-start#static-content "Direct link to Static Content") ------------------------------------------------------------------------------------------------------------- Serve any file from static directory for path `/static/*`. e.Static("/static", "static") [Learn More](https://echo.labstack.com/docs/static-files) [Template Rendering](https://echo.labstack.com/docs/templates) [​](https://echo.labstack.com/docs/quick-start#template-rendering "Direct link to template-rendering") ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Middleware[​](https://echo.labstack.com/docs/quick-start#middleware "Direct link to Middleware") ------------------------------------------------------------------------------------------------- // Root level middlewaree.Use(middleware.Logger())e.Use(middleware.Recover())// Group level middlewareg := e.Group("/admin")g.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) { if username == "joe" && password == "secret" { return true, nil } return false, nil}))// Route level middlewaretrack := func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { println("request to /users") return next(c) }}e.GET("/users", func(c echo.Context) error { return c.String(http.StatusOK, "/users")}, track) * [Installation](https://echo.labstack.com/docs/quick-start#installation) * [Requirements](https://echo.labstack.com/docs/quick-start#requirements) * [Hello, World!](https://echo.labstack.com/docs/quick-start#hello-world) * [Routing](https://echo.labstack.com/docs/quick-start#routing) * [Path Parameters](https://echo.labstack.com/docs/quick-start#path-parameters) * [Query Parameters](https://echo.labstack.com/docs/quick-start#query-parameters) * [Form application/x-www-form-urlencoded](https://echo.labstack.com/docs/quick-start#form-applicationx-www-form-urlencoded) * [Form multipart/form-data](https://echo.labstack.com/docs/quick-start#form-multipartform-data) * [Handling Request](https://echo.labstack.com/docs/quick-start#handling-request) * [Static Content](https://echo.labstack.com/docs/quick-start#static-content) * [Template Rendering](https://echo.labstack.com/docs/quick-start#template-rendering) * [Middleware](https://echo.labstack.com/docs/quick-start#middleware) --- # Routing | Echo [Skip to main content](https://echo.labstack.com/docs/routing#__docusaurus_skipToContent_fallback) On this page Echo's router is based on [radix tree](https://en.wikipedia.org/wiki/Radix_tree) , making route lookup really fast. It leverages [sync pool](https://golang.org/pkg/sync/#Pool) to reuse memory and achieve zero dynamic memory allocation with no GC overhead. Routes can be registered by specifying HTTP method, path and a matching handler. For example, code below registers a route for method `GET`, path `/hello` and a handler which sends `Hello, World!` HTTP response. // Handlerfunc hello(c echo.Context) error { return c.String(http.StatusOK, "Hello, World!")}// Routee.GET("/hello", hello) You can use `Echo.Any(path string, h Handler)` to register a handler for all HTTP methods. If you want to register it for some methods use `Echo.Match(methods []string, path string, h Handler)`. Echo defines handler function as `func(echo.Context) error` where `echo.Context` primarily holds HTTP request and response interfaces. Match-any / wildcard[​](https://echo.labstack.com/docs/routing#match-any--wildcard "Direct link to Match-any / wildcard") -------------------------------------------------------------------------------------------------------------------------- Matches zero or more characters in the path. For example, pattern `/users/*` will match: * `/users/` * `/users/1` * `/users/1/files/1` * `/users/anything...` caution There can be only one effective match-any parameter in route. When route is added with multiple match-any `/v1/*/images/*`. The router matches always the first `*` till the end of request URL i.e. it works as `/v1/*`. Path Matching Order[​](https://echo.labstack.com/docs/routing#path-matching-order "Direct link to Path Matching Order") ------------------------------------------------------------------------------------------------------------------------ * Static * Param * Match any _Example_ e.GET("/users/:id", func(c echo.Context) error { return c.String(http.StatusOK, "/users/:id")})e.GET("/users/new", func(c echo.Context) error { return c.String(http.StatusOK, "/users/new")})e.GET("/users/1/files/*", func(c echo.Context) error { return c.String(http.StatusOK, "/users/1/files/*")}) Above routes would resolve in the following order: * `/users/new` * `/users/:id` * `/users/1/files/*` tip Routes can be written in any order. Group[​](https://echo.labstack.com/docs/routing#group "Direct link to Group") ------------------------------------------------------------------------------ `Echo#Group(prefix string, m ...Middleware) *Group` Routes with common prefix can be grouped to define a new sub-router with optional middleware. In addition to specified middleware group also inherits parent middleware. To add middleware later in the group you can use `Group.Use(m ...Middleware)`. Groups can also be nested. In the code below, we create an admin group which requires basic HTTP authentication for routes `/admin/*`. g := e.Group("/admin")g.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) { if username == "joe" && password == "secret" { return true, nil } return false, nil})) Route Naming[​](https://echo.labstack.com/docs/routing#route-naming "Direct link to Route Naming") --------------------------------------------------------------------------------------------------- Each of the registration methods returns a `Route` object, which can be used to name a route after the registration. For example: route := e.POST("/users", func(c echo.Context) error {})route.Name = "create-user"// or using the inline syntaxe.GET("/users/:id", func(c echo.Context) error {}).Name = "get-user" Route names can be very useful when generating URIs from the templates, where you can't access the handler references or when you have multiple routes with the same handler. URI Building[​](https://echo.labstack.com/docs/routing#uri-building "Direct link to URI Building") --------------------------------------------------------------------------------------------------- `Echo#URI(handler HandlerFunc, params ...interface{})` can be used to generate URI for any handler with specified path parameters. It's helpful to centralize all your URI patterns which ease in refactoring your application. For example, `e.URI(h, 1)` will generate `/users/1` for the route registered below: // Handlerh := func(c echo.Context) error { return c.String(http.StatusOK, "OK")}// Routee.GET("/users/:id", h) In addition to `Echo#URI`, there is also `Echo#Reverse(name string, params ...interface{})` which is used to generate URIs based on the route name. For example a call to `Echo#Reverse("foobar", 1234)` would generate the URI `/users/1234` if the `foobar` route is registered like below: // Handlerh := func(c echo.Context) error { return c.String(http.StatusOK, "OK")}// Routee.GET("/users/:id", h).Name = "foobar" List Routes[​](https://echo.labstack.com/docs/routing#list-routes "Direct link to List Routes") ------------------------------------------------------------------------------------------------ `Echo#Routes() []*Route` can be used to list all registered routes in the order they are defined. Each route contains HTTP method, path and an associated handler. _Example_ // Handlersfunc createUser(c echo.Context) error {}func findUser(c echo.Context) error {}func updateUser(c echo.Context) error {}func deleteUser(c echo.Context) error {}// Routese.POST("/users", createUser)e.GET("/users", findUser)e.PUT("/users", updateUser)e.DELETE("/users", deleteUser) Using the following code you can output all the routes to a JSON file: data, err := json.MarshalIndent(e.Routes(), "", " ")if err != nil { return err}os.WriteFile("routes.json", data, 0644) `routes.json` [ { "method": "POST", "path": "/users", "name": "main.createUser" }, { "method": "GET", "path": "/users", "name": "main.findUser" }, { "method": "PUT", "path": "/users", "name": "main.updateUser" }, { "method": "DELETE", "path": "/users", "name": "main.deleteUser" }] * [Match-any / wildcard](https://echo.labstack.com/docs/routing#match-any--wildcard) * [Path Matching Order](https://echo.labstack.com/docs/routing#path-matching-order) * [Group](https://echo.labstack.com/docs/routing#group) * [Route Naming](https://echo.labstack.com/docs/routing#route-naming) * [URI Building](https://echo.labstack.com/docs/routing#uri-building) * [List Routes](https://echo.labstack.com/docs/routing#list-routes) --- # Body Limit | Echo [Skip to main content](https://echo.labstack.com/docs/middleware/body-limit#__docusaurus_skipToContent_fallback) On this page Body limit middleware sets the maximum allowed size for a request body, if the size exceeds the configured limit, it sends "413 - Request Entity Too Large" response. The body limit is determined based on both `Content-Length` request header and actual content read, which makes it super secure. Limit can be specified as `4x` or `4xB`, where x is one of the multiple from K, M, G, T or P. Usage[​](https://echo.labstack.com/docs/middleware/body-limit#usage "Direct link to Usage") -------------------------------------------------------------------------------------------- e := echo.New()e.Use(middleware.BodyLimit("2M")) Custom Configuration[​](https://echo.labstack.com/docs/middleware/body-limit#custom-configuration "Direct link to Custom Configuration") ----------------------------------------------------------------------------------------------------------------------------------------- ### Usage[​](https://echo.labstack.com/docs/middleware/body-limit#usage-1 "Direct link to Usage") e := echo.New()e.Use(middleware.BodyLimitWithConfig(middleware.BodyLimitConfig{})) Configuration[​](https://echo.labstack.com/docs/middleware/body-limit#configuration "Direct link to Configuration") -------------------------------------------------------------------------------------------------------------------- BodyLimitConfig struct { // Skipper defines a function to skip middleware. Skipper Skipper // Maximum allowed size for a request body, it can be specified // as `4x` or `4xB`, where x is one of the multiple from K, M, G, T or P. Limit string `json:"limit"`} ### Default Configuration[​](https://echo.labstack.com/docs/middleware/body-limit#default-configuration "Direct link to Default Configuration") DefaultBodyLimitConfig = BodyLimitConfig{ Skipper: DefaultSkipper,} * [Usage](https://echo.labstack.com/docs/middleware/body-limit#usage) * [Custom Configuration](https://echo.labstack.com/docs/middleware/body-limit#custom-configuration) * [Usage](https://echo.labstack.com/docs/middleware/body-limit#usage-1) * [Configuration](https://echo.labstack.com/docs/middleware/body-limit#configuration) * [Default Configuration](https://echo.labstack.com/docs/middleware/body-limit#default-configuration) --- # Body Dump | Echo [Skip to main content](https://echo.labstack.com/docs/middleware/body-dump#__docusaurus_skipToContent_fallback) On this page Body dump middleware captures the request and response payload and calls the registered handler. Generally used for debugging/logging purpose. Avoid using it if your request/response payload is huge e.g. file upload/download, but if you still need to, add an exception for your endpoints in the skipper function. Usage[​](https://echo.labstack.com/docs/middleware/body-dump#usage "Direct link to Usage") ------------------------------------------------------------------------------------------- e := echo.New()e.Use(middleware.BodyDump(func(c echo.Context, reqBody, resBody []byte) {})) Custom Configuration[​](https://echo.labstack.com/docs/middleware/body-dump#custom-configuration "Direct link to Custom Configuration") ---------------------------------------------------------------------------------------------------------------------------------------- ### Usage[​](https://echo.labstack.com/docs/middleware/body-dump#usage-1 "Direct link to Usage") e := echo.New()e.Use(middleware.BodyDumpWithConfig(middleware.BodyDumpConfig{})) Configuration[​](https://echo.labstack.com/docs/middleware/body-dump#configuration "Direct link to Configuration") ------------------------------------------------------------------------------------------------------------------- BodyDumpConfig struct { // Skipper defines a function to skip middleware. Skipper Skipper // Handler receives request and response payload. // Required. Handler BodyDumpHandler} ### Default Configuration\*[​](https://echo.labstack.com/docs/middleware/body-dump#default-configuration "Direct link to Default Configuration*") DefaultBodyDumpConfig = BodyDumpConfig{ Skipper: DefaultSkipper,} * [Usage](https://echo.labstack.com/docs/middleware/body-dump#usage) * [Custom Configuration](https://echo.labstack.com/docs/middleware/body-dump#custom-configuration) * [Usage](https://echo.labstack.com/docs/middleware/body-dump#usage-1) * [Configuration](https://echo.labstack.com/docs/middleware/body-dump#configuration) * [Default Configuration\*](https://echo.labstack.com/docs/middleware/body-dump#default-configuration) --- # Static Files | Echo [Skip to main content](https://echo.labstack.com/docs/static-files#__docusaurus_skipToContent_fallback) On this page Images, JavaScript, CSS, PDF, Fonts and so on... Using Static Middleware[​](https://echo.labstack.com/docs/static-files#using-static-middleware "Direct link to Using Static Middleware") ----------------------------------------------------------------------------------------------------------------------------------------- [See](https://echo.labstack.com/docs/middleware/static) Using Echo#Static()[​](https://echo.labstack.com/docs/static-files#using-echostatic "Direct link to Using Echo#Static()") -------------------------------------------------------------------------------------------------------------------------- `Echo#Static(prefix, root string)` registers a new route with path prefix to serve static files from the provided root directory. _Usage 1_ e := echo.New()e.Static("/static", "assets") Example above will serve any file from the assets directory for path `/static/*`. For example, a request to `/static/js/main.js` will fetch and serve `assets/js/main.js` file. _Usage 2_ e := echo.New()e.Static("/", "assets") Example above will serve any file from the assets directory for path `/*`. For example, a request to `/js/main.js` will fetch and serve `assets/js/main.js` file. Using Echo#File()[​](https://echo.labstack.com/docs/static-files#using-echofile "Direct link to Using Echo#File()") -------------------------------------------------------------------------------------------------------------------- `Echo#File(path, file string)` registers a new route with path to serve a static file. _Usage 1_ Serving an index page from `public/index.html` e.File("/", "public/index.html") _Usage 2_ Serving a favicon from `images/favicon.ico` e.File("/favicon.ico", "images/favicon.ico") * [Using Static Middleware](https://echo.labstack.com/docs/static-files#using-static-middleware) * [Using Echo#Static()](https://echo.labstack.com/docs/static-files#using-echostatic) * [Using Echo#File()](https://echo.labstack.com/docs/static-files#using-echofile) --- # Basic Auth | Echo [Skip to main content](https://echo.labstack.com/docs/middleware/basic-auth#__docusaurus_skipToContent_fallback) On this page Basic auth middleware provides an HTTP basic authentication. * For valid credentials it calls the next handler. * For missing or invalid credentials, it sends "401 - Unauthorized" response. Usage[​](https://echo.labstack.com/docs/middleware/basic-auth#usage "Direct link to Usage") -------------------------------------------------------------------------------------------- e.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) { // Be careful to use constant time comparison to prevent timing attacks if subtle.ConstantTimeCompare([]byte(username), []byte("joe")) == 1 && subtle.ConstantTimeCompare([]byte(password), []byte("secret")) == 1 { return true, nil } return false, nil})) Custom Configuration[​](https://echo.labstack.com/docs/middleware/basic-auth#custom-configuration "Direct link to Custom Configuration") ----------------------------------------------------------------------------------------------------------------------------------------- ### Usage[​](https://echo.labstack.com/docs/middleware/basic-auth#usage-1 "Direct link to Usage") e.Use(middleware.BasicAuthWithConfig(middleware.BasicAuthConfig{})) Configuration[​](https://echo.labstack.com/docs/middleware/basic-auth#configuration "Direct link to Configuration") -------------------------------------------------------------------------------------------------------------------- BasicAuthConfig struct { // Skipper defines a function to skip middleware. Skipper Skipper // Validator is a function to validate BasicAuth credentials. // Required. Validator BasicAuthValidator // Realm is a string to define realm attribute of BasicAuth. // Default value "Restricted". Realm string} ### Default Configuration[​](https://echo.labstack.com/docs/middleware/basic-auth#default-configuration "Direct link to Default Configuration") DefaultBasicAuthConfig = BasicAuthConfig{ Skipper: DefaultSkipper,} * [Usage](https://echo.labstack.com/docs/middleware/basic-auth#usage) * [Custom Configuration](https://echo.labstack.com/docs/middleware/basic-auth#custom-configuration) * [Usage](https://echo.labstack.com/docs/middleware/basic-auth#usage-1) * [Configuration](https://echo.labstack.com/docs/middleware/basic-auth#configuration) * [Default Configuration](https://echo.labstack.com/docs/middleware/basic-auth#default-configuration) --- # Start Server | Echo [Skip to main content](https://echo.labstack.com/docs/start-server#__docusaurus_skipToContent_fallback) On this page Echo provides following convenience methods to start the server: * `Echo.Start(address string)` * `Echo.StartTLS(address string, certFile, keyFile interface{})` * `Echo.StartAutoTLS(address string)` * `Echo.StartH2CServer(address string, h2s *http2.Server)` * `Echo.StartServer(s *http.Server)` HTTP Server[​](https://echo.labstack.com/docs/start-server#http-server "Direct link to HTTP Server") ----------------------------------------------------------------------------------------------------- `Echo.Start` is convenience method that starts http server with Echo serving requests. func main() { e := echo.New() // add middleware and routes // ... if err := e.Start(":8080"); err != http.ErrServerClosed { log.Fatal(err) }} Following is equivalent to `Echo.Start` previous example func main() { e := echo.New() // add middleware and routes // ... s := http.Server{ Addr: ":8080", Handler: e, //ReadTimeout: 30 * time.Second, // customize http.Server timeouts } if err := s.ListenAndServe(); err != http.ErrServerClosed { log.Fatal(err) }} HTTPS Server[​](https://echo.labstack.com/docs/start-server#https-server "Direct link to HTTPS Server") -------------------------------------------------------------------------------------------------------- `Echo.StartTLS` is convenience method that starts HTTPS server with Echo serving requests on given address and uses `server.crt` and `server.key` as TLS certificate pair. func main() { e := echo.New() // add middleware and routes // ... if err := e.StartTLS(":8443", "server.crt", "server.key"); err != http.ErrServerClosed { log.Fatal(err) }} Following is equivalent to `Echo.StartTLS` previous example func main() { e := echo.New() // add middleware and routes // ... s := http.Server{ Addr: ":8443", Handler: e, // set Echo as handler TLSConfig: &tls.Config{ //MinVersion: 1, // customize TLS configuration }, //ReadTimeout: 30 * time.Second, // use custom timeouts } if err := s.ListenAndServeTLS("server.crt", "server.key"); err != http.ErrServerClosed { log.Fatal(err) }} Auto TLS Server with Let’s Encrypt[​](https://echo.labstack.com/docs/start-server#auto-tls-server-with-lets-encrypt "Direct link to Auto TLS Server with Let’s Encrypt") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- See [Auto TLS Recipe](https://echo.labstack.com/docs/cookbook/auto-tls#server) HTTP/2 Cleartext Server (HTTP2 over HTTP)[​](https://echo.labstack.com/docs/start-server#http2-cleartext-server-http2-over-http "Direct link to HTTP/2 Cleartext Server (HTTP2 over HTTP)") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- `Echo.StartH2CServer` is convenience method that starts a custom HTTP/2 cleartext server on given address func main() { e := echo.New() // add middleware and routes // ... s := &http2.Server{ MaxConcurrentStreams: 250, MaxReadFrameSize: 1048576, IdleTimeout: 10 * time.Second, } if err := e.StartH2CServer(":8080", s); err != http.ErrServerClosed { log.Fatal(err) }} Following is equivalent to `Echo.StartH2CServer` previous example func main() { e := echo.New() // add middleware and routes // ... h2s := &http2.Server{ MaxConcurrentStreams: 250, MaxReadFrameSize: 1048576, IdleTimeout: 10 * time.Second, } s := http.Server{ Addr: ":8080", Handler: h2c.NewHandler(e, h2s), } if err := s.ListenAndServe(); err != http.ErrServerClosed { log.Fatal(err) }} * [HTTP Server](https://echo.labstack.com/docs/start-server#http-server) * [HTTPS Server](https://echo.labstack.com/docs/start-server#https-server) * [Auto TLS Server with Let’s Encrypt](https://echo.labstack.com/docs/start-server#auto-tls-server-with-lets-encrypt) * [HTTP/2 Cleartext Server (HTTP2 over HTTP)](https://echo.labstack.com/docs/start-server#http2-cleartext-server-http2-over-http) --- # Templates | Echo [Skip to main content](https://echo.labstack.com/docs/templates#__docusaurus_skipToContent_fallback) On this page Rendering[​](https://echo.labstack.com/docs/templates#rendering "Direct link to Rendering") -------------------------------------------------------------------------------------------- `Context#Render(code int, name string, data interface{}) error` renders a template with data and sends a text/html response with status code. Templates can be registered by setting `Echo.Renderer`, allowing us to use any template engine. Example below shows how to use Go `html/template`: 1. Implement `echo.Renderer` interface type Template struct { templates *template.Template}func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error { return t.templates.ExecuteTemplate(w, name, data)} 2. Pre-compile templates `public/views/hello.html` {{define "hello"}}Hello, {{.}}!{{end}} t := &Template{ templates: template.Must(template.ParseGlob("public/views/*.html")),} 3. Register templates e := echo.New()e.Renderer = te.GET("/hello", Hello) 4. Render a template inside your handler func Hello(c echo.Context) error { return c.Render(http.StatusOK, "hello", "World")} Advanced - Calling Echo from templates[​](https://echo.labstack.com/docs/templates#advanced---calling-echo-from-templates "Direct link to Advanced - Calling Echo from templates") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- In certain situations it might be useful to generate URIs from the templates. In order to do so, you need to call `Echo#Reverse` from the templates itself. Golang's `html/template` package is not the best suited for this job, but this can be done in two ways: by providing a common method on all objects passed to templates or by passing `map[string]interface{}` and augmenting this object in the custom renderer. Given the flexibility of the latter approach, here is a sample program: `template.html`

Hello {{index . "name"}}

{{ with $x := index . "reverse" }} {{ call $x "foobar" }} <-- this will call the $x with parameter "foobar" {{ end }}

`server.go` package mainimport ( "html/template" "io" "net/http" "github.com/labstack/echo/v4")// TemplateRenderer is a custom html/template renderer for Echo frameworktype TemplateRenderer struct { templates *template.Template}// Render renders a template documentfunc (t *TemplateRenderer) Render(w io.Writer, name string, data interface{}, c echo.Context) error { // Add global methods if data is a map if viewContext, isMap := data.(map[string]interface{}); isMap { viewContext["reverse"] = c.Echo().Reverse } return t.templates.ExecuteTemplate(w, name, data)}func main() { e := echo.New() renderer := &TemplateRenderer{ templates: template.Must(template.ParseGlob("*.html")), } e.Renderer = renderer // Named route "foobar" e.GET("/something", func(c echo.Context) error { return c.Render(http.StatusOK, "template.html", map[string]interface{}{ "name": "Dolly!", }) }).Name = "foobar" e.Logger.Fatal(e.Start(":8000"))} * [Rendering](https://echo.labstack.com/docs/templates#rendering) * [Advanced - Calling Echo from templates](https://echo.labstack.com/docs/templates#advanced---calling-echo-from-templates) --- # Context Timeout | Echo [Skip to main content](https://echo.labstack.com/docs/middleware/context-timeout#__docusaurus_skipToContent_fallback) On this page Timeout middleware is used to timeout request context within a predefined period so context aware methods could return early. Usage[​](https://echo.labstack.com/docs/middleware/context-timeout#usage "Direct link to Usage") ------------------------------------------------------------------------------------------------- e.Use(middleware.ContextTimeout(60 * time.Second)) Custom Configuration[​](https://echo.labstack.com/docs/middleware/context-timeout#custom-configuration "Direct link to Custom Configuration") ---------------------------------------------------------------------------------------------------------------------------------------------- e.Use(middleware.ContextTimeoutWithConfig(middleware.ContextTimeoutConfig{ // Skipper defines a function to skip middleware. Skipper: nil, // ErrorHandler is a function when error aries in middleware execution. ErrorHandler: nil, // Timeout configures a timeout for the middleware, defaults to 0 for no timeout Timeout: 60 * time.Second,})) * [Usage](https://echo.labstack.com/docs/middleware/context-timeout#usage) * [Custom Configuration](https://echo.labstack.com/docs/middleware/context-timeout#custom-configuration) --- # Response | Echo [Skip to main content](https://echo.labstack.com/docs/response#__docusaurus_skipToContent_fallback) On this page Send String[​](https://echo.labstack.com/docs/response#send-string "Direct link to Send String") ------------------------------------------------------------------------------------------------- `Context#String(code int, s string)` can be used to send plain text response with status code. _Example_ func(c echo.Context) error { return c.String(http.StatusOK, "Hello, World!")} Send HTML (Reference to templates)[​](https://echo.labstack.com/docs/response#send-html-reference-to-templates "Direct link to Send HTML (Reference to templates)") -------------------------------------------------------------------------------------------------------------------------------------------------------------------- `Context#HTML(code int, html string)` can be used to send simple HTML response with status code. If you are looking to send dynamically generate HTML see [templates](https://echo.labstack.com/docs/templates) . _Example_ func(c echo.Context) error { return c.HTML(http.StatusOK, "Hello, World!")} ### Send HTML Blob[​](https://echo.labstack.com/docs/response#send-html-blob "Direct link to Send HTML Blob") `Context#HTMLBlob(code int, b []byte)` can be used to send HTML blob with status code. You may find it handy using with a template engine which outputs `[]byte`. Render Template[​](https://echo.labstack.com/docs/response#render-template "Direct link to Render Template") ------------------------------------------------------------------------------------------------------------- [Learn more](https://echo.labstack.com/docs/templates) Send JSON[​](https://echo.labstack.com/docs/response#send-json "Direct link to Send JSON") ------------------------------------------------------------------------------------------- `Context#JSON(code int, i interface{})` can be used to encode a provided Go type into JSON and send it as response with status code. _Example_ // Usertype User struct { Name string `json:"name" xml:"name"` Email string `json:"email" xml:"email"`}// Handlerfunc(c echo.Context) error { u := &User{ Name: "Jon", Email: "[email protected]", } return c.JSON(http.StatusOK, u)} ### Stream JSON[​](https://echo.labstack.com/docs/response#stream-json "Direct link to Stream JSON") `Context#JSON()` internally uses `json.Marshal` which may not be efficient to large JSON, in that case you can directly stream JSON. _Example_ func(c echo.Context) error { u := &User{ Name: "Jon", Email: "[email protected]", } c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8) c.Response().WriteHeader(http.StatusOK) return json.NewEncoder(c.Response()).Encode(u)} ### JSON Pretty[​](https://echo.labstack.com/docs/response#json-pretty "Direct link to JSON Pretty") `Context#JSONPretty(code int, i interface{}, indent string)` can be used to a send a JSON response which is pretty printed based on indent, which could be spaces or tabs. Example below sends a pretty print JSON indented with spaces: func(c echo.Context) error { u := &User{ Name: "Jon", Email: "[email protected]", } return c.JSONPretty(http.StatusOK, u, " ")} { "email": "[email protected]", "name": "Jon"} tip You can also use `Context#JSON()` to output a pretty printed JSON (indented with spaces) by appending `pretty` in the request URL query string. _Example_ curl http://localhost:1323/users/1?pretty ### JSON Blob[​](https://echo.labstack.com/docs/response#json-blob "Direct link to JSON Blob") `Context#JSONBlob(code int, b []byte)` can be used to send pre-encoded JSON blob directly from external source, for example, database. _Example_ func(c echo.Context) error { encodedJSON := []byte{} // Encoded JSON from external source return c.JSONBlob(http.StatusOK, encodedJSON)} Send JSONP[​](https://echo.labstack.com/docs/response#send-jsonp "Direct link to Send JSONP") ---------------------------------------------------------------------------------------------- `Context#JSONP(code int, callback string, i interface{})` can be used to encode a provided Go type into JSON and send it as JSONP payload constructed using a callback, with status code. [_Example_](https://echo.labstack.com/docs/cookbook/jsonp) Send XML[​](https://echo.labstack.com/docs/response#send-xml "Direct link to Send XML") ---------------------------------------------------------------------------------------- `Context#XML(code int, i interface{})` can be used to encode a provided Go type into XML and send it as response with status code. _Example_ func(c echo.Context) error { u := &User{ Name: "Jon", Email: "[email protected]", } return c.XML(http.StatusOK, u)} ### Stream XML[​](https://echo.labstack.com/docs/response#stream-xml "Direct link to Stream XML") `Context#XML` internally uses `xml.Marshal` which may not be efficient to large XML, in that case you can directly stream XML. _Example_ func(c echo.Context) error { u := &User{ Name: "Jon", Email: "[email protected]", } c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationXMLCharsetUTF8) c.Response().WriteHeader(http.StatusOK) return xml.NewEncoder(c.Response()).Encode(u)} ### XML Pretty[​](https://echo.labstack.com/docs/response#xml-pretty "Direct link to XML Pretty") `Context#XMLPretty(code int, i interface{}, indent string)` can be used to a send an XML response which is pretty printed based on indent, which could be spaces or tabs. Example below sends a pretty print XML indented with spaces: func(c echo.Context) error { u := &User{ Name: "Jon", Email: "[email protected]", } return c.XMLPretty(http.StatusOK, u, " ")} Jon [email protected] tip You can also use `Context#XML()` to output a pretty printed XML (indented with spaces) by appending `pretty` in the request URL query string. _Example_ curl http://localhost:1323/users/1?pretty ### XML Blob[​](https://echo.labstack.com/docs/response#xml-blob "Direct link to XML Blob") `Context#XMLBlob(code int, b []byte)` can be used to send pre-encoded XML blob directly from external source, for example, database. _Example_ func(c echo.Context) error { encodedXML := []byte{} // Encoded XML from external source return c.XMLBlob(http.StatusOK, encodedXML)} Send File[​](https://echo.labstack.com/docs/response#send-file "Direct link to Send File") ------------------------------------------------------------------------------------------- `Context#File(file string)` can be used to send the content of file as response. It automatically sets the correct content type and handles caching gracefully. _Example_ func(c echo.Context) error { return c.File("")} Send Attachment[​](https://echo.labstack.com/docs/response#send-attachment "Direct link to Send Attachment") ------------------------------------------------------------------------------------------------------------- `Context#Attachment(file, name string)` is similar to `File()` except that it is used to send file as `Content-Disposition: attachment` with provided name. _Example_ func(c echo.Context) error { return c.Attachment("", "")} Send Inline[​](https://echo.labstack.com/docs/response#send-inline "Direct link to Send Inline") ------------------------------------------------------------------------------------------------- `Context#Inline(file, name string)` is similar to `File()` except that it is used to send file as `Content-Disposition: inline` with provided name. _Example_ func(c echo.Context) error { return c.Inline("")} Send Blob[​](https://echo.labstack.com/docs/response#send-blob "Direct link to Send Blob") ------------------------------------------------------------------------------------------- `Context#Blob(code int, contentType string, b []byte)` can be used to send an arbitrary data response with provided content type and status code. _Example_ func(c echo.Context) (err error) { data := []byte(`0306703,0035866,NO_ACTION,06/19/2006 0086003,"0005866",UPDATED,06/19/2006`) return c.Blob(http.StatusOK, "text/csv", data)} Send Stream[​](https://echo.labstack.com/docs/response#send-stream "Direct link to Send Stream") ------------------------------------------------------------------------------------------------- `Context#Stream(code int, contentType string, r io.Reader)` can be used to send an arbitrary data stream response with provided content type, `io.Reader` and status code. _Example_ func(c echo.Context) error { f, err := os.Open("") if err != nil { return err } defer f.Close() return c.Stream(http.StatusOK, "image/png", f)} Send No Content[​](https://echo.labstack.com/docs/response#send-no-content "Direct link to Send No Content") ------------------------------------------------------------------------------------------------------------- `Context#NoContent(code int)` can be used to send empty body with status code. _Example_ func(c echo.Context) error { return c.NoContent(http.StatusOK)} Redirect Request[​](https://echo.labstack.com/docs/response#redirect-request "Direct link to Redirect Request") ---------------------------------------------------------------------------------------------------------------- `Context#Redirect(code int, url string)` can be used to redirect the request to a provided URL with status code. _Example_ func(c echo.Context) error { return c.Redirect(http.StatusMovedPermanently, "")} Hooks[​](https://echo.labstack.com/docs/response#hooks "Direct link to Hooks") ------------------------------------------------------------------------------- ### Before Response[​](https://echo.labstack.com/docs/response#before-response "Direct link to Before Response") `Context#Response#Before(func())` can be used to register a function which is called just before the response is written. ### After Response[​](https://echo.labstack.com/docs/response#after-response "Direct link to After Response") `Context#Response#After(func())` can be used to register a function which is called just after the response is written. If the "Content-Length" is unknown, none of the after function is executed. _Example_ func(c echo.Context) error { c.Response().Before(func() { println("before response") }) c.Response().After(func() { println("after response") }) return c.NoContent(http.StatusNoContent)} tip It is possible to register multiple Before and After functions. * [Send String](https://echo.labstack.com/docs/response#send-string) * [Send HTML (Reference to templates)](https://echo.labstack.com/docs/response#send-html-reference-to-templates) * [Send HTML Blob](https://echo.labstack.com/docs/response#send-html-blob) * [Render Template](https://echo.labstack.com/docs/response#render-template) * [Send JSON](https://echo.labstack.com/docs/response#send-json) * [Stream JSON](https://echo.labstack.com/docs/response#stream-json) * [JSON Pretty](https://echo.labstack.com/docs/response#json-pretty) * [JSON Blob](https://echo.labstack.com/docs/response#json-blob) * [Send JSONP](https://echo.labstack.com/docs/response#send-jsonp) * [Send XML](https://echo.labstack.com/docs/response#send-xml) * [Stream XML](https://echo.labstack.com/docs/response#stream-xml) * [XML Pretty](https://echo.labstack.com/docs/response#xml-pretty) * [XML Blob](https://echo.labstack.com/docs/response#xml-blob) * [Send File](https://echo.labstack.com/docs/response#send-file) * [Send Attachment](https://echo.labstack.com/docs/response#send-attachment) * [Send Inline](https://echo.labstack.com/docs/response#send-inline) * [Send Blob](https://echo.labstack.com/docs/response#send-blob) * [Send Stream](https://echo.labstack.com/docs/response#send-stream) * [Send No Content](https://echo.labstack.com/docs/response#send-no-content) * [Redirect Request](https://echo.labstack.com/docs/response#redirect-request) * [Hooks](https://echo.labstack.com/docs/response#hooks) * [Before Response](https://echo.labstack.com/docs/response#before-response) * [After Response](https://echo.labstack.com/docs/response#after-response) --- # Testing | Echo [Skip to main content](https://echo.labstack.com/docs/testing#__docusaurus_skipToContent_fallback) On this page Testing Handler[​](https://echo.labstack.com/docs/testing#testing-handler "Direct link to Testing Handler") ------------------------------------------------------------------------------------------------------------ `GET` `/users/:id` Handler below retrieves user by id from the database. If user is not found it returns `404` error with a message. ### CreateUser[​](https://echo.labstack.com/docs/testing#createuser "Direct link to CreateUser") `POST` `/users` * Accepts JSON payload * On success `201 - Created` * On error `500 - Internal Server Error` ### GetUser[​](https://echo.labstack.com/docs/testing#getuser "Direct link to GetUser") `GET` `/users/:email` * On success `200 - OK` * On error `404 - Not Found` if user is not found otherwise `500 - Internal Server Error` `handler.go` package handlerimport ( "net/http" "github.com/labstack/echo/v4")type ( User struct { Name string `json:"name" form:"name"` Email string `json:"email" form:"email"` } handler struct { db map[string]*User })func (h *handler) createUser(c echo.Context) error { u := new(User) if err := c.Bind(u); err != nil { return err } return c.JSON(http.StatusCreated, u)}func (h *handler) getUser(c echo.Context) error { email := c.Param("email") user := h.db[email] if user == nil { return echo.NewHTTPError(http.StatusNotFound, "user not found") } return c.JSON(http.StatusOK, user)} `handler_test.go` package handlerimport ( "net/http" "net/http/httptest" "strings" "testing" "github.com/labstack/echo/v4" "github.com/stretchr/testify/assert")var ( mockDB = map[string]*User{ "[email protected]": &User{"Jon Snow", "[email protected]"}, } userJSON = `{"name":"Jon Snow","email":"[email protected]"}`)func TestCreateUser(t *testing.T) { // Setup e := echo.New() req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(userJSON)) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) rec := httptest.NewRecorder() c := e.NewContext(req, rec) h := &handler{mockDB} // Assertions if assert.NoError(t, h.createUser(c)) { assert.Equal(t, http.StatusCreated, rec.Code) assert.Equal(t, userJSON, rec.Body.String()) }}func TestGetUser(t *testing.T) { // Setup e := echo.New() req := httptest.NewRequest(http.MethodGet, "/", nil) rec := httptest.NewRecorder() c := e.NewContext(req, rec) c.SetPath("/users/:email") c.SetParamNames("email") c.SetParamValues("[email protected]") h := &handler{mockDB} // Assertions if assert.NoError(t, h.getUser(c)) { assert.Equal(t, http.StatusOK, rec.Code) assert.Equal(t, userJSON, rec.Body.String()) }} ### Using Form Payload[​](https://echo.labstack.com/docs/testing#using-form-payload "Direct link to Using Form Payload") // import "net/url"f := make(url.Values)f.Set("name", "Jon Snow")f.Set("email", "[email protected]")req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(f.Encode()))req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationForm) ### Setting Path Params[​](https://echo.labstack.com/docs/testing#setting-path-params "Direct link to Setting Path Params") c.SetParamNames("id", "email")c.SetParamValues("1", "[email protected]") ### Setting Query Params[​](https://echo.labstack.com/docs/testing#setting-query-params "Direct link to Setting Query Params") // import "net/url"q := make(url.Values)q.Set("email", "[email protected]")req := httptest.NewRequest(http.MethodGet, "/?"+q.Encode(), nil) Testing Middleware[​](https://echo.labstack.com/docs/testing#testing-middleware "Direct link to Testing Middleware") --------------------------------------------------------------------------------------------------------------------- _TBD_ For now you can look into built-in middleware [test cases](https://github.com/labstack/echo/tree/master/middleware) . * [Testing Handler](https://echo.labstack.com/docs/testing#testing-handler) * [CreateUser](https://echo.labstack.com/docs/testing#createuser) * [GetUser](https://echo.labstack.com/docs/testing#getuser) * [Using Form Payload](https://echo.labstack.com/docs/testing#using-form-payload) * [Setting Path Params](https://echo.labstack.com/docs/testing#setting-path-params) * [Setting Query Params](https://echo.labstack.com/docs/testing#setting-query-params) * [Testing Middleware](https://echo.labstack.com/docs/testing#testing-middleware) --- # Casbin Auth | Echo [Skip to main content](https://echo.labstack.com/docs/middleware/casbin-auth#__docusaurus_skipToContent_fallback) On this page note Echo community contribution [Casbin](https://github.com/casbin/casbin) is a powerful and efficient open-source access control library for Go. It provides support for enforcing authorization based on various models. So far, the access control models supported by Casbin are: * ACL (Access Control List) * ACL with superuser * ACL without users: especially useful for systems that don't have authentication or user log-ins. * ACL without resources: some scenarios may target for a type of resources instead of an individual resource by using permissions like write-article, read-log. It doesn't control the access to a specific article or log. * RBAC (Role-Based Access Control) * RBAC with resource roles: both users and resources can have roles (or groups) at the same time. * RBAC with domains/tenants: users can have different role sets for different domains/tenants. * ABAC (Attribute-Based Access Control) * RESTful * Deny-override: both allow and deny authorizations are supported, deny overrides the allow. info Currently, only HTTP basic authentication is supported. Dependencies[​](https://echo.labstack.com/docs/middleware/casbin-auth#dependencies "Direct link to Dependencies") ------------------------------------------------------------------------------------------------------------------ import ( "github.com/casbin/casbin" casbin_mw "github.com/labstack/echo-contrib/casbin") Usage[​](https://echo.labstack.com/docs/middleware/casbin-auth#usage "Direct link to Usage") --------------------------------------------------------------------------------------------- e := echo.New()enforcer, err := casbin.NewEnforcer("casbin_auth_model.conf", "casbin_auth_policy.csv")e.Use(casbin_mw.Middleware(enforcer)) For syntax, see: [Syntax for Models](https://casbin.org/docs/syntax-for-models) . Custom Configuration[​](https://echo.labstack.com/docs/middleware/casbin-auth#custom-configuration "Direct link to Custom Configuration") ------------------------------------------------------------------------------------------------------------------------------------------ ### Usage[​](https://echo.labstack.com/docs/middleware/casbin-auth#usage-1 "Direct link to Usage") e := echo.New()ce := casbin.NewEnforcer("casbin_auth_model.conf", "")ce.AddRoleForUser("alice", "admin")ce.AddPolicy(...)e.Use(casbin_mw.MiddlewareWithConfig(casbin_mw.Config{ Enforcer: ce,})) Configuration[​](https://echo.labstack.com/docs/middleware/casbin-auth#configuration "Direct link to Configuration") --------------------------------------------------------------------------------------------------------------------- // Config defines the config for CasbinAuth middleware.Config struct { // Skipper defines a function to skip middleware. Skipper middleware.Skipper // Enforcer CasbinAuth main rule. // Required. Enforcer *casbin.Enforcer} ### Default Configuration[​](https://echo.labstack.com/docs/middleware/casbin-auth#default-configuration "Direct link to Default Configuration") // DefaultConfig is the default CasbinAuth middleware config.DefaultConfig = Config{ Skipper: middleware.DefaultSkipper,} * [Dependencies](https://echo.labstack.com/docs/middleware/casbin-auth#dependencies) * [Usage](https://echo.labstack.com/docs/middleware/casbin-auth#usage) * [Custom Configuration](https://echo.labstack.com/docs/middleware/casbin-auth#custom-configuration) * [Usage](https://echo.labstack.com/docs/middleware/casbin-auth#usage-1) * [Configuration](https://echo.labstack.com/docs/middleware/casbin-auth#configuration) * [Default Configuration](https://echo.labstack.com/docs/middleware/casbin-auth#default-configuration) --- # CORS | Echo [Skip to main content](https://echo.labstack.com/docs/middleware/cors#__docusaurus_skipToContent_fallback) On this page CORS middleware implements [CORS](http://www.w3.org/TR/cors) specification. CORS gives web servers cross-domain access controls, which enable secure cross-domain data transfers. Usage[​](https://echo.labstack.com/docs/middleware/cors#usage "Direct link to Usage") -------------------------------------------------------------------------------------- e.Use(middleware.CORS()) Custom Configuration[​](https://echo.labstack.com/docs/middleware/cors#custom-configuration "Direct link to Custom Configuration") ----------------------------------------------------------------------------------------------------------------------------------- ### Usage[​](https://echo.labstack.com/docs/middleware/cors#usage-1 "Direct link to Usage") e := echo.New()e.Use(middleware.CORSWithConfig(middleware.CORSConfig{ AllowOrigins: []string{"https://labstack.com", "https://labstack.net"}, AllowHeaders: []string{echo.HeaderOrigin, echo.HeaderContentType, echo.HeaderAccept},})) Configuration[​](https://echo.labstack.com/docs/middleware/cors#configuration "Direct link to Configuration") -------------------------------------------------------------------------------------------------------------- CORSConfig struct { // Skipper defines a function to skip middleware. Skipper Skipper // AllowOrigin defines a list of origins that may access the resource. // Optional. Default value []string{"*"}. AllowOrigins []string `yaml:"allow_origins"` // AllowOriginFunc is a custom function to validate the origin. It takes the // origin as an argument and returns true if allowed or false otherwise. If // an error is returned, it is returned by the handler. If this option is // set, AllowOrigins is ignored. // Optional. AllowOriginFunc func(origin string) (bool, error) `yaml:"allow_origin_func"` // AllowMethods defines a list methods allowed when accessing the resource. // This is used in response to a preflight request. // Optional. Default value DefaultCORSConfig.AllowMethods. AllowMethods []string `yaml:"allow_methods"` // AllowHeaders defines a list of request headers that can be used when // making the actual request. This is in response to a preflight request. // Optional. Default value []string{}. AllowHeaders []string `yaml:"allow_headers"` // AllowCredentials indicates whether or not the response to the request // can be exposed when the credentials flag is true. When used as part of // a response to a preflight request, this indicates whether or not the // actual request can be made using credentials. // Optional. Default value false. AllowCredentials bool `yaml:"allow_credentials"` // ExposeHeaders defines a whitelist headers that clients are allowed to // access. // Optional. Default value []string{}. ExposeHeaders []string `yaml:"expose_headers"` // MaxAge indicates how long (in seconds) the results of a preflight request // can be cached. // Optional. Default value 0. MaxAge int `yaml:"max_age"`} ### Default Configuration[​](https://echo.labstack.com/docs/middleware/cors#default-configuration "Direct link to Default Configuration") DefaultCORSConfig = CORSConfig{ Skipper: DefaultSkipper, AllowOrigins: []string{"*"}, AllowMethods: []string{http.MethodGet, http.MethodHead, http.MethodPut, http.MethodPatch, http.MethodPost, http.MethodDelete},} * [Usage](https://echo.labstack.com/docs/middleware/cors#usage) * [Custom Configuration](https://echo.labstack.com/docs/middleware/cors#custom-configuration) * [Usage](https://echo.labstack.com/docs/middleware/cors#usage-1) * [Configuration](https://echo.labstack.com/docs/middleware/cors#configuration) * [Default Configuration](https://echo.labstack.com/docs/middleware/cors#default-configuration) --- # Decompress | Echo [Skip to main content](https://echo.labstack.com/docs/middleware/decompress#__docusaurus_skipToContent_fallback) On this page Decompress middleware decompresses HTTP request if Content-Encoding header is set to gzip. note The body will be decompressed in memory and consume it for the lifetime of the request (and garbage collection). Usage[​](https://echo.labstack.com/docs/middleware/decompress#usage "Direct link to Usage") -------------------------------------------------------------------------------------------- e.Use(middleware.Decompress()) Custom Configuration[​](https://echo.labstack.com/docs/middleware/decompress#custom-configuration "Direct link to Custom Configuration") ----------------------------------------------------------------------------------------------------------------------------------------- ### Usage[​](https://echo.labstack.com/docs/middleware/decompress#usage-1 "Direct link to Usage") e := echo.New()e.Use(middleware.DecompressWithConfig(middleware.DecompressConfig{ Skipper: Skipper})) Configuration[​](https://echo.labstack.com/docs/middleware/decompress#configuration "Direct link to Configuration") -------------------------------------------------------------------------------------------------------------------- DecompressConfig struct { // Skipper defines a function to skip middleware. Skipper Skipper} ### Default Configuration[​](https://echo.labstack.com/docs/middleware/decompress#default-configuration "Direct link to Default Configuration") DefaultDecompressConfig = DecompressConfig{ Skipper: DefaultSkipper,} * [Usage](https://echo.labstack.com/docs/middleware/decompress#usage) * [Custom Configuration](https://echo.labstack.com/docs/middleware/decompress#custom-configuration) * [Usage](https://echo.labstack.com/docs/middleware/decompress#usage-1) * [Configuration](https://echo.labstack.com/docs/middleware/decompress#configuration) * [Default Configuration](https://echo.labstack.com/docs/middleware/decompress#default-configuration) --- # CSRF | Echo [Skip to main content](https://echo.labstack.com/docs/middleware/csrf#__docusaurus_skipToContent_fallback) On this page Cross-site request forgery, also known as one-click attack or session riding and abbreviated as CSRF (sometimes pronounced sea-surf) or XSRF, is a type of malicious exploit of a website where unauthorized commands are transmitted from a user that the website trusts. Usage[​](https://echo.labstack.com/docs/middleware/csrf#usage "Direct link to Usage") -------------------------------------------------------------------------------------- e.Use(middleware.CSRF()) Custom Configuration[​](https://echo.labstack.com/docs/middleware/csrf#custom-configuration "Direct link to Custom Configuration") ----------------------------------------------------------------------------------------------------------------------------------- ### Usage[​](https://echo.labstack.com/docs/middleware/csrf#usage-1 "Direct link to Usage") e := echo.New()e.Use(middleware.CSRFWithConfig(middleware.CSRFConfig{ TokenLookup: "header:X-XSRF-TOKEN",})) Example above uses `X-XSRF-TOKEN` request header to extract CSRF token. _Example Configuration that reads token from Cookie_ middleware.CSRFWithConfig(middleware.CSRFConfig{ TokenLookup: "cookie:_csrf", CookiePath: "/", CookieDomain: "example.com", CookieSecure: true, CookieHTTPOnly: true, CookieSameSite: http.SameSiteStrictMode,}) Accessing CSRF Token[​](https://echo.labstack.com/docs/middleware/csrf#accessing-csrf-token "Direct link to Accessing CSRF Token") ----------------------------------------------------------------------------------------------------------------------------------- ### Server-side[​](https://echo.labstack.com/docs/middleware/csrf#server-side "Direct link to Server-side") CSRF token can be accessed from `Echo#Context` using `ContextKey` and passed to the client via template. ### Client-side[​](https://echo.labstack.com/docs/middleware/csrf#client-side "Direct link to Client-side") CSRF token can be accessed from CSRF cookie. Configuration[​](https://echo.labstack.com/docs/middleware/csrf#configuration "Direct link to Configuration") -------------------------------------------------------------------------------------------------------------- CSRFConfig struct { // Skipper defines a function to skip middleware. Skipper Skipper // TokenLength is the length of the generated token. TokenLength uint8 `json:"token_length"` // Optional. Default value 32. // TokenLookup is a string in the form of ":" that is used // to extract token from the request. // Optional. Default value "header:X-CSRF-Token". // Possible values: // - "header:" // - "form:" // - "query:" // - "cookie:" TokenLookup string `json:"token_lookup"` // Context key to store generated CSRF token into context. // Optional. Default value "csrf". ContextKey string `json:"context_key"` // Name of the CSRF cookie. This cookie will store CSRF token. // Optional. Default value "_csrf". CookieName string `json:"cookie_name"` // Domain of the CSRF cookie. // Optional. Default value none. CookieDomain string `json:"cookie_domain"` // Path of the CSRF cookie. // Optional. Default value none. CookiePath string `json:"cookie_path"` // Max age (in seconds) of the CSRF cookie. // Optional. Default value 86400 (24hr). CookieMaxAge int `json:"cookie_max_age"` // Indicates if CSRF cookie is secure. // Optional. Default value false. CookieSecure bool `json:"cookie_secure"` // Indicates if CSRF cookie is HTTP only. // Optional. Default value false. CookieHTTPOnly bool `json:"cookie_http_only"`} ### Default Configuration[​](https://echo.labstack.com/docs/middleware/csrf#default-configuration "Direct link to Default Configuration") DefaultCSRFConfig = CSRFConfig{ Skipper: DefaultSkipper, TokenLength: 32, TokenLookup: "header:" + echo.HeaderXCSRFToken, ContextKey: "csrf", CookieName: "_csrf", CookieMaxAge: 86400,} * [Usage](https://echo.labstack.com/docs/middleware/csrf#usage) * [Custom Configuration](https://echo.labstack.com/docs/middleware/csrf#custom-configuration) * [Usage](https://echo.labstack.com/docs/middleware/csrf#usage-1) * [Accessing CSRF Token](https://echo.labstack.com/docs/middleware/csrf#accessing-csrf-token) * [Server-side](https://echo.labstack.com/docs/middleware/csrf#server-side) * [Client-side](https://echo.labstack.com/docs/middleware/csrf#client-side) * [Configuration](https://echo.labstack.com/docs/middleware/csrf#configuration) * [Default Configuration](https://echo.labstack.com/docs/middleware/csrf#default-configuration) --- # Gzip | Echo [Skip to main content](https://echo.labstack.com/docs/middleware/gzip#__docusaurus_skipToContent_fallback) On this page Gzip middleware compresses HTTP response using gzip compression scheme. Usage[​](https://echo.labstack.com/docs/middleware/gzip#usage "Direct link to Usage") -------------------------------------------------------------------------------------- `e.Use(middleware.Gzip())` Custom Configuration[​](https://echo.labstack.com/docs/middleware/gzip#custom-configuration "Direct link to Custom Configuration") ----------------------------------------------------------------------------------------------------------------------------------- ### Usage[​](https://echo.labstack.com/docs/middleware/gzip#usage-1 "Direct link to Usage") e := echo.New()e.Use(middleware.GzipWithConfig(middleware.GzipConfig{ Level: 5,})) tip A middleware skipper can be passed to avoid gzip to certain URL(s). #### Example[​](https://echo.labstack.com/docs/middleware/gzip#example "Direct link to Example") e := echo.New()e.Use(middleware.GzipWithConfig(middleware.GzipConfig{ Skipper: func(c echo.Context) bool { return strings.Contains(c.Path(), "metrics") // Change "metrics" for your own path },})) Configuration[​](https://echo.labstack.com/docs/middleware/gzip#configuration "Direct link to Configuration") -------------------------------------------------------------------------------------------------------------- GzipConfig struct { // Skipper defines a function to skip middleware. Skipper Skipper // Gzip compression level. // Optional. Default value -1. Level int `json:"level"`} ### Default Configuration[​](https://echo.labstack.com/docs/middleware/gzip#default-configuration "Direct link to Default Configuration") DefaultGzipConfig = GzipConfig{ Skipper: DefaultSkipper, Level: -1,} * [Usage](https://echo.labstack.com/docs/middleware/gzip#usage) * [Custom Configuration](https://echo.labstack.com/docs/middleware/gzip#custom-configuration) * [Usage](https://echo.labstack.com/docs/middleware/gzip#usage-1) * [Configuration](https://echo.labstack.com/docs/middleware/gzip#configuration) * [Default Configuration](https://echo.labstack.com/docs/middleware/gzip#default-configuration) --- # Method Override | Echo [Skip to main content](https://echo.labstack.com/docs/middleware/method-override#__docusaurus_skipToContent_fallback) On this page Method override middleware checks for the overridden method from the request and uses it instead of the original method. info For security reasons, only `POST` method can be overridden. Usage[​](https://echo.labstack.com/docs/middleware/method-override#usage "Direct link to Usage") ------------------------------------------------------------------------------------------------- e.Pre(middleware.MethodOverride()) Custom Configuration[​](https://echo.labstack.com/docs/middleware/method-override#custom-configuration "Direct link to Custom Configuration") ---------------------------------------------------------------------------------------------------------------------------------------------- ### Usage[​](https://echo.labstack.com/docs/middleware/method-override#usage-1 "Direct link to Usage") e := echo.New()e.Pre(middleware.MethodOverrideWithConfig(middleware.MethodOverrideConfig{ Getter: middleware.MethodFromForm("_method"),})) Configuration[​](https://echo.labstack.com/docs/middleware/method-override#configuration "Direct link to Configuration") ------------------------------------------------------------------------------------------------------------------------- MethodOverrideConfig struct { // Skipper defines a function to skip middleware. Skipper Skipper // Getter is a function that gets overridden method from the request. // Optional. Default values MethodFromHeader(echo.HeaderXHTTPMethodOverride). Getter MethodOverrideGetter} ### Default Configuration[​](https://echo.labstack.com/docs/middleware/method-override#default-configuration "Direct link to Default Configuration") DefaultMethodOverrideConfig = MethodOverrideConfig{ Skipper: DefaultSkipper, Getter: MethodFromHeader(echo.HeaderXHTTPMethodOverride),} * [Usage](https://echo.labstack.com/docs/middleware/method-override#usage) * [Custom Configuration](https://echo.labstack.com/docs/middleware/method-override#custom-configuration) * [Usage](https://echo.labstack.com/docs/middleware/method-override#usage-1) * [Configuration](https://echo.labstack.com/docs/middleware/method-override#configuration) * [Default Configuration](https://echo.labstack.com/docs/middleware/method-override#default-configuration) --- # Key Auth | Echo [Skip to main content](https://echo.labstack.com/docs/middleware/key-auth#__docusaurus_skipToContent_fallback) On this page Key auth middleware provides a key based authentication. * For valid key it calls the next handler. * For invalid key, it sends "401 - Unauthorized" response. * For missing key, it sends "400 - Bad Request" response. Usage[​](https://echo.labstack.com/docs/middleware/key-auth#usage "Direct link to Usage") ------------------------------------------------------------------------------------------ e.Use(middleware.KeyAuth(func(key string, c echo.Context) (bool, error) { return key == "valid-key", nil})) Custom Configuration[​](https://echo.labstack.com/docs/middleware/key-auth#custom-configuration "Direct link to Custom Configuration") --------------------------------------------------------------------------------------------------------------------------------------- ### Usage[​](https://echo.labstack.com/docs/middleware/key-auth#usage-1 "Direct link to Usage") e := echo.New()e.Use(middleware.KeyAuthWithConfig(middleware.KeyAuthConfig{ KeyLookup: "query:api-key", Validator: func(key string, c echo.Context) (bool, error) { return key == "valid-key", nil },})) Configuration[​](https://echo.labstack.com/docs/middleware/key-auth#configuration "Direct link to Configuration") ------------------------------------------------------------------------------------------------------------------ KeyAuthConfig struct { // Skipper defines a function to skip middleware. Skipper Skipper // KeyLookup is a string in the form of ":" that is used // to extract key from the request. // Optional. Default value "header:Authorization". // Possible values: // - "header:" // - "query:" // - "cookie:" // - "form:" KeyLookup string `yaml:"key_lookup"` // AuthScheme to be used in the Authorization header. // Optional. Default value "Bearer". AuthScheme string // Validator is a function to validate key. // Required. Validator KeyAuthValidator // ErrorHandler defines a function which is executed for an invalid key. // It may be used to define a custom error. ErrorHandler KeyAuthErrorHandler} ### Default Configuration[​](https://echo.labstack.com/docs/middleware/key-auth#default-configuration "Direct link to Default Configuration") DefaultKeyAuthConfig = KeyAuthConfig{ Skipper: DefaultSkipper, KeyLookup: "header:" + echo.HeaderAuthorization, AuthScheme: "Bearer",} * [Usage](https://echo.labstack.com/docs/middleware/key-auth#usage) * [Custom Configuration](https://echo.labstack.com/docs/middleware/key-auth#custom-configuration) * [Usage](https://echo.labstack.com/docs/middleware/key-auth#usage-1) * [Configuration](https://echo.labstack.com/docs/middleware/key-auth#configuration) * [Default Configuration](https://echo.labstack.com/docs/middleware/key-auth#default-configuration) --- # Recover | Echo [Skip to main content](https://echo.labstack.com/docs/middleware/recover#__docusaurus_skipToContent_fallback) On this page Recover middleware recovers from panics anywhere in the chain, prints stack trace and handles the control to the centralized [HTTPErrorHandler](https://echo.labstack.com/docs/customization#http-error-handler) . Usage[​](https://echo.labstack.com/docs/middleware/recover#usage "Direct link to Usage") ----------------------------------------------------------------------------------------- e.Use(middleware.Recover()) Custom Configuration[​](https://echo.labstack.com/docs/middleware/recover#custom-configuration "Direct link to Custom Configuration") -------------------------------------------------------------------------------------------------------------------------------------- ### Usage[​](https://echo.labstack.com/docs/middleware/recover#usage-1 "Direct link to Usage") e := echo.New()e.Use(middleware.RecoverWithConfig(middleware.RecoverConfig{ StackSize: 1 << 10, // 1 KB LogLevel: log.ERROR,})) Example above uses a `StackSize` of 1 KB, `LogLevel` of error and default values for `DisableStackAll` and `DisablePrintStack`. Configuration[​](https://echo.labstack.com/docs/middleware/recover#configuration "Direct link to Configuration") ----------------------------------------------------------------------------------------------------------------- // LogErrorFunc defines a function for custom logging in the middleware.LogErrorFunc func(c echo.Context, err error, stack []byte) errorRecoverConfig struct { // Skipper defines a function to skip middleware. Skipper Skipper // Size of the stack to be printed. // Optional. Default value 4KB. StackSize int `yaml:"stack_size"` // DisableStackAll disables formatting stack traces of all other goroutines // into buffer after the trace for the current goroutine. // Optional. Default value false. DisableStackAll bool `yaml:"disable_stack_all"` // DisablePrintStack disables printing stack trace. // Optional. Default value as false. DisablePrintStack bool `yaml:"disable_print_stack"` // LogLevel is log level to printing stack trace. // Optional. Default value 0 (Print). LogLevel log.Lvl // LogErrorFunc defines a function for custom logging in the middleware. // If it's set you don't need to provide LogLevel for config. LogErrorFunc LogErrorFunc // DisableErrorHandler disables the call to centralized HTTPErrorHandler. // The recovered error is then passed back to upstream middleware, instead of swallowing the error. // Optional. Default value false. DisableErrorHandler bool `yaml:"disable_error_handler"`} ### Default Configuration[​](https://echo.labstack.com/docs/middleware/recover#default-configuration "Direct link to Default Configuration") DefaultRecoverConfig = RecoverConfig{ Skipper: DefaultSkipper, StackSize: 4 << 10, // 4 KB DisableStackAll: false, DisablePrintStack: false, LogLevel: 0, LogErrorFunc: nil, DisableErrorHandler: false,} * [Usage](https://echo.labstack.com/docs/middleware/recover#usage) * [Custom Configuration](https://echo.labstack.com/docs/middleware/recover#custom-configuration) * [Usage](https://echo.labstack.com/docs/middleware/recover#usage-1) * [Configuration](https://echo.labstack.com/docs/middleware/recover#configuration) * [Default Configuration](https://echo.labstack.com/docs/middleware/recover#default-configuration) --- # Jaeger | Echo [Skip to main content](https://echo.labstack.com/docs/middleware/jaeger#__docusaurus_skipToContent_fallback) On this page note Echo community contribution Trace requests on Echo framework with Jaeger Tracing Middleware. Usage[​](https://echo.labstack.com/docs/middleware/jaeger#usage "Direct link to Usage") ---------------------------------------------------------------------------------------- package mainimport ( "github.com/labstack/echo-contrib/jaegertracing" "github.com/labstack/echo/v4")func main() { e := echo.New() // Enable tracing middleware c := jaegertracing.New(e, nil) defer c.Close() e.Logger.Fatal(e.Start(":1323"))} Enabling the tracing middleware creates a tracer and a root tracing span for every request. Custom Configuration[​](https://echo.labstack.com/docs/middleware/jaeger#custom-configuration "Direct link to Custom Configuration") ------------------------------------------------------------------------------------------------------------------------------------- By default, traces are sent to `localhost` Jaeger agent instance. To configure an external Jaeger, start your application with environment variables. ### Usage[​](https://echo.labstack.com/docs/middleware/jaeger#usage-1 "Direct link to Usage") $ JAEGER_AGENT_HOST=192.168.1.10 JAEGER_AGENT_PORT=6831 ./myserver The tracer can be initialized with values coming from environment variables. None of the env vars are required and all of them can be overridden via direct setting of the property on the configuration object. | Property | Description | | --- | --- | | JAEGER\_SERVICE\_NAME | The service name | | JAEGER\_AGENT\_HOST | The hostname for communicating with agent via UDP | | JAEGER\_AGENT\_PORT | The port for communicating with agent via UDP | | JAEGER\_ENDPOINT | The HTTP endpoint for sending spans directly to a collector, i.e. [http://jaeger-collector:14268/api/traces](http://jaeger-collector:14268/api/traces) | | JAEGER\_USER | Username to send as part of "Basic" authentication to the collector endpoint | | JAEGER\_PASSWORD | Password to send as part of "Basic" authentication to the collector endpoint | | JAEGER\_REPORTER\_LOG\_SPANS | Whether the reporter should also log the spans | | JAEGER\_REPORTER\_MAX\_QUEUE\_SIZE | The reporter's maximum queue size | | JAEGER\_REPORTER\_FLUSH\_INTERVAL | The reporter's flush interval, with units, e.g. "500ms" or "2s" (\[valid units\]\[timeunits\]) | | JAEGER\_SAMPLER\_TYPE | The sampler type | | JAEGER\_SAMPLER\_PARAM | The sampler parameter (number) | | JAEGER\_SAMPLER\_MANAGER\_HOST\_PORT | The HTTP endpoint when using the remote sampler, i.e. [http://jaeger-agent:5778/sampling](http://jaeger-agent:5778/sampling) | | JAEGER\_SAMPLER\_MAX\_OPERATIONS | The maximum number of operations that the sampler will keep track of | | JAEGER\_SAMPLER\_REFRESH\_INTERVAL | How often the remotely controlled sampler will poll jaeger-agent for the appropriate sampling strategy, with units, e.g. "1m" or "30s" (\[valid units\]\[timeunits\]) | | JAEGER\_TAGS | A comma separated list of `name = value` tracer level tags, which get added to all reported spans. The value can also refer to an environment variable using the format `${envVarName:default}`, where the `:default` is optional, and identifies a value to be used if the environment variable cannot be found | | JAEGER\_DISABLED | Whether the tracer is disabled or not. If true, the default `opentracing.NoopTracer` is used. | | JAEGER\_RPC\_METRICS | Whether to store RPC metrics | By default, the client sends traces via UDP to the agent at `localhost:6831`. Use `JAEGER_AGENT_HOST` and `JAEGER_AGENT_PORT` to send UDP traces to a different `host:port`. If `JAEGER_ENDPOINT` is set, the client sends traces to the endpoint via `HTTP`, making the `JAEGER_AGENT_HOST` and `JAEGER_AGENT_PORT` unused. If `JAEGER_ENDPOINT` is secured, HTTP basic authentication can be performed by setting the `JAEGER_USER` and `JAEGER_PASSWORD` environment variables. ### Skipping URL(s)[​](https://echo.labstack.com/docs/middleware/jaeger#skipping-urls "Direct link to Skipping URL(s)") A middleware skipper can be passed to avoid tracing spans to certain URL(s). _Usage_ package mainimport ( "strings" "github.com/labstack/echo-contrib/jaegertracing" "github.com/labstack/echo/v4")// urlSkipper ignores metrics route on some middlewarefunc urlSkipper(c echo.Context) bool { if strings.HasPrefix(c.Path(), "/testurl") { return true } return false}func main() { e := echo.New() // Enable tracing middleware c := jaegertracing.New(e, urlSkipper) defer c.Close() e.Logger.Fatal(e.Start(":1323"))} ### TraceFunction[​](https://echo.labstack.com/docs/middleware/jaeger#tracefunction "Direct link to TraceFunction") This is a wrapper function that can be used to seamlessly add a span for the duration of the invoked function. There is no need to change function arguments. _Usage_ package mainimport ( "github.com/labstack/echo-contrib/jaegertracing" "github.com/labstack/echo/v4" "net/http" "time")func main() { e := echo.New() // Enable tracing middleware c := jaegertracing.New(e, nil) defer c.Close() e.GET("/", func(c echo.Context) error { // Wrap slowFunc on a new span to trace it's execution passing the function arguments jaegertracing.TraceFunction(c, slowFunc, "Test String") return c.String(http.StatusOK, "Hello, World!") }) e.Logger.Fatal(e.Start(":1323"))}// A function to be wrapped. No need to change it's arguments due to tracingfunc slowFunc(s string) { time.Sleep(200 * time.Millisecond) return} ### CreateChildSpan[​](https://echo.labstack.com/docs/middleware/jaeger#createchildspan "Direct link to CreateChildSpan") For more control over the Span, the function `CreateChildSpan` can be called giving control on data to be appended to the span like log messages, baggages and tags. _Usage_ package mainimport ( "github.com/labstack/echo-contrib/jaegertracing" "github.com/labstack/echo/v4")func main() { e := echo.New() // Enable tracing middleware c := jaegertracing.New(e, nil) defer c.Close() e.GET("/", func(c echo.Context) error { // Do something before creating the child span time.Sleep(40 * time.Millisecond) sp := jaegertracing.CreateChildSpan(c, "Child span for additional processing") defer sp.Finish() sp.LogEvent("Test log") sp.SetBaggageItem("Test baggage", "baggage") sp.SetTag("Test tag", "New Tag") time.Sleep(100 * time.Millisecond) return c.String(http.StatusOK, "Hello, World!") }) e.Logger.Fatal(e.Start(":1323"))} References[​](https://echo.labstack.com/docs/middleware/jaeger#references "Direct link to References") ------------------------------------------------------------------------------------------------------- * [Opentracing Library](https://github.com/opentracing/opentracing-go) * [Jaeger configuration](https://github.com/jaegertracing/jaeger-client-go#environment-variables) * [Usage](https://echo.labstack.com/docs/middleware/jaeger#usage) * [Custom Configuration](https://echo.labstack.com/docs/middleware/jaeger#custom-configuration) * [Usage](https://echo.labstack.com/docs/middleware/jaeger#usage-1) * [Skipping URL(s)](https://echo.labstack.com/docs/middleware/jaeger#skipping-urls) * [TraceFunction](https://echo.labstack.com/docs/middleware/jaeger#tracefunction) * [CreateChildSpan](https://echo.labstack.com/docs/middleware/jaeger#createchildspan) * [References](https://echo.labstack.com/docs/middleware/jaeger#references) --- # JWT | Echo [Skip to main content](https://echo.labstack.com/docs/middleware/jwt#__docusaurus_skipToContent_fallback) On this page JWT provides a JSON Web Token (JWT) authentication middleware. Echo JWT middleware is located at [https://github.com/labstack/echo-jwt](https://github.com/labstack/echo-jwt) Basic middleware behavior: * For valid token, it sets the user in context and calls next handler. * For invalid token, it sends "401 - Unauthorized" response. * For missing or invalid `Authorization` header, it sends "400 - Bad Request". Dependencies[​](https://echo.labstack.com/docs/middleware/jwt#dependencies "Direct link to Dependencies") ---------------------------------------------------------------------------------------------------------- import "github.com/labstack/echo-jwt/v4" Usage[​](https://echo.labstack.com/docs/middleware/jwt#usage "Direct link to Usage") ------------------------------------------------------------------------------------- e.Use(echojwt.JWT([]byte("secret"))) Custom Configuration[​](https://echo.labstack.com/docs/middleware/jwt#custom-configuration "Direct link to Custom Configuration") ---------------------------------------------------------------------------------------------------------------------------------- ### Usage[​](https://echo.labstack.com/docs/middleware/jwt#usage-1 "Direct link to Usage") e.Use(echojwt.WithConfig(echojwt.Config{ // ... SigningKey: []byte("secret"), // ...})) Configuration[​](https://echo.labstack.com/docs/middleware/jwt#configuration "Direct link to Configuration") ------------------------------------------------------------------------------------------------------------- type Config struct { // Skipper defines a function to skip middleware. Skipper middleware.Skipper // BeforeFunc defines a function which is executed just before the middleware. BeforeFunc middleware.BeforeFunc // SuccessHandler defines a function which is executed for a valid token. SuccessHandler func(c echo.Context) // ErrorHandler defines a function which is executed when all lookups have been done and none of them passed Validator // function. ErrorHandler is executed with last missing (ErrExtractionValueMissing) or an invalid key. // It may be used to define a custom JWT error. // // Note: when error handler swallows the error (returns nil) middleware continues handler chain execution towards handler. // This is useful in cases when portion of your site/api is publicly accessible and has extra features for authorized users // In that case you can use ErrorHandler to set default public JWT token value to request and continue with handler chain. ErrorHandler func(c echo.Context, err error) error // ContinueOnIgnoredError allows the next middleware/handler to be called when ErrorHandler decides to // ignore the error (by returning `nil`). // This is useful when parts of your site/api allow public access and some authorized routes provide extra functionality. // In that case you can use ErrorHandler to set a default public JWT token value in the request context // and continue. Some logic down the remaining execution chain needs to check that (public) token value then. ContinueOnIgnoredError bool // Context key to store user information from the token into context. // Optional. Default value "user". ContextKey string // Signing key to validate token. // This is one of the three options to provide a token validation key. // The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey. // Required if neither user-defined KeyFunc nor SigningKeys is provided. SigningKey interface{} // Map of signing keys to validate token with kid field usage. // This is one of the three options to provide a token validation key. // The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey. // Required if neither user-defined KeyFunc nor SigningKey is provided. SigningKeys map[string]interface{} // Signing method used to check the token's signing algorithm. // Optional. Default value HS256. SigningMethod string // KeyFunc defines a user-defined function that supplies the public key for a token validation. // The function shall take care of verifying the signing algorithm and selecting the proper key. // A user-defined KeyFunc can be useful if tokens are issued by an external party. // Used by default ParseTokenFunc implementation. // // When a user-defined KeyFunc is provided, SigningKey, SigningKeys, and SigningMethod are ignored. // This is one of the three options to provide a token validation key. // The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey. // Required if neither SigningKeys nor SigningKey is provided. // Not used if custom ParseTokenFunc is set. // Default to an internal implementation verifying the signing algorithm and selecting the proper key. KeyFunc jwt.Keyfunc // TokenLookup is a string in the form of ":" or ":,:" that is used // to extract token from the request. // Optional. Default value "header:Authorization". // Possible values: // - "header:" or "header::" // `` is argument value to cut/trim prefix of the extracted value. This is useful if header // value has static prefix like `Authorization: ` where part that we // want to cut is ` ` note the space at the end. // In case of JWT tokens `Authorization: Bearer ` prefix we cut is `Bearer `. // If prefix is left empty the whole value is returned. // - "query:" // - "param:" // - "cookie:" // - "form:" // Multiple sources example: // - "header:Authorization:Bearer ,cookie:myowncookie" TokenLookup string // TokenLookupFuncs defines a list of user-defined functions that extract JWT token from the given context. // This is one of the two options to provide a token extractor. // The order of precedence is user-defined TokenLookupFuncs, and TokenLookup. // You can also provide both if you want. TokenLookupFuncs []middleware.ValuesExtractor // ParseTokenFunc defines a user-defined function that parses token from given auth. Returns an error when token // parsing fails or parsed token is invalid. // Defaults to implementation using `github.com/golang-jwt/jwt` as JWT implementation library ParseTokenFunc func(c echo.Context, auth string) (interface{}, error) // Claims are extendable claims data defining token content. Used by default ParseTokenFunc implementation. // Not used if custom ParseTokenFunc is set. // Optional. Defaults to function returning jwt.MapClaims NewClaimsFunc func(c echo.Context) jwt.Claims} [Example](https://echo.labstack.com/docs/cookbook/jwt) [​](https://echo.labstack.com/docs/middleware/jwt#example "Direct link to example") ------------------------------------------------------------------------------------------------------------------------------------------- * [Dependencies](https://echo.labstack.com/docs/middleware/jwt#dependencies) * [Usage](https://echo.labstack.com/docs/middleware/jwt#usage) * [Custom Configuration](https://echo.labstack.com/docs/middleware/jwt#custom-configuration) * [Usage](https://echo.labstack.com/docs/middleware/jwt#usage-1) * [Configuration](https://echo.labstack.com/docs/middleware/jwt#configuration) * [Example](https://echo.labstack.com/docs/middleware/jwt#example) --- # Rate Limiter | Echo [Skip to main content](https://echo.labstack.com/docs/middleware/rate-limiter#__docusaurus_skipToContent_fallback) On this page `RateLimiter` provides a Rate Limiter middleware for limiting the amount of requests to the server from a particular IP or id within a time period. By default an in-memory store is used for keeping track of requests. The default in-memory implementation is focused on correctness and may not be the best option for a high number of concurrent requests or a large number of different identifiers (>16k). Usage[​](https://echo.labstack.com/docs/middleware/rate-limiter#usage "Direct link to Usage") ---------------------------------------------------------------------------------------------- To add a rate limit to your application simply add the `RateLimiter` middleware. The example below will limit the application to 20 requests/sec using the default in-memory store: e.Use(middleware.RateLimiter(middleware.NewRateLimiterMemoryStore(rate.Limit(20)))) info If the provided rate is a float number, Burst will be treated as the rounded down value of the rate. Custom Configuration[​](https://echo.labstack.com/docs/middleware/rate-limiter#custom-configuration "Direct link to Custom Configuration") ------------------------------------------------------------------------------------------------------------------------------------------- config := middleware.RateLimiterConfig{ Skipper: middleware.DefaultSkipper, Store: middleware.NewRateLimiterMemoryStoreWithConfig( middleware.RateLimiterMemoryStoreConfig{Rate: rate.Limit(10), Burst: 30, ExpiresIn: 3 * time.Minute}, ), IdentifierExtractor: func(ctx echo.Context) (string, error) { id := ctx.RealIP() return id, nil }, ErrorHandler: func(context echo.Context, err error) error { return context.JSON(http.StatusForbidden, nil) }, DenyHandler: func(context echo.Context, identifier string,err error) error { return context.JSON(http.StatusTooManyRequests, nil) },}e.Use(middleware.RateLimiterWithConfig(config)) ### Errors[​](https://echo.labstack.com/docs/middleware/rate-limiter#errors "Direct link to Errors") var ( // ErrRateLimitExceeded denotes an error raised when rate limit is exceeded ErrRateLimitExceeded = echo.NewHTTPError(http.StatusTooManyRequests, "rate limit exceeded") // ErrExtractorError denotes an error raised when extractor function is unsuccessful ErrExtractorError = echo.NewHTTPError(http.StatusForbidden, "error while extracting identifier")) tip If you need to implement your own store, be sure to implement the RateLimiterStore interface and pass it to RateLimiterConfig and you're good to go! Configuration[​](https://echo.labstack.com/docs/middleware/rate-limiter#configuration "Direct link to Configuration") ---------------------------------------------------------------------------------------------------------------------- type RateLimiterConfig struct { Skipper Skipper BeforeFunc BeforeFunc // IdentifierExtractor uses echo.Context to extract the identifier for a visitor IdentifierExtractor Extractor // Store defines a store for the rate limiter Store RateLimiterStore // ErrorHandler provides a handler to be called when IdentifierExtractor returns a non-nil error ErrorHandler func(context echo.Context, err error) error // DenyHandler provides a handler to be called when RateLimiter denies access DenyHandler func(context echo.Context, identifier string, err error) error} ### Default Configuration[​](https://echo.labstack.com/docs/middleware/rate-limiter#default-configuration "Direct link to Default Configuration") // DefaultRateLimiterConfig defines default values for RateLimiterConfigvar DefaultRateLimiterConfig = RateLimiterConfig{ Skipper: DefaultSkipper, IdentifierExtractor: func(ctx echo.Context) (string, error) { id := ctx.RealIP() return id, nil }, ErrorHandler: func(context echo.Context, err error) error { return &echo.HTTPError{ Code: ErrExtractorError.Code, Message: ErrExtractorError.Message, Internal: err, } }, DenyHandler: func(context echo.Context, identifier string, err error) error { return &echo.HTTPError{ Code: ErrRateLimitExceeded.Code, Message: ErrRateLimitExceeded.Message, Internal: err, } },} * [Usage](https://echo.labstack.com/docs/middleware/rate-limiter#usage) * [Custom Configuration](https://echo.labstack.com/docs/middleware/rate-limiter#custom-configuration) * [Errors](https://echo.labstack.com/docs/middleware/rate-limiter#errors) * [Configuration](https://echo.labstack.com/docs/middleware/rate-limiter#configuration) * [Default Configuration](https://echo.labstack.com/docs/middleware/rate-limiter#default-configuration) --- # Proxy | Echo [Skip to main content](https://echo.labstack.com/docs/middleware/proxy#__docusaurus_skipToContent_fallback) On this page Proxy provides an HTTP/WebSocket reverse proxy middleware. It forwards a request to upstream server using a configured load balancing technique. ### Usage[​](https://echo.labstack.com/docs/middleware/proxy#usage "Direct link to Usage") url1, err := url.Parse("http://localhost:8081")if err != nil { e.Logger.Fatal(err)}url2, err := url.Parse("http://localhost:8082")if err != nil { e.Logger.Fatal(err)}e.Use(middleware.Proxy(middleware.NewRoundRobinBalancer([]*middleware.ProxyTarget{ { URL: url1, }, { URL: url2, },}))) Custom Configuration[​](https://echo.labstack.com/docs/middleware/proxy#custom-configuration "Direct link to Custom Configuration") ------------------------------------------------------------------------------------------------------------------------------------ ### Usage[​](https://echo.labstack.com/docs/middleware/proxy#usage-1 "Direct link to Usage") e := echo.New()e.Use(middleware.ProxyWithConfig(middleware.ProxyConfig{})) ### Configuration[​](https://echo.labstack.com/docs/middleware/proxy#configuration "Direct link to Configuration") // ProxyConfig defines the config for Proxy middleware. ProxyConfig struct { // Skipper defines a function to skip middleware. Skipper Skipper // Balancer defines a load balancing technique. // Required. Balancer ProxyBalancer // Rewrite defines URL path rewrite rules. The values captured in asterisk can be // retrieved by index e.g. $1, $2 and so on. Rewrite map[string]string // RegexRewrite defines rewrite rules using regexp.Rexexp with captures // Every capture group in the values can be retrieved by index e.g. $1, $2 and so on. RegexRewrite map[*regexp.Regexp]string // Context key to store selected ProxyTarget into context. // Optional. Default value "target". ContextKey string // To customize the transport to remote. // Examples: If custom TLS certificates are required. Transport http.RoundTripper // ModifyResponse defines function to modify response from ProxyTarget. ModifyResponse func(*http.Response) error ### Default Configuration[​](https://echo.labstack.com/docs/middleware/proxy#default-configuration "Direct link to Default Configuration") | Name | Value | | --- | --- | | Skipper | DefaultSkipper | | ContextKey | `target` | ### Regex-based Rules[​](https://echo.labstack.com/docs/middleware/proxy#regex-based-rules "Direct link to Regex-based Rules") For advanced rewriting of proxy requests rules may also be defined using regular expression. Normal capture groups can be defined using `()` and referenced by index (`$1`, `$2`, ...) for the rewritten path. `RegexRules` and normal `Rules` can be combined. e.Use(ProxyWithConfig(ProxyConfig{ Balancer: rrb, Rewrite: map[string]string{ "^/v1/*": "/v2/$1", }, RegexRewrite: map[*regexp.Regexp]string{ regexp.MustCompile("^/foo/([0-9].*)"): "/num/$1", regexp.MustCompile("^/bar/(.+?)/(.*)"): "/baz/$2/$1", }, })) [Example](https://echo.labstack.com/docs/cookbook/reverse-proxy) [​](https://echo.labstack.com/docs/middleware/proxy#example "Direct link to example") ------------------------------------------------------------------------------------------------------------------------------------------------------- * [Usage](https://echo.labstack.com/docs/middleware/proxy#usage) * [Custom Configuration](https://echo.labstack.com/docs/middleware/proxy#custom-configuration) * [Usage](https://echo.labstack.com/docs/middleware/proxy#usage-1) * [Configuration](https://echo.labstack.com/docs/middleware/proxy#configuration) * [Default Configuration](https://echo.labstack.com/docs/middleware/proxy#default-configuration) * [Regex-based Rules](https://echo.labstack.com/docs/middleware/proxy#regex-based-rules) * [Example](https://echo.labstack.com/docs/middleware/proxy#example) --- # Redirect | Echo [Skip to main content](https://echo.labstack.com/docs/middleware/redirect#__docusaurus_skipToContent_fallback) On this page HTTPS Redirect[​](https://echo.labstack.com/docs/middleware/redirect#https-redirect "Direct link to HTTPS Redirect") --------------------------------------------------------------------------------------------------------------------- HTTPS redirect middleware redirects http requests to https. For example, [http://labstack.com](http://labstack.com/) will be redirected to [https://labstack.com](https://labstack.com/) . ### Usage[​](https://echo.labstack.com/docs/middleware/redirect#usage "Direct link to Usage") e := echo.New()e.Pre(middleware.HTTPSRedirect()) HTTPS WWW Redirect[​](https://echo.labstack.com/docs/middleware/redirect#https-www-redirect "Direct link to HTTPS WWW Redirect") --------------------------------------------------------------------------------------------------------------------------------- HTTPS WWW redirect redirects http requests to www https. For example, [http://labstack.com](http://labstack.com/) will be redirected to [https://www.labstack.com](https://www.labstack.com/) . Usage[​](https://echo.labstack.com/docs/middleware/redirect#usage-1 "Direct link to Usage") -------------------------------------------------------------------------------------------- e := echo.New()e.Pre(middleware.HTTPSWWWRedirect()) HTTPS NonWWW Redirect[​](https://echo.labstack.com/docs/middleware/redirect#https-nonwww-redirect "Direct link to HTTPS NonWWW Redirect") ------------------------------------------------------------------------------------------------------------------------------------------ HTTPS NonWWW redirect redirects http requests to https non [www](http://www/) . For example, [http://www.labstack.com](http://www.labstack.com/) will be redirect to [https://labstack.com](https://labstack.com/) . ### Usage[​](https://echo.labstack.com/docs/middleware/redirect#usage-2 "Direct link to Usage") e := echo.New()e.Pre(middleware.HTTPSNonWWWRedirect()) WWW Redirect[​](https://echo.labstack.com/docs/middleware/redirect#www-redirect "Direct link to WWW Redirect") --------------------------------------------------------------------------------------------------------------- WWW redirect redirects non www requests to [www](http://www/) . For example, [http://labstack.com](http://labstack.com/) will be redirected to [http://www.labstack.com](http://www.labstack.com/) . ### Usage[​](https://echo.labstack.com/docs/middleware/redirect#usage-3 "Direct link to Usage") e := echo.New()e.Pre(middleware.WWWRedirect()) NonWWW Redirect[​](https://echo.labstack.com/docs/middleware/redirect#nonwww-redirect "Direct link to NonWWW Redirect") ------------------------------------------------------------------------------------------------------------------------ NonWWW redirect redirects www requests to non [www](http://www/) . For example, [http://www.labstack.com](http://www.labstack.com/) will be redirected to [http://labstack.com](http://labstack.com/) . ### Usage[​](https://echo.labstack.com/docs/middleware/redirect#usage-4 "Direct link to Usage") e := echo.New()e.Pre(middleware.NonWWWRedirect()) Custom Configuration[​](https://echo.labstack.com/docs/middleware/redirect#custom-configuration "Direct link to Custom Configuration") --------------------------------------------------------------------------------------------------------------------------------------- ### Usage[​](https://echo.labstack.com/docs/middleware/redirect#usage-5 "Direct link to Usage") e := echo.New()e.Use(middleware.HTTPSRedirectWithConfig(middleware.RedirectConfig{ Code: http.StatusTemporaryRedirect,})) Example above will redirect the request HTTP to HTTPS with status code `307 - StatusTemporaryRedirect`. Configuration[​](https://echo.labstack.com/docs/middleware/redirect#configuration "Direct link to Configuration") ------------------------------------------------------------------------------------------------------------------ RedirectConfig struct { // Skipper defines a function to skip middleware. Skipper Skipper // Status code to be used when redirecting the request. // Optional. Default value http.StatusMovedPermanently. Code int `json:"code"`} ### Default Configuration\*[​](https://echo.labstack.com/docs/middleware/redirect#default-configuration "Direct link to Default Configuration*") DefaultRedirectConfig = RedirectConfig{ Skipper: DefaultSkipper, Code: http.StatusMovedPermanently,} * [HTTPS Redirect](https://echo.labstack.com/docs/middleware/redirect#https-redirect) * [Usage](https://echo.labstack.com/docs/middleware/redirect#usage) * [HTTPS WWW Redirect](https://echo.labstack.com/docs/middleware/redirect#https-www-redirect) * [Usage](https://echo.labstack.com/docs/middleware/redirect#usage-1) * [HTTPS NonWWW Redirect](https://echo.labstack.com/docs/middleware/redirect#https-nonwww-redirect) * [Usage](https://echo.labstack.com/docs/middleware/redirect#usage-2) * [WWW Redirect](https://echo.labstack.com/docs/middleware/redirect#www-redirect) * [Usage](https://echo.labstack.com/docs/middleware/redirect#usage-3) * [NonWWW Redirect](https://echo.labstack.com/docs/middleware/redirect#nonwww-redirect) * [Usage](https://echo.labstack.com/docs/middleware/redirect#usage-4) * [Custom Configuration](https://echo.labstack.com/docs/middleware/redirect#custom-configuration) * [Usage](https://echo.labstack.com/docs/middleware/redirect#usage-5) * [Configuration](https://echo.labstack.com/docs/middleware/redirect#configuration) * [Default Configuration\*](https://echo.labstack.com/docs/middleware/redirect#default-configuration) --- # Secure | Echo [Skip to main content](https://echo.labstack.com/docs/middleware/secure#__docusaurus_skipToContent_fallback) On this page Secure middleware provides protection against cross-site scripting (XSS) attack, content type sniffing, clickjacking, insecure connection and other code injection attacks. Usage[​](https://echo.labstack.com/docs/middleware/secure#usage "Direct link to Usage") ---------------------------------------------------------------------------------------- e.Use(middleware.Secure()) Custom Configuration[​](https://echo.labstack.com/docs/middleware/secure#custom-configuration "Direct link to Custom Configuration") ------------------------------------------------------------------------------------------------------------------------------------- ### Usage[​](https://echo.labstack.com/docs/middleware/secure#usage-1 "Direct link to Usage") e := echo.New()e.Use(middleware.SecureWithConfig(middleware.SecureConfig{ XSSProtection: "", ContentTypeNosniff: "", XFrameOptions: "", HSTSMaxAge: 3600, ContentSecurityPolicy: "default-src 'self'",})) info Passing empty `XSSProtection`, `ContentTypeNosniff`, `XFrameOptions` or `ContentSecurityPolicy` disables that protection. Configuration[​](https://echo.labstack.com/docs/middleware/secure#configuration "Direct link to Configuration") ---------------------------------------------------------------------------------------------------------------- SecureConfig struct { // Skipper defines a function to skip middleware. Skipper Skipper // XSSProtection provides protection against cross-site scripting attack (XSS) // by setting the `X-XSS-Protection` header. // Optional. Default value "1; mode=block". XSSProtection string `json:"xss_protection"` // ContentTypeNosniff provides protection against overriding Content-Type // header by setting the `X-Content-Type-Options` header. // Optional. Default value "nosniff". ContentTypeNosniff string `json:"content_type_nosniff"` // XFrameOptions can be used to indicate whether or not a browser should // be allowed to render a page in a ,