{"id":13393526,"url":"https://github.com/rs/rest-layer","last_synced_at":"2025-04-08T09:07:30.767Z","repository":{"id":35637355,"uuid":"39911647","full_name":"rs/rest-layer","owner":"rs","description":"REST Layer, Go (golang) REST API framework","archived":false,"fork":false,"pushed_at":"2021-10-01T07:21:48.000Z","size":1167,"stargazers_count":1251,"open_issues_count":36,"forks_count":112,"subscribers_count":33,"default_branch":"master","last_synced_at":"2025-04-01T05:36:19.424Z","etag":null,"topics":["api","api-documentation","api-server","framework","go","graphql","json-schema","rest-api","schema-fields","storage-backend"],"latest_commit_sha":null,"homepage":" http://rest-layer.io","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-07-29T19:16:20.000Z","updated_at":"2025-03-04T10:40:48.000Z","dependencies_parsed_at":"2022-08-13T04:30:23.619Z","dependency_job_id":null,"html_url":"https://github.com/rs/rest-layer","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rs%2Frest-layer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rs%2Frest-layer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rs%2Frest-layer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rs%2Frest-layer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rs","download_url":"https://codeload.github.com/rs/rest-layer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247809962,"owners_count":20999816,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","api-documentation","api-server","framework","go","graphql","json-schema","rest-api","schema-fields","storage-backend"],"created_at":"2024-07-30T17:00:55.165Z","updated_at":"2025-04-08T09:07:30.741Z","avatar_url":"https://github.com/rs.png","language":"Go","readme":"# REST Layer\n\nREST APIs made easy.\n\n[![godoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/rs/rest-layer) [![license](https://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/rs/rest-layer/master/LICENSE) [![build](https://img.shields.io/travis/rs/rest-layer.svg?style=flat)](https://travis-ci.org/rs/rest-layer) [![Go Report Card](https://goreportcard.com/badge/github.com/rs/rest-layer)](https://goreportcard.com/report/github.com/rs/rest-layer)\n\nREST Layer is an API framework heavily inspired by the excellent [Python Eve](http://python-eve.org). It helps you create a comprehensive, customizable, and secure REST (graph) API on top of pluggable [backend storages](#main-storage-handlers) with no boiler plate code so you can focus on your business logic.\n\nImplemented as a `net/http` handler, it plays well with standard middleware like [CORS](http://github.com/rs/cors). It is also [context](https://godoc.org/context) aware. This allows deadline management to be supported down to the storage and permit an easy extensibility by passing custom data between layers of the framework.\n\nREST Layer is an opinionated framework. Unlike many API frameworks, you don't directly control the routing and you don't have to write handlers. You just define resources and sub-resources with a [schema](#resource-configuration), the framework automatically figures out what routes need to be generated behind the scene. You don't have to take care of the HTTP headers and response, JSON encoding, etc. either. REST layer handles HTTP [conditional requests](#conditional-requests), caching, [integrity checking](#data-integrity-and-concurrency-control) for you.\n\nA powerful and extensible [validation engine](#resource-configuration) make sure that data comes pre-validated to your [custom storage handlers](#data-storage-handler). Generic resource handlers for [MongoDB](http://github.com/rs/rest-layer-mongo), [ElasticSearch](http://github.com/rs/rest-layer-es) and other databases are also available so you have few to no code to write to get up and running.\n\nMoreover, REST Layer let you create a graph API by linking resources between them. Thanks to its advanced [field selection](#field-selection) syntax or [GraphQL](#graphql) support, you can gather resources and their dependencies in a single request, saving you from costly network round-trips.\n\nThe REST Layer framework is composed of several sub-packages:\n\n![package layout](doc/schema.png)\n\n| Package                                                         | Coverage                                                                                                                                       | Description\n| --------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------\n| [rest](https://godoc.org/github.com/rs/rest-layer/rest)         | [![Coverage](https://gocover.io/_badge/github.com/rs/rest-layer/rest)](https://gocover.io/github.com/rs/rest-layer/rest) | A `net/http` handler to expose a REST-ful API.\n| [graphql](https://godoc.org/github.com/rs/rest-layer/graphql)   | [![Coverage](https://gocover.io/_badge/github.com/rs/rest-layer/graphql)](https://gocover.io/github.com/rs/rest-layer/graphql)              | A `net/http` handler to expose your API using the GraphQL protocol.\n| [schema](https://godoc.org/github.com/rs/rest-layer/schema)     | [![Coverage](https://gocover.io/_badge/github.com/rs/rest-layer/schema)](https://gocover.io/github.com/rs/rest-layer/schema)               | A validation framework for the API resources.\n| [resource](https://godoc.org/github.com/rs/rest-layer/resource) | [![Coverage](https://gocover.io/_badge/github.com/rs/rest-layer/resource)](https://gocover.io/github.com/rs/rest-layer/resource)             | Defines resources, manages the resource graph and manages the interface with resource storage handler.\n\n## Documentation\n\n- [Breaking Changes](#breaking-changes)\n- [Features](#features)\n  - [Extensions](#extensions)\n  - [Main Storage Handlers](#main-storage-handlers)\n  - [Alternate Storage Handlers](#alternate-storage-handlers)\n- [Usage](#usage)\n- [Resource Configuration](#resource-configuration)\n  - [Schema](#schema)\n  - [Field Definition](#field-definition)\n  - [Binding](#binding)\n  - [Modes](#modes)\n  - [Hooks](#hooks)\n  - [Sub Resources](#sub-resources)\n  - [Dependency](#dependency)\n- [HTTP Request Headers](#http-request-headers)\n  - [Prefer](#prefer)\n- [HTTP Request Methods](#http-request-methods)\n  - [OPTIONS](#options)\n  - [HEAD](#head)\n  - [GET](#get)\n  - [POST](#post)\n  - [PUT](#put)\n  - [PATCH](#patch)\n  - [DELETE](#delete)\n- [Querying](#querying)\n  - [Filtering](#filtering)\n  - [Sorting](#sorting)\n  - [Field Selection](#field-selection)\n    - [Field Aliasing](#field-aliasing)\n    - [Field Parameters](#field-parameters)\n    - [Embedding](#embedding)\n  - [Pagination](#pagination)\n  - [Skipping](#skipping)\n- [Authentication \u0026 Authorization](#authentication-and-authorization)\n- [Conditional Requests](#conditional-requests)\n- [Data Integrity \u0026 Concurrency Control](#data-integrity-and-concurrency-control)\n- [Data Validation](#data-validation)\n  - [Nullable Values](#nullable-values)\n  - [Extensible Data Validation](#extensible-data-validation)\n- [Timeout and Request Cancellation](#timeout-and-request-cancellation)\n- [Logging](#logging)\n- [CORS](#cors)\n- [JSONP](#jsonp)\n- [Data Storage Handler](#data-storage-handler)\n- [Custom Response Formatter / Sender](#custom-response-formatter--sender)\n- [GraphQL](#graphql)\n- [Hystrix](#hystrix)\n- [JSONSchema](#jsonschema)\n\n## Breaking Changes\n\nUntil we reach a stable v1, there will be occasional breaking changes to the rest-layer APIs. Breaking changes will however not arrive at patch releases.\n\n### Breaking changes since v0.2.0\n\nNo breaking changes since v0.2.0.\n\n### Breaking changes prior to v0.2.0\n\nBelow is an incomplete list of breaking changes included in v0.2.0:\n\n- PR #151: `ValuesValidator FieldValidator` attribute in `schema.Dict` struct replaced by `Values Field`.\n- PR #179: `ValuesValidator FieldValidator` attribute in `schema.Array` struct replaced by `Values Field`.\n- PR #204:\n  - Storage drivers need to accept pointer to `Expression` implementer in `query.Predicate`.\n  - `filter` parameters in sub-query will be validated for type match.\n  - `filter` parameters will be validated for type match only, instead of type \u0026 constrains.\n- PR #228: `Reference` projection fields will be validated against referenced resource schema.\n- PR #230: `Connection` projection fields will be validated against connected resource schema.\n- PR #241: Always call `OnUpdate` field hook on HTTP PUT for existing documents. Deleting a field with `Default` value set, will always be reset to its default value.\n\n## Features\n\n- [x] Automatic handling of REST resource operations\n- [ ] Full test coverage\n- [x] Plays well with other `net/http` middleware\n- [x] Pluggable resources storage\n- [x] Pluggable response sender\n- [x] GraphQL query support\n- [ ] GraphQL mutation support\n- [ ] Swagger Documentation\n- [x] JSONSchema Output (partial)\n- [ ] Testing framework\n- [x] Sub resources\n- [ ] Cascading deletes on sub resources\n- [x] Filtering\n- [x] Sorting\n- [x] Pagination\n- [x] Aliasing\n- [x] Custom business logic\n- [x] Event hooks\n- [x] Field hooks\n- [x] Extensible data validation and transformation\n- [x] Conditional requests (Last-Modified / Etag)\n- [x] Data integrity and concurrency control (If-Match)\n- [x] Timeout and request cancellation through [context](https://godoc.org/context)\n- [x] Logging\n- [x] Multi-GET\n- [ ] Bulk inserts\n- [x] Default and nullable values\n- [ ] Per resource cache control\n- [ ] Customizable authentication / authorization\n- [x] Projections\n- [x] Embedded resource serialization\n- [x] Sub-request concurrency control\n- [x] Custom ID field\n- [ ] Data versioning\n- [x] Per resource circuit breaker using [Hystrix](https://godoc.org/github.com/afex/hystrix-go/hystrix)\n- [x] [JSON-Patch](https://tools.ietf.org/html/rfc6902) support\n\n### Extensions\n\nAs REST Layer is a simple `net/http` handler. You can use standard middleware to extend its functionalities:\n\n- [x] [CORS](http://github.com/rs/cors)\n- [ ] Method Override\n- [ ] Gzip, Deflate\n- [ ] JSONP\n- [x] [X-Forwarded-For](https://github.com/sebest/xff)\n- [x] [Rate Limiting](https://github.com/didip/tollbooth)\n- [ ] Operations Log\n- [x] [Hystrix storage handler wrapper](https://github.com/rs/rest-layer-hystrix)\n\n### Main Storage Handlers\n\n- [x] [Memory](http://github.com/rs/rest-layer/tree/master/resource/testing/mem) (test only)\n- [x] [MongoDB](http://github.com/rs/rest-layer-mongo)\n\n### Alternate Storage Handlers\n\n- [ElasticSearch](http://github.com/rs/rest-layer-es) (no longer actively tested)\n- [SQL](https://github.com/apuigsech/rest-layer-sql) (third party)\n- [Google Datastore](https://github.com/ajcrowe/rest-layer-datastore) (third party)\n- [Kubernetes ConfigMap](https://github.com/Segence/rest-layer-kubernetes-configmap) (third party)\n\n## Usage\n\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/rs/rest-layer/resource/testing/mem\"\n\t\"github.com/rs/rest-layer/resource\"\n\t\"github.com/rs/rest-layer/rest\"\n\t\"github.com/rs/rest-layer/schema/query\"\n\t\"github.com/rs/rest-layer/schema\"\n)\n\nvar (\n\t// Define a user resource schema\n\tuser = schema.Schema{\n\t\tDescription: `The user object`,\n\t\tFields: schema.Fields{\n\t\t\t\"id\": {\n\t\t\t\tRequired: true,\n\t\t\t\t// When a field is read-only, only default values or hooks can\n\t\t\t\t// set their value. The client can't change it.\n\t\t\t\tReadOnly: true,\n\t\t\t\t// This is a field hook called when a new user is created.\n\t\t\t\t// The schema.NewID hook is a provided hook to generate a\n\t\t\t\t// unique id when no value is provided.\n\t\t\t\tOnInit: schema.NewID,\n\t\t\t\t// The Filterable and Sortable allows usage of filter and sort\n\t\t\t\t// on this field in requests.\n\t\t\t\tFilterable: true,\n\t\t\t\tSortable:   true,\n\t\t\t\tValidator: \u0026schema.String{\n\t\t\t\t\tRegexp: \"^[0-9a-v]{20}$\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"created\": {\n\t\t\t\tRequired:   true,\n\t\t\t\tReadOnly:   true,\n\t\t\t\tFilterable: true,\n\t\t\t\tSortable:   true,\n\t\t\t\tOnInit:     schema.Now,\n\t\t\t\tValidator:  \u0026schema.Time{},\n\t\t\t},\n\t\t\t\"updated\": {\n\t\t\t\tRequired:   true,\n\t\t\t\tReadOnly:   true,\n\t\t\t\tFilterable: true,\n\t\t\t\tSortable:   true,\n\t\t\t\tOnInit:     schema.Now,\n\t\t\t\t// The OnUpdate hook is called when the item is edited. Here we use\n\t\t\t\t// provided Now hook which returns the current time.\n\t\t\t\tOnUpdate:  schema.Now,\n\t\t\t\tValidator: \u0026schema.Time{},\n\t\t\t},\n\t\t\t// Define a name field as required with a string validator\n\t\t\t\"name\": {\n\t\t\t\tRequired:   true,\n\t\t\t\tFilterable: true,\n\t\t\t\tValidator: \u0026schema.String{\n\t\t\t\t\tMaxLen: 150,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\t// Define a post resource schema\n\tpost = schema.Schema{\n\t\tDescription: `Represents a blog post`,\n\t\tFields: schema.Fields{\n\t\t\t// schema.*Field are shortcuts for common fields\n\t\t\t// (identical to users' same fields)\n\t\t\t\"id\":      schema.IDField,\n\t\t\t\"created\": schema.CreatedField,\n\t\t\t\"updated\": schema.UpdatedField,\n\t\t\t// Define a user field which references the user owning the post.\n\t\t\t// See bellow, the content of this field is enforced by the fact\n\t\t\t// that posts is a sub-resource of users.\n\t\t\t\"user\": {\n\t\t\t\tRequired:   true,\n\t\t\t\tFilterable: true,\n\t\t\t\tValidator: \u0026schema.Reference{\n\t\t\t\t\tPath: \"users\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"published\": {\n\t\t\t\tRequired: true,\n\t\t\t\tFilterable: true,\n\t\t\t\tDefault: false,\n\t\t\t\tValidator: \u0026schema.Bool{},\n\t\t\t},\n\t\t\t\"title\": {\n\t\t\t\tRequired: true,\n\t\t\t\tValidator: \u0026schema.String{\n\t\t\t\t\tMaxLen: 150,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"body\": {\n\t\t\t\t// Dependency defines that body field can't be changed if\n\t\t\t\t// the published field is not \"false\".\n\t\t\t\tDependency: query.MustParsePredicate(`{\"published\": false}`),\n\t\t\t\tValidator: \u0026schema.String{\n\t\t\t\t\tMaxLen: 100000,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n)\n\nfunc main() {\n\t// Create a REST API resource index\n\tindex := resource.NewIndex()\n\n\t// Add a resource on /users[/:user_id]\n\tusers := index.Bind(\"users\", user, mem.NewHandler(), resource.Conf{\n\t\t// We allow all REST methods\n\t\t// (rest.ReadWrite is a shortcut for []resource.Mode{resource.Create,\n\t    //  resource.Read, resource.Update, resource.Delete, resource,List})\n\t\tAllowedModes: resource.ReadWrite,\n\t})\n\n\t// Bind a sub resource on /users/:user_id/posts[/:post_id]\n\t// and reference the user on each post using the \"user\" field of the posts resource.\n\tusers.Bind(\"posts\", \"user\", post, mem.NewHandler(), resource.Conf{\n\t\t// Posts can only be read, created and deleted, not updated\n\t\tAllowedModes: []resource.Mode{resource.Read, resource.List,\n\t\t\t resource.Create, resource.Delete},\n\t})\n\n\t// Create API HTTP handler for the resource graph\n\tapi, err := rest.NewHandler(index)\n\tif err != nil {\n\t\tlog.Fatalf(\"Invalid API configuration: %s\", err)\n\t}\n\n\t// Bind the API under /api/ path\n\thttp.Handle(\"/api/\", http.StripPrefix(\"/api/\", api))\n\n\t// Serve it\n\tlog.Print(\"Serving API on http://localhost:8080\")\n\tif err := http.ListenAndServe(\":8080\", nil); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nJust run this code (or use the provided [examples/demo](https://github.com/rs/rest-layer/blob/master/examples/demo/main.go)):\n\n```sh\n$ go run examples/demo/main.go\n2015/07/27 20:54:55 Serving API on http://localhost:8080\n```\n\nUsing [HTTPie](http://httpie.org/), you can now play with your API.\n\nFirst create a user:\n\n```sh\n$ http POST :8080/api/users name=\"John Doe\"\nHTTP/1.1 201 Created\nContent-Length: 155\nContent-Location: /api/users/ar6ejgmkj5lfl98r67p0\nContent-Type: application/json\nDate: Mon, 27 Jul 2015 19:10:20 GMT\nEtag: \"1e18e148e1ff3ecdaae5ec03ac74e0e4\"\nLast-Modified: Mon, 27 Jul 2015 19:10:20 GMT\nVary: Origin\n\n{\n    \"id\": \"ar6ejgmkj5lfl98r67p0\",\n    \"created\": \"2015-07-27T21:10:20.671003126+02:00\",\n    \"updated\": \"2015-07-27T21:10:20.671003989+02:00\",\n    \"name\": \"John Doe\",\n}\n```\n\nAs you can see, the `id`, `created` and `updated` fields have been automatically generated by our `OnInit` field hooks.\n\nAlso notice the `Etag` and `Last-Modified` headers. Those guys allow data integrity and concurrency control *down to the storage layer* through the use of the `If-Match` and `If-Unmodified-Since` headers. They can also serve for conditional requests using `If-None-Match` and `If-Modified-Since` headers.\n\nHere is an example of conditional request:\n\n```sh\n$ http :8080/api/users/ar6ejgmkj5lfl98r67p0 \\\n  If-Modified-Since:\"Mon, 27 Jul 2015 19:10:20 GMT\"\nHTTP/1.1 304 Not Modified\nDate: Mon, 27 Jul 2015 19:17:11 GMT\nVary: Origin\n```\n\nAnd here is a data integrity request following the [RFC-5789](http://tools.ietf.org/html/rfc5789) recommendations:\n\n```sh\n$ http PATCH :8080/api/users/ar6ejgmkj5lfl98r67p0 \\\n  name=\"Someone Else\" If-Match:invalid-etag\nHTTP/1.1 412 Precondition Failed\nContent-Length: 58\nContent-Type: application/json\nDate: Mon, 27 Jul 2015 19:33:27 GMT\nVary: Origin\n\n{\n    \"code\": 412,\n    \"fields\": null,\n    \"message\": \"Precondition Failed\"\n}\n```\n\nRetry with the valid etag:\n\n```sh\n$ http PATCH :8080/api/users/ar6ejgmkj5lfl98r67p0 \\\n  name=\"Someone Else\" If-Match:'\"1e18e148e1ff3ecdaae5ec03ac74e0e4\"'\n\nHTTP/1.1 200 OK\nContent-Length: 159\nContent-Type: application/json\nDate: Mon, 27 Jul 2015 19:36:19 GMT\nEtag: \"7bb7a71b0f66197aa07c4c8fc9564616\"\nLast-Modified: Mon, 27 Jul 2015 19:36:19 GMT\nVary: Origin\n\n{\n    \"created\": \"2015-07-27T21:33:09.168492448+02:00\",\n    \"id\": \"ar6ejmukj5lflde9q8bg\",\n    \"name\": \"Someone Else\",\n    \"updated\": \"2015-07-27T21:36:19.904545093+02:00\"\n}\n```\n\nNote that even if you don't use conditional request, the `Etag` is always used by the storage handler to manage concurrency control between requests.\n\nAnother cool thing is sub-resources. We've set our `posts` resource as a child of the `users` resource. This way we can handle ownership very easily as routes are constructed as `/users/:user_id/posts`.\n\nLets create a post:\n\n```sh\n$ http POST :8080/api/users/ar6ejgmkj5lfl98r67p0/posts \\\n  title=\"My first post\"\nHTTP/1.1 200 OK\nContent-Length: 212\nContent-Type: application/json\nDate: Mon, 27 Jul 2015 19:46:55 GMT\nEtag: \"307ae92df6c3dd54847bfc7d72422e07\"\nLast-Modified: Mon, 27 Jul 2015 19:46:55 GMT\nVary: Origin\n\n{\n    \"id\": \"ar6ejs6kj5lflgc28es0\",\n    \"created\": \"2015-07-27T21:46:55.355857401+02:00\",\n    \"updated\": \"2015-07-27T21:46:55.355857989+02:00\",\n    \"title\": \"My first post\",\n    \"user\": \"ar6ejgmkj5lfl98r67p0\"\n}\n```\n\nNotice how the `user` field has been set with the user id provided in the route, that's pretty cool, huh?\n\nWe defined that we can create posts but we can't modify them, lets verify that:\n\n```sh\n$ http PATCH :8080/api/users/821d…/posts/ar6ejs6kj5lflgc28es0 \\\n  private=true\nHTTP/1.1 405 Method Not Allowed\nContent-Length: 53\nContent-Type: application/json\nDate: Mon, 27 Jul 2015 19:50:33 GMT\nVary: Origin\n\n{\n    \"code\": 405,\n    \"fields\": null,\n    \"message\": \"Invalid method\"\n}\n```\n\nLet's list posts for that user now:\n\n```sh\n$ http :8080/api/users/ar6ejgmkj5lfl98r67p0/posts\nHTTP/1.1 200 OK\nContent-Length: 257\nContent-Type: application/json\nDate: Mon, 27 Jul 2015 19:51:46 GMT\nVary: Origin\nX-Total: 1\n\n[\n    {\n        \"id\": \"ar6ejs6kj5lflgc28es0\",\n        \"_etag\": \"307ae92df6c3dd54847bfc7d72422e07\",\n        \"created\": \"2015-07-27T21:46:55.355857401+02:00\",\n        \"updated\": \"2015-07-27T21:46:55.355857989+02:00\",\n        \"title\": \"My first post\",\n        \"user\": \"ar6ejgmkj5lfl98r67p0\"\n    }\n]\n```\n\nNotice the added `_etag` field. This is to let you get etags of multiple items without having to `GET` each one of them through individual requests.\n\nNow, let's get user's information for each posts in a single request:\n\n```sh\n$ http :8080/api/users/ar6ejgmkj5lfl98r67p0/posts fields=='id,title,user{id,name}'\nHTTP/1.1 200 OK\nContent-Length: 257\nContent-Type: application/json\nDate: Mon, 27 Jul 2015 19:51:46 GMT\nVary: Origin\nX-Total: 1\n\n[\n    {\n        \"id\": \"ar6ejs6kj5lflgc28es0\",\n        \"_etag\": \"307ae92df6c3dd54847bfc7d72422e07\",\n        \"created\": \"2015-07-27T21:46:55.355857401+02:00\",\n        \"updated\": \"2015-07-27T21:46:55.355857989+02:00\",\n        \"title\": \"My first post\",\n        \"user\": {\n            \"id\": \"ar6ejgmkj5lfl98r67p0\",\n            \"name\": \"John Doe\"\n        }\n    }\n]\n```\n\nNotice how we selected which fields we wanted in the result using the [field selection](#field-selection) query format. Thanks to sub-request support, the user name is included with each post with no additional HTTP request.\n\nWe can go even further and embed a sub-request list responses. Let's say we want a list of users with the last two posts:\n\n```sh\n$ http GET :8080/api/users fields='id,name,posts(limit:2){id,title}'\nHTTP/1.1 201 Created\nContent-Length: 155\nContent-Location: /api/users/ar6ejgmkj5lfl98r67p0\nContent-Type: application/json\nDate: Mon, 27 Jul 2015 19:10:20 GMT\nEtag: \"1e18e148e1ff3ecdaae5ec03ac74e0e4\"\nLast-Modified: Mon, 27 Jul 2015 19:10:20 GMT\nVary: Origin\n\n[\n    {\n        \"id\": \"ar6ejgmkj5lfl98r67p0\",\n        \"name\": \"John Doe\",\n        \"posts\": [\n            {\n                \"id\": \"ar6ejs6kj5lflgc28es0\",\n                \"title\": \"My first post\"\n            },\n            {\n                \"id\": \"ar6ek26kj5lfljgh84qg\",\n                \"title\": \"My second post\"\n            }\n        ]\n    }\n]\n```\n\nSub-requests are executed concurrently whenever possible to ensure the fastest response time.\n\n## Resource Configuration\n\nFor REST Layer to be able to expose resources, you have to first define what fields the resource contains and where to bind it in the REST API URL namespace.\n\n### Schema\n\nResource field configuration is performed through the [schema](https://godoc.org/github.com/rs/rest-layer/schema) package. A schema is a struct describing a resource. A schema is composed of metadata about the resource and a description of the allowed fields through a map of field name pointing to field definition.\n\nSample resource schema:\n\n```go\nfoo = schema.Schema{\n\tDescription: \"A foo object\",\n\tFields: schema.Fields{\n\t\t\"field_name\": {\n\t\t\tRequired: true,\n\t\t\tFilterable: true,\n\t\t\tValidator: \u0026schema.String{\n\t\t\t\tMaxLen: 150,\n\t\t\t},\n\t\t},\n\t},\n}\n```\n\nSchema fields:\n\n| Field         | Description\n| ------------- | -------------\n| `Description` | The description of the resource. This is used for API documentation.\n| `Fields`      | A map of field name to field definition.\n\n### Field Definition\n\nThe field definitions contains the following properties:\n\n| Field        | Description\n| ------------ | -------------\n| `Required`   | If `true`, the field must be provided when the resource is created and can't be set to `null`. The client may be able to omit a required field if a `Default` or a hook sets its content.\n| `ReadOnly`   | If `true`, the field can not be set by the client, only a `Default` or a hook can alter its value. You may specify a value for a read-only field in your mutation request if the value is equal to the old value, REST Layer won't complain about it. This lets your client `PUT` the same document it got with `GET` without having to take care of removing the read-only fields.\n| `Hidden`     | Hidden allows writes but hides the field's content from the client. When this field is enabled, PUTing the document without the field would not remove the field but use the previous document's value if any.\n| `Default`    | The value to be set when resource is created and the client didn't provide a value for the field. The content of this variable must still pass validation.\n| `OnInit`     | A function to be executed when the resource is created. The function gets the current value of the field (after `Default` has been set if any) and returns the new value to be set.\n| `OnUpdate`   | A function to be executed when the resource is updated. The function gets the current (updated) value of the field and returns the new value to be set.\n| `Params`     | Params defines the list of parameters allowed for this field. See [Field Parameters](#field-parameters) section for some examples.\n| `Handler`    | Handler defines a function able to change the field's value depending on the passed parameters. See [Field Parameters](#field-parameters) section for some examples.\n| `Validator`  | A `schema.FieldValidator` to validate the content of the field.\n| `Dependency` | A query using `filter` format created with ``query.MustParsePredicate(`{\"field\": \"value\"}`)``. If the query doesn't match the document, the field generates a dependency error.\n| `Filterable` | If `true`, the field can be used with the `filter` parameter. You may want to ensure the backend database has this field indexed when enabled. Some storage handlers may not support all the operators of the filter parameter, see their documentation for more information.\n| `Sortable`   | If `true`, the field can be used with the `sort` parameter. You may want to ensure the backend database has this field indexed when enabled.\n| `Schema`     | An optional sub schema to validate hierarchical documents.\n\nREST Layer comes with a set of validators. You can add your own by implementing the `schema.FieldValidator` interface. Here is the list of provided validators:\n\n| Validator               | Description\n| ----------------------- | -------------\n| [schema.String][str]    | Ensures the field is a string\n| [schema.Integer][int]   | Ensures the field is an integer\n| [schema.Float][float]   | Ensures the field is a float\n| [schema.Bool][bool]     | Ensures the field is a Boolean\n| [schema.Array][array]   | Ensures the field is an array\n| [schema.Dict][dict]     | Ensures the field is a dict\n| [schema.Object][object] | Ensures the field is an object validating against a sub-schema\n| [schema.Time][time]     | Ensures the field is a datetime\n| [schema.URL][url]       | Ensures the field is a valid URL\n| [schema.IP][url]        | Ensures the field is a valid IPv4 or IPv6\n| [schema.Password][pswd] | Ensures the field is a valid password and bcrypt it\n| [schema.Reference][ref] | Ensures the field contains a reference to another _existing_ API item\n| [schema.AnyOf][any]     | Ensures that at least one sub-validator is valid\n| [schema.AllOf][all]     | Ensures that at least all sub-validators are valid\n\n[str]:    https://godoc.org/github.com/rs/rest-layer/schema#String\n[int]:    https://godoc.org/github.com/rs/rest-layer/schema#Integer\n[float]:  https://godoc.org/github.com/rs/rest-layer/schema#Float\n[bool]:   https://godoc.org/github.com/rs/rest-layer/schema#Bool\n[array]:  https://godoc.org/github.com/rs/rest-layer/schema#Array\n[dict]:   https://godoc.org/github.com/rs/rest-layer/schema#Dict\n[object]: https://godoc.org/github.com/rs/rest-layer/schema#Object\n[time]:   https://godoc.org/github.com/rs/rest-layer/schema#Time\n[url]:    https://godoc.org/github.com/rs/rest-layer/schema#URL\n[ip]:     https://godoc.org/github.com/rs/rest-layer/schema#IP\n[pswd]:   https://godoc.org/github.com/rs/rest-layer/schema#Password\n[ref]:    https://godoc.org/github.com/rs/rest-layer/schema#Reference\n[any]:    https://godoc.org/github.com/rs/rest-layer/schema#AnyOf\n[all]:    https://godoc.org/github.com/rs/rest-layer/schema#AllOf\n\nSome common hook handler to be used with `OnInit` and `OnUpdate` are also provided:\n\n| Hook           | Description\n| -------------- | -------------\n| `schema.Now`   | Returns the current time ignoring the input (current) value.\n| `schema.NewID` | Returns a unique identifier using [xid](https://github.com/rs/xid) if input value is `nil`.\n\nSome common field configuration are also provided as variables:\n\n| Field Config           | Description\n| ---------------------- | -------------\n| `schema.IDField`       | A required, read-only field with `schema.NewID` set as `OnInit` hook and a `schema.String` validator matching [xid](https://github.com/rs/xid) format.\n| `schema.CreatedField`  | A required, read-only field with `schema.Now` set on `OnInit` hook with a `schema.Time` validator.\n| `schema.UpdatedField`  | A required, read-only field with `schema.Now` set on `OnInit` and `OnUpdate` hooks with a `schema.Time` validator.\n| `schema.PasswordField` | A hidden, required field with a `schema.Password` validator.\n\nHere is an example of schema declaration:\n\n```go\n// Define a post resource schema\npost = schema.Schema{\n\tFields: schema.Fields{\n\t\t// schema.*Field are shortcuts for common fields (identical to users' same fields)\n\t\t\"id\":      schema.IDField,\n\t\t\"created\": schema.CreatedField,\n\t\t\"updated\": schema.UpdatedField,\n\t\t// Define a user field which references the user owning the post.\n\t\t// See bellow, the content of this field is enforced by the fact\n\t\t// that posts is a sub-resource of users.\n\t\t\"user\": {\n\t\t\tRequired: true,\n\t\t\tFilterable: true,\n\t\t\tValidator: \u0026schema.Reference{\n\t\t\t\tPath: \"users\",\n\t\t\t},\n\t\t},\n\t\t// Sub-documents are handled via a sub-schema\n\t\t\"meta\": {\n\t\t\tSchema: \u0026schema.Schema{\n\t\t\t\tFields: schema.Fields{\n\t\t\t\t\t\"title\": {\n\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\tValidator: \u0026schema.String{\n\t\t\t\t\t\t\tMaxLen: 150,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t\"body\": {\n\t\t\t\t\t\tValidator: \u0026schema.String{\n\t\t\t\t\t\t\tMaxLen: 100000,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n}\n```\n\n### Binding\n\nNow you just need to bind this schema at a specific endpoint on the [resource.Index](https://godoc.org/github.com/rs/rest-layer/resource#Index) object:\n\n```go\nindex := resource.NewIndex()\nposts := index.Bind(\"posts\", post, mem.NewHandler(), resource.DefaultConf)\n```\n\nThis tells the `resource.Index` to bind the `post` schema at the `posts` endpoint. The resource collection URL is then `/posts` and item URLs are `/posts/\u003cpost_id\u003e`.\n\nThe [resource.DefaultConf](https://godoc.org/github.com/rs/rest-layer/resource#pkg-variables) variable is a pre-defined [resource.Conf](https://godoc.org/github.com/rs/rest-layer/resource#Conf) type with sensible defaults. You can customize the resource behavior using a custom configuration.\n\nThe `resource.Conf` type has the following customizable properties:\n\n| Property                 | Description\n| ------------------------ | -------------\n| `AllowedModes`           | A list of `resource.Mode` allowed for the resource.\n| `PaginationDefaultLimit` | If set, pagination is enabled for list requests by default with the number of item per page as defined here. Note that the default ony applies to list (GET) requests, i.e. it does _not_ apply for clear (DELETE) requests.\n| `ForceTotal`             | Control the behavior of the computation of `X-Total` header and the `total` query-string parameter. See `resource.ForceTotalMode` for available options.\n\n### Modes\n\nREST Layer handles mapping of HTTP methods to your resource URLs automatically. With REST, there is two kind of resource URL paths: collection and item URLs. Collection URLs (`/\u003cresource\u003e`) are pointing to the collection of items, while item URL (`/\u003cresource\u003e/\u003citem_id\u003e`) points to a specific item in that collection. HTTP methods are used to perform [CRUDL](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) operations on those resources.\n\nYou can easily dis/allow an operation on a per resource basis using `resource.Conf`'s `AllowedModes` property. The use of modes instead of HTTP methods in the configuration adds a layer of abstraction necessary to handle specific cases like `PUT` HTTP method performing a `create` if the specified item does not exist or a `replace` if it does. This gives you precise control of what you want to allow or not.\n\nModes are passed as configuration to resources as follow:\n\n```go\nusers := index.Bind(\"users\", user, mem.NewHandler(), resource.Conf{\n\tAllowedModes: []resource.Mode{resource.Read, resource.List, resource.Create, resource.Delete},\n})\n```\n\nThe following table shows how REST layer maps CRUDL operations to HTTP methods and `modes`:\n\n\n| Mode      | HTTP Method | Context    | Description\n| --------- | ----------- | ---------- | -------------\n| `Read`    | GET         | Item       | Get an individual item by its ID.\n| `List`    | GET         | Collection | List/find items using filters and sorts.\n| `Create`  | POST        | Collection | Create an item letting the system generate its ID.\n| `Create`  | PUT         | Item       | Create an item by choosing its ID.\n| `Update`  | PATCH       | Item       | Partially modify the item following [RFC-5789](http://tools.ietf.org/html/rfc5789), [RFC-6902](https://tools.ietf.org/html/rfc6902).\n| `Replace` | PUT         | Item       | Replace the item by a new on.\n| `Delete`  | DELETE      | Item       | Delete the item by its ID.\n| `Clear`   | DELETE      | Collection | Delete all items from the collection matching the context and/or filters.\n\nNote on GraphQL support and modes: current implementation of GraphQL doesn't support mutation. Thus only resources with `Read` and `List` modes will be exposed with GraphQL. Support for other modes will be added in the future.\n\n### Hooks\n\nHooks are piece of code you can attach before or after an operation is performed on a resource. A hook is a Go type implementing one of the event handler interface below, and attached to a resource via the [Resource.Use](https://godoc.org/github.com/rs/rest-layer/resource#Resource.Use) method.\n\n| Hook Interface         | Description\n| ---------------------- | -------------\n| [FindEventHandler]     | Defines a function called when the resource is listed with or without a query. Note that hook is called for both resource and item fetch as well a prior to updates and deletes.\n| [FoundEventHandler]    | Defines a function called with the result of a find on resource.\n| [GetEventHandler]      | Defines a function called when a get is performed on an item of the resource. Note: when multi-get is performed this hook is called for each items id individually.\n| [GotEventHandler]      | Defines a function called with the result of a get on a resource.\n| [InsertEventHandler]   | Defines a function called before an item is inserted.\n| [InsertedEventHandler] | Defines a function called after an item has been inserted.\n| [UpdateEventHandler]   | Defines a function called before an item is updated.\n| [UpdatedEventHandler]  | Defines a function called after an item has been updated.\n| [DeleteEventHandler]   | Defines a function called before an item is deleted.\n| [DeletedEventHandler]  | Defines a function called after an item has been deleted.\n| [ClearEventHandler]    | Defines a function called before a resource is cleared.\n| [ClearedEventHandler]  | Defines a function called after a resource has been cleared.\n\n[FindEventHandler]:     https://godoc.org/github.com/rs/rest-layer/resource#FindEventHandler\n[FoundEventHandler]:    https://godoc.org/github.com/rs/rest-layer/resource#FoundEventHandler\n[GetEventHandler]:      https://godoc.org/github.com/rs/rest-layer/resource#GetEventHandler\n[GotEventHandler]:      https://godoc.org/github.com/rs/rest-layer/resource#GotEventHandler\n[InsertEventHandler]:   https://godoc.org/github.com/rs/rest-layer/resource#InsertEventHandler\n[InsertedEventHandler]: https://godoc.org/github.com/rs/rest-layer/resource#InsertedEventHandler\n[UpdateEventHandler]:   https://godoc.org/github.com/rs/rest-layer/resource#UpdateEventHandler\n[UpdatedEventHandler]:  https://godoc.org/github.com/rs/rest-layer/resource#UpdatedEventHandler\n[DeleteEventHandler]:   https://godoc.org/github.com/rs/rest-layer/resource#DeleteEventHandler\n[DeletedEventHandler]:  https://godoc.org/github.com/rs/rest-layer/resource#DeletedEventHandler\n[ClearEventHandler]:    https://godoc.org/github.com/rs/rest-layer/resource#ClearEventHandler\n[ClearedEventHandler]:  https://godoc.org/github.com/rs/rest-layer/resource#ClearedEventHandler\n\nNote that these are resource level hooks, and do not correspond one-to-one to `rest` or `graphql` operation. For the `rest` package in particular, note that a HTTP request to `GET` an item by ID, will result in a `Find` and not a `Get` call which will triggering the `OnFind` and `OnFound` hooks to be called, not `OnGet` and `OnGot`. Similarly, a `PATCH` or `PUT` request will call `Find` before it calls `Update`, which will trigger the same hooks. If your hooks logic require knowing which rest-level operation is performed see [rest.RouteFromContext](https://godoc.org/github.com/rs/rest-layer/rest#RouteFromContext)\n\nAll hooks functions get a `context.Context` as first argument. If a network call must be performed from the hook, the context's deadline must be respected. If a hook returns an error, the whole request is aborted with that error. You can also use the context to pass data to your hooks from a middleware executed before REST Layer. This can be used to manage authentication for instance. See [examples/auth](https://github.com/rs/rest-layer/blob/master/examples/auth/main.go) to see an example.\n\nHooks that get passed both an an error and/or an item, such as [GotEventHandler], [UpdatedEventHandler], [DeletedEventHandler] should insert guards to handle the error being set and/or the item not being set; both can be true in some cases. It's also allowed to set items or errors to nil, which is why double pointers are often used.\n\n```go\nfunc (hook Hook) OnGot(ctx context.Context, item **resource.Item, err *error) {\n\t// Guard.\n\tif *err != nil || *item == nil {\n\t\treturn\n\t}\n\t// ...\n}\n```\n\n```go\nfunc (hook Hook) OnGot(ctx context.Context, item **resource.Item, err *error) {\n\t// Overriding an error response.\n\tif *err != nil || *item == nil {\n\t\t(*err) = nil\n\t\t(*item) = fallbackItem()\n\t}\n\t// ...\n}\n```\n\n### Sub Resources\n\nSub resources can be used to express a one-to-may parent-child relationship between two resources. A sub-resource is automatically filtered by its parent on the field specified as second argument of the `Bind` method.\n\nTo create a sub-resource, you bind you resource on the object returned by the binding of the parent resource. For instance, here we bind a `comments` resource to a `posts` resource:\n\n```go\nposts := index.Bind(\"posts\", post, mem.NewHandler(), resource.DefaultConf)\n// Bind comment as sub-resource of the posts resource\nposts.Bind(\"comments\", \"post\", comment, mem.NewHandler(), resource.DefaultConf)\n```\n\nThe second argument `post` defines the field in the `comments` resource that refers to the parent. This field must be present in the resource and the backend storage must support filtering on it. As a result, we get a new hierarchical route as follow:\n\n    /posts/:post_id/comments[/:comment_id]\n\nWhen performing a `GET` on `/posts/:post_id/comments`, it is like adding the filter `{\"post\":\"\u003cpost_id\u003e\"}` to the request to comments resource.\n\nAdditionally, thanks to REST Layer's [embedding](#embedding), this relationship can be embedded in the parent object as a sub-query:\n\n    /posts?fields=id,title,comments(limit=5,sort=-updated){id,user{id,name},message}\n\nHere we would get all post with their respective 5 last comments embedded in the `comments` field of each post object with the user commenting to post embedded in each comment's sub-document:\n\n```json\n[\n    {\n        \"id\": \"abc\",\n        \"comments\": [\n            {\n                \"id\": \"def\",\n                \"user\": {\n                    \"id\": \"ghi\",\n                    \"name\": \"John Doe\",\n                },\n                \"message\": \"Last comment\"\n            },\n        ]\n    },\n]\n```\n\nSee [embedding](#embedding) for more information.\n\n### Dependency\n\nFields can depend on other fields in order to be changed. To configure a dependency, set a filter on the `Dependency` property of the field using the [query.MustParsePredicate()](https://godoc.org/github.com/rs/rest-layer/schema/queru#MustParsePredicate) method.\n\nIn this example, the `body` field can't be changed if the `published` field is not set to `true`:\n\n```go\npost = schema.Schema{\n\tFields: schema.Fields{\n\t\t\"published\": schema.Field{\n\t\t\tValidator:  \u0026schema.Bool{},\n\t\t},\n\t\t\"body\": {\n\t\t\tDependency: query.MustParsePredicate(`{\"published\": true}`),\n\t\t\tValidator:  \u0026schema.String{},\n\t\t},\n\t},\n}\n```\n\n## HTTP Request Headers\n\n### Prefer\n\nCurrently supported values are:\n\n- [return=minimal](https://tools.ietf.org/html/rfc7240#section-4.2): When a request is successfully (HTTP Response Status of `200` or `201`), response body is not returned. For Response Status of `200 OK`, status becomes `204 No Content`. Can be used for e.g `PUT`, `POST` and `PATCH` methods, where returned body will be known by the client.\n- [return=no-content](https://msdn.microsoft.com/en-us/library/hh537533.aspx): same as `return=minimal`.\n\n```sh\n$ echo '[{\"op\": \"add\", \"path\":\"/foo\", \"value\": \"bar\"}]' | http PATCH :8080/users/ar6ej4mkj5lfl688d8lg If-Match:'\"1234567890123456789012345678901234567890\"' \\\nContent-Type: application/json-patch+json \\\nPrefer: return=minimal\nHTTP/1.1 204 No Content\n```\n\n### Content-Type\n\nThe Content-Type of the request body. Most HTTP methods only support `\"aplication/json\"` by default, but `PUT` requests also allow `\"application/json-patch+json\"`.\n\n## HTTP Request Methods\n\nFollowing HTTP Methods are currently supported by rest-layer.\n\n### OPTIONS\n\nUsed to tell the client which HTTP Methods are supported for any given path.\n\n### HEAD\n\nThe same as `GET`, except it includes only headers in the response.\n\n### GET\n\nUsed to retrieve a (projected[#field-selection]) resource document by specifying it's `ID` in the path, or to retrieve a paginated view of documents matching a [query](#quering).\n\n### POST\n\nUsed to create new resource document when the `ID` can be generated by the server. Field default values are set for omitted fields, and `OnCreate` field hooks are issued.\n\n### PUT\n\nUsed to create or update a single resource document by specifying it's `ID` in the path. Field default values are set for omitted fields. If the document did not previously exist `OnCreate` field hooks are issued, otherwise `OnUpdate` field hooks are issued.\n\n`If-Match` [concurrency protection](#data-integrity-and-concurrency-control) could be used if relevant.\n\n### PATCH\n\nUsed to create or patch a single resource document by specifying it's `ID` in the path. `OnUpdate` field hooks are issued.\n\nREST Layer supports two PATCH protocols, that can be specified via the `Content-Type` header.\n\n- Simple filed replacement [RFC-5789](http://tools.ietf.org/html/rfc5789) - this protocol will update only supplied top level fields, and will leave other fields in the document intact. This means that this protocol can't delete fields. Using this protocol is specified with `Content-Type: application/json` HTTP Request header.\n\n- [JSON-Patch/RFC-6902](https://tools.ietf.org/html/rfc6902) - When patching deeply nested documents, it is more convenient to use protocol designed especially for this. Using this protocol is specified with `Content-Type: application/json-patch+json` HTTP Request header.\n\n`If-Match` [concurrency protection](#data-integrity-and-concurrency-control) could be used if relevant.\n\nExample JSON Patch Request where we utilize concurrency control ask for the response body to be omitted:\n\n```sh\n$ echo '[{\"op\": \"add\", \"path\":\"/foo\", \"value\": \"bar\"}]' | http PATCH :8080/users/ar6ej4mkj5lfl688d8lg If-Match:'\"1234567890123456789012345678901234567890\"' \\\nContent-Type: application/json-patch+json \\\nPrefer: return=minimal\nHTTP/1.1 204 No Content\n```\n\n### DELETE\n\nUsed to delete single resource document given its `ID`, or multiple documents matching a [query](#quering).\n\n## Querying\n\nWhen supplying query parameters be sure to honor URL encoding scheme. If you need to include `+` sign, use `%2B`, etc.\n\n### Filtering\n\nTo filter resources, you use the `filter` query-string parameter. The format of the parameter is inspired by the [MongoDB query format](http://docs.mongodb.org/manual/tutorial/query-documents/). The `filter` parameter can be used with `GET` and `DELETE` methods on resource URLs.\n\nTo use a resource field with the `filter` parameter, the field must be defined on the resource and the `Filterable` field property must be set to `true`. You may want to ensure the backend database has this field indexed when enabled.\n\nTo specify equality condition, use the query `{\u003cfield\u003e: \u003cvalue\u003e}` to select all items with `\u003cfield\u003e` equal `\u003cvalue\u003e`. REST Layer will complain with a `422` HTTP error if any field queried is not defined in the resource schema or is using an operator incompatible with field type (i.e.: `$lt` on a string field).\n\nA query can specify conditions for more than one field. Implicitly, a logical `AND` conjunction connects the clauses so that the query selects the items that match all the conditions.\n\nIt is also possible to use an explicit `$and` operator to join each clause with a logical `AND`. There are sometimes good use-cases for this, such as when joining two independent `$or` queries that must both match, or when programmatically merging multiple queries with potentially overlapping fields.\n\n```js\n{$and: [\n  {$or: [{quantity: {$gt: 100}}, {price: {$lt: 9.95}}]},\n  {$or: [{length: {$lt: 1000}}, {width: {$lt: 1000}}\n]}\n```\n\nUsing the the `$or` operator, you can specify a compound query that joins each clause with a logical `OR` conjunction so that the query selects the items that match at least one condition.\n\nIn the following example, the query document selects all items in the collection where the field `quantity` has a value greater than (`$gt`) `100` or the value of the `price` field is less than (`$lt`) `9.95`:\n\n```js\n{$or: [{quantity: {$gt: 100}}, {price: {$lt: 9.95}}]}\n```\n\nMatch on sub-fields is performed through field path separated by dots. This example shows an exact match on the sub-fields `country` and `city` of the `address` sub-document:\n\n```js\n{address.country: \"France\", address.city: \"Paris\"}\n```\n\nSome operators can change the type of match. For instance `$in` can be used to match a field against several values. For instance, to select all items with the `type` field equal either `food` or `snacks`, use the following query:\n\n```js\n{type: {$in: [\"food\", \"snacks\"]}}\n```\n\nThe opposite `$nin` is also available.\n\nThe following numeric comparisons operators are supported: `$lt`, `$lte`, `$gt`, `$gte`.\n\nThe `$exists` operator matches documents containing the field, even if this field is `null`.\n\n```js\n{type: {$exists: true}}\n```\n\nYou can invert the operator by passing `false`.\n\nThere is also a `$regex` operator that matches documents containing the field given as a regular expression. In general, the syntax of the regular expressions accepted is the same general syntax used by Perl, Python, and other languages.\nMore precisely, it is the syntax accepted by RE2 and described at [https://golang.org/s/re2syntax](https://golang.org/s/re2syntax), except for `\\C`.\n\nFlags are supported for more control over regular expressions. Flag syntax is xyz (set) or -xyz (clear) or xy-z (set xy, clear z).\nThe flags are:\n\n|Flag  |Mode                                                                       | Default\n| ---- | ------------------------------------------------------------------------- | -----\n|`i`   |case-insensitive                                                           | false\n|`m`   |multi-line mode: ^ and $ match begin/end line in addition to begin/end text| false\n|`s`   |let . match \\n                                                             | false\n|`U`   |non-greedy: swap meaning of x\\* and x\\*?, x+ and x+?, etc                  | false\n\nFor example the following regular expression would match any document with a field `type` and its value `rest-layer`.\n\n```js\n{type: {$regex: \"re[s]{1}t-la.+r\"}}\n```\n\nThe same example with flags:\n\n```js\n{type: {$regex: \"(?i)re[s]{1}t-LAYER\"}}\n```\n\nHowever, keep in mind that Storers have to support regular expression and depending on the implementation of the storage handler the accepted syntax may vary.\nAn error of `ErrNotImplemented` will be returned for those storage back-ends which do not support the `$regex` operator.\n\nThe operator `$not` functions as an opposite operator to `$regex`. Unlike MongoDB, we do not allow `$not` as a general negation operator.\n\nThe `$elemMatch` operator matches documents that contain an array field with at least one element that matches all the specified query criteria.\n```go\n\t\t\t\"telephones\": schema.Field{\n\t\t\t\tFilterable: true,\n\t\t\t\tValidator: \u0026schema.Array{\n\t\t\t\t\tValues: schema.Field{\n\t\t\t\t\t\tValidator:  \u0026schema.Object{Schema: \u0026Telephone},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n```\n\nMatching documents that contain specific values within array objects can be done with `$elemMatch`:\n\n```js\n{telephones: {$elemMatch: {name: \"John Snow\", active: true}}}\n```\n\nThe snippet above will return all documents, which `telephones` array field contains objects that have `name` **_AND_** `active` fields matching queried values.\n\u003e Note that documents returned may contain other objects in `telephones` that don't match the query above, but at least one object will do. Further filtering could be needed on the API client side.\n\n#### *$elemMatch* Limitation\n\n`$elemMatch` will work only for arrays of objects for now. Later it could be extended to work on plain arrays e.g:\n\n```js\n{numbers: {$elemMatch: {$gt: 20}}}\n```\n\n#### Filter operators\n\n| Operator     | Usage                           | Description\n| -------------| --------------------------------| ------------\n| `$or`        | `{$or: [{a: \"b\"}, {a: \"c\"}]}`   | Join two clauses with a logical `OR` conjunction.\n| `$and`       | `{$and: [{a: \"b\"}, {b: \"c\"}]}`  | Join two clauses with a logical `AND` conjunction.\n| `$in`        | `{a: {$in: [\"b\", \"c\"]}}`        | Match a field against several values.\n| `$nin`       | `{a: {$nin: [\"b\", \"c\"]}}`       | Opposite of `$in`.\n| `$lt`        | `{a: {$lt: 10}}`                | Fields value is lower than specified number.\n| `$lte`       | `{a: {$lte: 10}}`               | Fields value is lower than or equal to the specified number.\n| `$gt`        | `{a: {$gt: 10}}`                | Fields value is greater than specified number.\n| `$gte`       | `{a: {$gte: 10}}`               | Fields value is greater than or equal to the specified number.\n| `$exists`    | `{a: {$exists: true}}`          | Match if the field is present (or not if set to `false`) in the item, event if `nil`.\n| `$regex`     | `{a: {$regex: \"fo[o]{1}\"}}`     | Match regular expression on a field's value.\n| `$not`       | `{a: {$not: \"fo[o]{1}\"}}`       | Opposite of `$regex`.\n| `$elemMatch` | `{a: {$elemMatch: {b: \"foo\"}}}` | Match array items against multiple query criteria.\n\n*Some storage handlers may not support all operators. Refer to the storage handler's documentation for more info.*\n\n### Sorting\n\nSorting of resource items is defined through the `sort` query-string parameter. The `sort` value is a list of resource's fields separated by comas (`,`). To invert a field's sort, you can prefix its name with a minus (`-`) character. The `sort` parameter can be used with `GET` and `DELETE` methods on resource URLs.\n\nTo use a resource field with the `sort` parameter, the field must be defined on the resource and the `Sortable` field property must be set to `true`. You may want to ensure the backend database has this field indexed when enabled.\n\nHere we sort the result by ascending quantity and descending create time:\n\n    /posts?sort=quantity,-created\n\n### Field Selection\n\nREST APIs tend to grow over time. Resources get more and more fields to fulfill the needs for new features. But each time fields are added, all existing API clients automatically get the additional cost. This tend to lead to huge waste of bandwidth and added latency due to the transfer of unnecessary data. As a workaround, the `field` parameter can be used to minimize and customize the response body from requests with a `GET`, `POST`, `PUT`  or `PATCH` method on resource URLs.\n\nREST Layer provides a powerful fields selection (also named projection) system. If you provide the `fields` parameter with a list of fields for the resource you are interested in separated by commas, only those fields will be returned in the document:\n\n```sh\n$ http -b :8080/api/users/ar6eimekj5lfktka9mt0 fields=='id,name'\n{\n    \"id\": \"ar6eimekj5lfktka9mt0\",\n    \"name\": \"John Doe\"\n}\n```\n\nIf your document has sub-fields, you can use brackets to select sub-fields:\n\n```sh\n$ http -b :8080/api/users/ar6eimekj5lfktka9mt0/posts fields=='meta{title,body}'\n[\n    {\n        \"_etag\": \"ar6eimukj5lfl07r0uv0\",\n        \"meta\": {\n            \"title\": \"test\",\n            \"body\": \"example\"\n        }\n    }\n]\n```\n\nAlso `all fields` expansion is supported:\n\n```sh\n$ http -b :8080/api/users/ar6eimekj5lfktka9mt0/posts fields=='*,user{*}'\n[\n    {\n        \"_etag\": \"ar6eimukj5lfl07r0uv0\",\n        \"id\": \"ar6eimukj5lfl07r0ugz\",\n        \"created\": \"2015-07-27T21:46:55.355857401+02:00\",\n        \"updated\": \"2015-07-27T21:46:55.355857989+02:00\",\n        \"user\": {\n          \"id\": \"ar6eimukj5lfl07gzb0b\",\n          \"created\": \"2015-07-24T21:46:55.355857401+02:00\",\n          \"updated\": \"2015-07-24T21:46:55.355857989+02:00\",\n          \"name\": \"John Snow\",\n        },\n        \"meta\": {\n            \"title\": \"test\",\n            \"body\": \"example\"\n        }\n    }\n]\n```\n\n#### Field Aliasing\n\nIt's also possible to rename fields in the response using aliasing. To create an alias, prefix the field name by the wanted alias separated by a colon (`:`):\n\n```sh\n$ http -b :8080/api/users/ar6eimekj5lfktka9mt0 fields=='id,name,n:name'\n{\n    \"id\": \"ar6eimekj5lfktka9mt0\",\n    \"n\": \"John Doe\",\n    \"name\": \"John Doe\"\n}\n```\n\nAs you see, you can specify the same field several times. It doesn't seem useful in this example, but with [fields parameters](#field-parameters), it becomes very powerful (see below).\n\nAliasing works with sub-fields as well:\n\n```sh\n$ http -b :8080/api/users/ar6eimekj5lfktka9mt0/posts fields=='meta{title,b:body}'\n[\n    {\n        \"_etag\": \"ar6eimukj5lfl07r0uv0\",\n        \"meta\": {\n            \"title\": \"test\",\n            \"b\": \"example\"\n        }\n    }\n]\n```\n\n#### Field Parameters\n\nField parameters are used to apply a transformation on the value of a field using custom logic.\n\nFor instance, if you are using an on demand dynamic image resizer, you may want to expose the capability of this service, without requiring from the client to learn another URL based API. Wouldn't it be better if we could just ask the API to return the `thumbnail_url` dynamically transformed with the desired dimensions?\n\nBy combining field aliasing and field parameters, we can expose this resizer API as follow:\n\n```sh\n$ http -b :8080/api/videos fields=='id,\n                                    thumb_small_url:thumbnail_url(width:80,height:60),\n                                    thumb_large_url:thumbnail_url(width:800,height:600)'\n[\n    {\n        \"_etag\": \"ar6eimukj5lfl07r0uv0\",\n        \"thumb_small_url\": \"http://cdn.com/path/to/image-80w60h.jpg\",\n        \"thumb_large_url\": \"http://cdn.com/path/to/image-800w600h.jpg\"\n    }\n]\n```\n\nThe example above show the same field represented twice but with some useful value transformations.\n\nTo add parameters on a field, use the `Params` property of the `schema.Field` type as follow:\n\n```go\nschema.Schema{\n\tFields: schema.Fields{\n\t\t\"field\": {\n\t\t\tParams: schema.Params{\n\t\t\t\t\"width\": {\n\t\t\t\t\tDescription: \"Change the width of the thumbnail to the value in pixels\",\n\t\t\t\t\tValidator: schema.Integer{}\n\t\t\t\t},\n\t\t\t\t\"height\": {\n\t\t\t\t\tDescription: \"Change the width of the thumbnail to the value in pixels\",\n\t\t\t\t\tValidator: schema.Integer{},\n\t\t\t\t},\n\t\t\t},\n\t\t\tHandler: func(ctx context.Context, value interface{}, params map[string]interface{}) (interface{}, error) {\n\t\t\t\t// your transformation logic here\n\t\t\t\treturn value, nil\n\t\t\t},\n\t\t},\n\t},\n}\n```\n\nOnly parameters listed in the `Params` field will be accepted. You `Handler` function is called with the current value of the field and parameters sent by the user if any. Your function can apply wanted transformations on the value and return it. If an error is returned, a `422` error will be triggered with your error message associated to the field.\n\n#### Embedding\n\nWith sub-fields notation you can also request referenced resources or connections (sub-resources). REST Layer will recognize them automatically and fetch the associated resources in order embed their data in the response. This can save a lot of unnecessary sequential round-trips:\n\n```sh\n$ http -b :8080/api/users/ar6eimekj5lfktka9mt0/posts \\\n  fields=='meta{title},user{id,name},comments(sort:\"-created\",limit:10){user{id,name},body}'\n  [\n    {\n        \"_etag\": \"ar6eimukj5lfl07r0uv0\",\n        \"meta\": {\n            \"title\": \"test\"\n        },\n        \"user\": {\n            \"id\": \"ar6eimul07lfae7r4b5l\",\n            \"name\": \"John Doe\"\n        },\n        \"comments\": [\n            {\n                \"user\": {\n                    \"id\": \"ar6emul0kj5lfae7reimu\",\n                    \"name\": \"Paul Wolf\"\n                },\n                \"body\": \"That's awesome!\"\n            },\n            ...\n        ]\n    },\n    ...\n]\n```\n\nIn the above example, the `user` field is a reference on the `users` resource. REST Layer did fetch the user referenced by the post and embedded the requested sub-fields (`id` and `name`). Same for `comments`: `comments` is set as a sub-resource of the `posts` resource. With this syntax, it's easy to get the last 10 comments on the post in the same REST request. For each of those comment, we asked to embed the `user` field referenced resource with `id` and `name` fields again.\n\nNotice the `sort` and `limit` parameters passed to the `comments` field. Those are field parameter automatically exposed by connections to let you control the embedded list order, filter and pagination. You can use `sort`, `filter`, `skip`, `page` and `limit` parameters with those field with the same syntax as their top level query-string parameter counterpart.\n\nSuch request can quickly generate a lot of queries on the storage handler. To ensure a fast response time, REST layer tries to coalesce those storage requests and to execute them concurrently whenever possible.\n\n### Pagination\n\nPagination is supported on collection URLs using the `page` and `limit` query-string parameters and can be used for resource list view URLs with request method `GET` and `DELETE`. If you don't define a default pagination limit using `PaginationDefaultLimit` resource configuration parameter, the resource won't be paginated for list `GET` requests until you provide the `limit` query-string parameter. The `PaginationDefaultLimit` does not apply to list `DELETE` requests, but the `limit` and `page` parameters may still be used to delete a subset of items.\n\nIf your collections are large enough, failing to define a reasonable `PaginationDefaultLimit` parameter may quickly render your API unusable.\n\n### Skipping\n\nSkipping of resource items is defined through the `skip` query-string parameter. The `skip` value is a positive integer defining the number of items to skip when querying for items, and can be applied for requests with method `GET` or `DELETE`.\n\nSkip the first 10 items of the result:\n\n    /posts?skip=10\n\nReturn the first 2 items after skipping the first 10 of the result:\n\n    /posts?skip=10\u0026limit=2\n\nThe `skip` parameter can be used in conjunction with the `page` parameter. You may want them both when for instance, you show the first N elements of a list and then allow to paginate the remaining items:\n\nShow the first 2 elements:\n\n    /posts?limit=2\n\nPaginate the rest of the list:\n\n    /posts?skip=2\u0026page=1\u0026limit=10\n\n## Authentication and Authorization\n\nREST Layer doesn't provide any kind of support for authentication. Identifying the user is out of the scope of a REST API, it should be performed by an OAuth server. The OAuth endpoints could be either hosted on the same code base as your API or live in a different app. The recommended way to integrate OAuth or any other kind of authentication with REST Layer is through a signed token like [JWT](https://jwt.io).\n\nIn this schema, the authentication service identifies the user and stores data relevant to the user's identification in a JWT token. This token is sent to the API client as a [bearer token](https://tools.ietf.org/html/rfc6750), through the `access-token` query-string parameter or the `Authorization` HTTP header. A http middleware then decodes and verifies this token, extracts user's info from it and stores it into the context. In REST layer, user info is now accessible from your [resource hooks](#hooks) so you can change the query lookup or ensure mutated objects are owned by the user in order to handle the authorization part.\n\nSee the [JWT auth example](https://github.com/rs/rest-layer/blob/master/examples/auth-jwt/main.go) for more info.\n\n## Conditional Requests\n\nEach stored resource provides information on the last time it was updated (`Last-Modified`), along with a hash value computed on the representation itself (`ETag`). These headers allow clients to perform conditional requests by using the `If-Modified-Since` header:\n\n```sh\n$ http :8080/users/ar6ej4mkj5lfl688d8lg If-Modified-Since:'Wed, 05 Dec 2012 09:53:07 GMT'\nHTTP/1.1 304 Not Modified\n```\n\nor the `If-None-Match` header:\n\n```sh\n$ http :8080/users/ar6ej4mkj5lfl688d8lg If-None-Match:'\"1234567890123456789012345678901234567890\"'\nHTTP/1.1 304 Not Modified\n```\n\n## Data Integrity and Concurrency Control\n\nAPI responses include a `ETag` header which also allows for proper concurrency control. An `ETag` is a hash value representing the current state of the resource on the server. Clients may choose to ensure they update (`PATCH` or `PUT`) or delete (`DELETE`) a resource in the state they know it by providing the last known `ETag` for that resource. This prevents overwriting items with obsolete data.\n\nConsider the following workflow:\n\n```sh\n$ http PATCH :8080/users/ar6ej4mkj5lfl688d8lg If-Match:'\"1234567890123456789012345678901234567890\"' \\\n    name='John Doe'\nHTTP/1.1 412 Precondition Failed\n```\n\nWhat went wrong? We provided a `If-Match` header with the last known `ETag`, but its value did not match the current `ETag` of the item currently stored on the server, so we got a 412 Precondition Failed.\n\nWhen this happens, it's up to the client to decide whether to inform the user of the error and/or re-fetch the latest version of the document to get the latest `ETag` before retrying the operation.\n\n```sh\n$ http PATCH :8080/users/ar6ej4mkj5lfl688d8lg If-Match:'\"80b81f314712932a4d4ea75ab0b76a4eea613012\"' \\\n    name='John Doe'\nHTTP/1.1 200 OK\nEtag: \"7bb7a71b0f66197aa07c4c8fc9564616\"\nLast-Modified: Mon, 27 Jul 2015 19:36:19 GMT\n```\n\nThis time the update operation was accepted and we got a new `ETag` for the updated resource.\n\nConcurrency control header `If-Match` can be used with all mutation methods on item URLs: `PATCH` (update), `PUT` (replace) and `DELETE` (delete).\n\n## Data Validation\n\nData validation is provided out-of-the-box. Your configuration includes a schema definition for every resource managed by the API. Data sent to the API to be inserted/updated will be validated against the schema, and a resource will only be updated if validation passes. See [Field Definition](#field-definition) section to know more about how to configure your validators.\n\n```sh\n$ http  :8080/api/users name:=1 foo=bar\nHTTP/1.1 422 status code 422\nContent-Length: 110\nContent-Type: application/json\nDate: Thu, 30 Jul 2015 21:56:39 GMT\nVary: Origin\n\n{\n    \"code\": 422,\n    \"message\": \"Document contains error(s)\",\n    \"issues\": {\n        \"foo\": [\n            \"invalid field\"\n        ],\n        \"name\": [\n            \"not a string\"\n        ]\n    }\n}\n```\n\nIn the example above, the document did not validate so the request was rejected with description of the errors for each fields.\n\n### Nullable Values\n\nTo allow `null` value in addition the field type, you can use [schema.AnyOf](https://godoc.org/github.com/rs/rest-layer/schema#AnyOf) validator:\n\n```go\n\"nullable_field\": {\n\tValidator: schema.AnyOf{\n\t\tschema.String{},\n\t\tschema.Null{},\n\t},\n}\n```\n\n### Extensible Data Validation\n\nIt is very easy to add new validators. You just need to implement the [schema.FieldValidator](https://godoc.org/github.com/rs/rest-layer/schema#FieldValidator):\n\n```go\ntype FieldValidator interface {\n\tValidate(value interface{}) (interface{}, error)\n}\n```\n\nThe `Validate` method takes the value as argument and must either return the value back with some eventual transformation or an `error` if the validation failed.\n\nYour validator may also implement the optional [schema.Compiler](https://godoc.org/github.com/rs/rest-layer/schema#Compiler) interface:\n\n```go\ntype Compiler interface {\n\tCompile() error\n}\n```\n\nWhen a field validator implements this interface, the `Compile` method is called at the server initialization. It's a good place to pre-compute some data (i.e.: compile regexp) and verify validator configuration. If validator configuration contains issues, the `Compile` method must return an error, so the initialization of the resource will generate a fatal error.\n\nA validator may implement some advanced serialization or transformation of the data to optimize its storage. In order to read this data back and put it in a format suitable for JSON representation, a validator can implement the [schema.FieldSerializer](https://godoc.org/github.com/rs/rest-layer/schema#FieldSerializer) interface:\n\n```go\ntype FieldSerializer interface {\n\tSerialize(value interface{}) (interface{}, error)\n}\n```\n\nWhen a validator implements this interface, the method is called with the field's value just before JSON marshaling. You should return an error if the format stored in the db is invalid and can't be converted back into a suitable representation.\n\nSee [schema.IP](https://godoc.org/github.com/rs/rest-layer/schema#IP) validator for an implementation example.\n\n## Timeout and Request Cancellation\n\nREST Layer respects [context](https://godoc.org/context) deadline from end to end. Timeout and request cancellation are thus handled through `context`. Since Go 1.8, context is cancelled automatically if the user closes the connection.\n\nWhen a request is stopped because the client closed the connection (context cancelled), the response HTTP status is set to `499 Client Closed Request` (for logging purpose). When a timeout is set and the request has reached this timeout, the response HTTP status is set to `509 Gateway Timeout`.\n\n## Logging\n\nYou can customize REST Layer logger by changing the `resource.Logger` function to call any logging framework you want.\n\nWe recommend using [zerolog](https://github.com/rs/zerolog). To configure REST Layer with `zerolog`, proceed as follow:\n\n```go\n// Init an alice handler chain (use your preferred one)\nc := alice.New()\n\n// Install a logger\nc = c.Append(hlog.NewHandler(log.With().Logger()))\n\n// Log API accesses\nc = c.Append(hlog.AccessHandler(func(r *http.Request, status, size int, duration time.Duration) {\n\thlog.FromRequest(r).Info().\n\t\tStr(\"method\", r.Method).\n\t\tStr(\"url\", r.URL.String()).\n\t\tInt(\"status\", status).\n\t\tInt(\"size\", size).\n\t\tDur(\"duration\", duration).\n\t\tMsg(\"\")\n}))\n\n// Add some fields to per-request logger context\nc = c.Append(hlog.RequestHandler(\"req\"))\nc = c.Append(hlog.RemoteAddrHandler(\"ip\"))\nc = c.Append(hlog.UserAgentHandler(\"ua\"))\nc = c.Append(hlog.RefererHandler(\"ref\"))\nc = c.Append(hlog.RequestIDHandler(\"req_id\", \"Request-Id\"))\n\n// Install zerolog/rest-layer adapter\nresource.LoggerLevel = resource.LogLevelDebug\nresource.Logger = func(ctx context.Context, level resource.LogLevel, msg string, fields map[string]interface{}) {\n\tzerolog.Ctx(ctx).WithLevel(zerolog.Level(level)).Fields(fields).Msg(msg)\n}\n\n```\n\nSee [zerolog](https://github.com/rs/zerolog) documentation for more info.\n\n## CORS\n\nREST Layer doesn't support CORS internally but relies on an external middleware to do so. You may use the [CORS](http://github.com/rs/cors) middleware to add CORS support to REST Layer if needed. Here is a basic example:\n\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/rs/cors\"\n\t\"github.com/rs/rest-layer/resource\"\n\t\"github.com/rs/rest-layer/rest\"\n)\n\nfunc main() {\n\tindex := resource.NewIndex()\n\n\t// configure your resources\n\n\tapi, err := rest.NewHandler(index)\n\tif err != nil {\n\t\tlog.Fatalf(\"Invalid API configuration: %s\", err)\n\t}\n\n\thandler := cors.Default().Handler(api)\n\tlog.Fatal(http.ListenAndServe(\":8080\", handler))\n}\n```\n\n## JSONP\n\nIn general you don’t really want to add JSONP when you can use CORS instead:\n\n\u003e There have been some criticisms raised about JSONP. Cross-origin resource sharing (CORS) is a more recent method of getting data from a server in a different domain, which addresses some of those criticisms. All modern browsers now support CORS making it a viable cross-browser alternative (source.)\n\u003e There are circumstances however when you do need JSONP, like when you have to support legacy software (IE6 anyone?)\n\nAs for CORS, REST Layer doesn't support JSONP directly but rely on an external middleware. Such a middleware is very easy to write. Here is an example:\n\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/rs/rest-layer/resource\"\n\t\"github.com/rs/rest-layer/rest\"\n)\n\nfunc main() {\n\tindex := resource.NewIndex()\n\n\t// configure your resources\n\n\tapi, err := rest.NewHandler(index)\n\tif err != nil {\n\t\tlog.Fatalf(\"Invalid API configuration: %s\", err)\n\t}\n\n\thandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tfn := r.URL.Query().Get(\"callback\")\n\t\tif fn != \"\" {\n\t\t\tw.Header().Set(\"Content-Type\", \"application/javascript\")\n\t\t\tw.Write([]byte(\";fn(\"))\n\t\t}\n\t\tapi.ServeHTTP(w, r)\n\t\tif fn != \"\" {\n\t\t\tw.Write([]byte(\");\"))\n\t\t}\n\t})\n\tlog.Fatal(http.ListenAndServe(\":8080\", handler))\n}\n```\n\n## Data Storage Handler\n\nREST Layer doesn't handle storage of resources directly. A [mem.MemoryHandler](https://godoc.org/github.com/rs/rest-layer/resource/testing/mem#MemoryHandler) is provided as an example but should be used for testing only.\n\nA resource storage handler is easy to write though. Some handlers for [popular databases are available](#main-storage-handlers), but you may want to write your own to put an API in front of anything you want. It is very easy to write a data storage handler, you just need to implement the [resource.Storer](https://godoc.org/github.com/rs/rest-layer/resource#Storer) interface:\n\n```go\ntype Storer interface {\n\tFind(ctx context.Context, q *query.Query) (*ItemList, error)\n\tInsert(ctx context.Context, items []*Item) error\n\tUpdate(ctx context.Context, item *Item, original *Item) error\n\tDelete(ctx context.Context, item *Item) error\n\tClear(ctx context.Context, q *query.Query) (int, error)\n}\n```\n\nMutation methods like `Update` and `Delete` must ensure they are atomically mutating the same item as specified in argument by checking their `ETag` (the stored `ETag` must match the `ETag` of the provided item). In case the handler can't guarantee that, the storage must be left untouched and a [resource.ErrConflict](https://godoc.org/github.com/rs/rest-layer/resource#pkg-variables) must be returned.\n\nIf the operation is not immediate, the method must listen for cancellation on the passed `ctx`. If the operation is stopped due to context cancellation, the function must return the result of the [ctx.Err()](https://godoc.org/golang.org/x/net/context#Context) method. See [this blog post](https://blog.golang.org/context) for more information about how `context` works.\n\nIf the backend storage is able to efficiently fetch multiple document by their id, it can implement the optional [resource.MultiGetter](https://godoc.org/github.com/rs/rest-layer/resource#MultiGetter) interface. REST Layer will automatically use it whenever possible.\n\nSee [resource.Storer](https://godoc.org/github.com/rs/rest-layer/resource#Storer) documentation for more information on resource storage handler implementation details.\n\n## Custom Response Formatter / Sender\n\nREST Layer lets you extend or replace the default response formatter and sender. To write a new response format, you need to implement the [rest.ResponseFormatter](https://godoc.org/github.com/rs/rest-layer/rest#ResponseFormatter) interface:\n\n```go\n// ResponseFormatter defines an interface responsible for formatting a the different types of response objects\ntype ResponseFormatter interface {\n\t// FormatItem formats a single item in a format ready to be serialized by the ResponseSender\n\tFormatItem(ctx context.Context, headers http.Header, i *resource.Item, skipBody bool) (context.Context, interface{})\n\t// FormatList formats a list of items in a format ready to be serialized by the ResponseSender\n\tFormatList(ctx context.Context, headers http.Header, l *resource.ItemList, skipBody bool) (context.Context, interface{})\n\t// FormatError formats a REST formated error or a simple error in a format ready to be serialized by the ResponseSender\n\tFormatError(ctx context.Context, headers http.Header, err error, skipBody bool) (context.Context, interface{})\n}\n```\n\nYou can also customize the response sender responsible for the serialization of the formatted payload:\n\n```go\n// ResponseSender defines an interface responsible for serializing and sending the response\n// to the http.ResponseWriter.\ntype ResponseSender interface {\n\t// Send serialize the body, sets the given headers and write everything to the provided response writer\n\tSend(ctx context.Context, w http.ResponseWriter, status int, headers http.Header, body interface{})\n}\n```\n\nThen set your response formatter and sender on the REST Layer HTTP handler like this:\n\n```go\napi, _ := rest.NewHandler(index)\napi.ResponseFormatter = \u0026myResponseFormatter{}\napi.ResponseSender = \u0026myResponseSender{}\n```\n\nYou may also extend the [DefaultResponseFormatter](https://godoc.org/github.com/rs/rest-layer/rest#DefaultResponseFormatter) and/or [DefaultResponseSender](https://godoc.org/github.com/rs/rest-layer/rest#DefaultResponseSender) if you just want to wrap or slightly modify the default behavior:\n\n```go\ntype myResponseFormatter struct {\n\trest.DefaultResponseFormatter\n}\n\n// Add a wrapper around the list with pagination info\nfunc (r myResponseFormatter) FormatList(ctx context.Context, headers http.Header, l *resource.ItemList, skipBody bool) (context.Context, interface{}) {\n\tctx, data := r.DefaultResponseFormatter.FormatList(ctx, headers, l, skipBody)\n\treturn ctx, map[string]interface{}{\n\t\t\"meta\": map[string]int{\n\t\t\t\"offset\": l.Offset,\n\t\t\t\"total\":  l.Total,\n\t\t},\n\t\t\"list\": data,\n\t}\n}\n```\n\n## GraphQL\n\nIn parallel with the REST API handler, REST Layer is also able to handle GraphQL queries (mutation will come later). GraphQL is a query language created by Facebook which provides a common interface to fetch and manipulate data. REST Layer's GraphQL handler is able to read a [resource.Index](https://godoc.org/github.com/rs/rest-layer/resource#Index) and create a corresponding GraphQL schema.\n\nGraphQL doesn't expose resources directly, but queries. REST Layer take all the resources defined at the root of the `resource.Index` and create two GraphQL queries for each one. One query is just the name of the endpoint, so `/users` would result in `users` and another is the name of the endpoint suffixed with `List`, as `usersList`. The item query takes an `id` parameter and the list queries takes `skip`, `page`, `limit`, `filter` and `sort` parameters. All sub-resources are accessible using GraphQL sub-selection syntax.\n\nIf your resource defines aliases, some additional GraphQL queries are exposed with their name constructed as the name of the resource suffixed with the name of the alias with a capital. So for `users` with an alias `admin`, the query would be `usersAdmin`.\n\nYou can bind the GraphQL endpoint wherever you want as follow:\n\n```go\nindex := resource.NewIndex()\n// Bind some resources\n\nh, err := graphql.NewHandler(index)\nif err != nil {\n\tlog.Fatal(err)\n}\nhttp.Handle(\"/graphql\", h)\nhttp.ListenAndServe(\":8080\", nil)\n```\n\nGraphQL support is experimental. Only querying is supported for now, mutation will come later. Sub-queries are executed sequentially and may generate quite a lot of query on the storage backend on complex queries. You may prefer the REST endpoint with [field selection](#field-selection) which benefits from a lot of optimization for now.\n\n## Hystrix\n\nREST Layer supports Hystrix as a circuit breaker. You can enable Hystrix on a per resource basis by wrapping the storage handler using [rest-layer-hystrix](https://github.com/rs/rest-layer-hystrix):\n\n```go\nimport \"github.com/rs/rest-layer-hystrix\"\n\nindex.Bind(\"posts\", post, restrix.Wrap(\"posts\", mongo.NewHandler()), resource.DefaultConf)\n```\n\nWhen wrapped this way, one Hystrix command is created per storage handler action, with the name formatted as `\u003cname\u003e.\u003cAction\u003e`. Possible actions are:\n\n- `Find`: when a collection of items is requested.\n- `Insert`: when items are created.\n- `Update`: when items are modified.\n- `Delete`: when a single item is deleted by its id.\n- `Clear`: when a collection of items matching a filter are deleted.\n- `MultiGet`: when several items are retrieved by their ids (on storage handler supporting `MultiGetter` interface.\n\nOnce enabled, you must configure Hystrix for each command and start the Hystrix metrics stream handler.\n\nSee [Hystrix godoc](https://godoc.org/github.com/afex/hystrix-go/hystrix) for more info and [examples/hystrix](https://github.com/rs/rest-layer/blob/master/examples/hystrix/main.go) for a complete usage example with REST layer.\n\n## JSONSchema\n\nIt is possible to convert a schema to [JSON Schema](http://json-schema.org/) with some limitations for certain schema fields. Currently, we implement JSON Schema Draft 4 [core](https://tools.ietf.org/html/draft-zyp-json-schema-04) and [validation](https://tools.ietf.org/html/draft-fge-json-schema-validation-00) specifications. In addition, we have implemented \"readOnly\" from the less commonly used [hyper-schema](https://tools.ietf.org/html/draft-luff-json-hyper-schema-00#section-4.4) specification.\n\nExample usage:\n\n```go\nimport \"github.com/rs/rest-layer/schema/encoding/jsonschema\"\n\nb := new(bytes.Buffer)\nenc := jsonschema.NewEncoder(b)\nif err := enc.Encode(aSchema); err != nil {\n  return err\n}\nfmt.Println(b.String()) // Valid JSON Document describing the schema.\n```\n\n\n### Custom FieldValidators\n\nFor a custom `FieldValidator` to support encoding to JSON Schema, it must implement the `jsonschema.Builder` interface:\n\n```go\n// The Builder interface should be implemented by custom schema.FieldValidator implementations to allow JSON Schema\n// serialization.\ntype Builder interface {\n\t// BuildJSONSchema should return a map containing JSON Schema Draft 4 properties that can be set based on\n\t// FieldValidator data. Application specific properties can be added as well, but should not conflict with any\n\t// legal JSON Schema keys.\n\tBuildJSONSchema() (map[string]interface{}, error)\n}\n```\n\nTo easier extend a `FieldValidator` from the `schema` package, you can call `ValidatorBuilder` inside `BuildJSONSchema()`:\n\n```go\ntype Email struct {\n\tschema.String\n}\n\nfunc (e Email) BuildJSONSchema() (map[string]interface{}, error) {\n\tparentBuilder, _ = jsonschema.ValidatorBuilder(e.String)\n\tm, err := parentBuilder.BuildJSONSchema()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tm[\"format\"] = \"email\"\n\treturn m, nil\n}\n```\n\n### Sub-schema Limitation\n\nSub-schemas only get converted to JSON Schema, if you specify a sub-schema via setting a Field's `Validator` attribute to a `schema.Object` instance. Use of the Field's `Schema` field is _not_ supported. Instead we hope [#77](https://github.com/rs/rest-layer/issues/77) will be implemented.\n\n### schema.Dict Limitations\n\n`schema.Dict` only supports `nil` and `schema.String` as `KeysValidator` values. Note that some less common combinations of `schema.String` attributes will lead to usage of an `allOf` construct with duplicated schemas for values. This is to avoid usage of regular expression expansions that only a subset of implementations actually support.\n\nThe limitation in `KeysValidator` values arise because JSON Schema draft 4 (and draft 5) support for key validation is limited to [properties, patternProperties and additionalProperties](https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.4.4). This essentially means that there can be no JSON Schema object supplied for key validation, but that we need to rely on exact match (properties), regular expressions (patternProperties) or no key validation (additionalProperties).\n\n### schema.Reference Provisional Support\n\nThe support for `schema.Reference` is purely provisional and simply returns an empty object `{}`, meaning it does not give any hint as to which validation the server might use.\n\nWith a potential later implantation of the [OpenAPI Specification](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md) (a.k.a. the Swagger 2.0 Specification), the goal is to refer to the ID field of the linked resource via an object `{\"$ref\": \"#/definitions/\u003cunique schema title\u003e/id\"}`. This is tracked via issue [#36](https://github.com/rs/rest-layer/issues/36).\n\n### schema.URL Limitations\n\nThe current serialization of `schema.URL` always returns a schema `{\"type\": \"string\", \"format\": \"uri\"}`, ignoring any struct attributes that affect the actual validation within rest-layer. The JSON Schema is thus not completely accurate for this validator.\n\nNote that JSON Schema draft 5 adds [uriref](https://tools.ietf.org/html/draft-wright-json-schema-validation-00#section-7.3.7), which could allow us to at least document whether `AllowRelative` is `true` or `false`. JSON Schema also allow application specific additional formats to be defined, but it's not practical to create a custom format for any possible struct attribute combination.\n\n## Licenses\n\nAll source code is licensed under the [MIT License](https://raw.github.com/rs/rest-layer/master/LICENSE).\n","funding_links":[],"categories":["Web Frameworks","开源类库","Web框架","Go","RESTful API Server builders \u0026 generators","Open source library","Repositories"],"sub_categories":["HTTP Clients","Web 框架","实用程序/Miscellaneous","Web Framework","Utility/Miscellaneous"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frs%2Frest-layer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frs%2Frest-layer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frs%2Frest-layer/lists"}