{"id":13712925,"url":"https://github.com/manyminds/api2go","last_synced_at":"2025-12-25T22:25:56.058Z","repository":{"id":19929746,"uuid":"23196256","full_name":"manyminds/api2go","owner":"manyminds","description":"JSONAPI.org Implementation for Go","archived":false,"fork":false,"pushed_at":"2024-06-26T13:28:20.000Z","size":795,"stargazers_count":700,"open_issues_count":36,"forks_count":94,"subscribers_count":32,"default_branch":"master","last_synced_at":"2024-11-13T23:32:44.942Z","etag":null,"topics":["go","jsonapi","rest"],"latest_commit_sha":null,"homepage":"","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/manyminds.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-08-21T17:23:27.000Z","updated_at":"2024-10-22T16:31:26.000Z","dependencies_parsed_at":"2024-06-18T12:22:28.862Z","dependency_job_id":"69342064-033c-4bf3-b87c-58ff0d80754d","html_url":"https://github.com/manyminds/api2go","commit_stats":{"total_commits":412,"total_committers":35,"mean_commits":"11.771428571428572","dds":0.6067961165048543,"last_synced_commit":"95b4fb838cf658332fec4c35b59de4f6325c361e"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manyminds%2Fapi2go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manyminds%2Fapi2go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manyminds%2Fapi2go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manyminds%2Fapi2go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/manyminds","download_url":"https://codeload.github.com/manyminds/api2go/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252779162,"owners_count":21802896,"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":["go","jsonapi","rest"],"created_at":"2024-08-02T23:01:24.636Z","updated_at":"2025-12-25T22:25:51.018Z","avatar_url":"https://github.com/manyminds.png","language":"Go","funding_links":[],"categories":["Go","Repositories"],"sub_categories":[],"readme":"# api2go\n\n[![Join the chat at https://gitter.im/manyminds/api2go](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/manyminds/api2go?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n[![GoDoc](https://godoc.org/github.com/manyminds/api2go?status.svg)](https://godoc.org/github.com/manyminds/api2go)\n[![Build Status](https://travis-ci.org/manyminds/api2go.svg?branch=master)](https://travis-ci.org/manyminds/api2go)\n[![Coverage Status](https://coveralls.io/repos/github/manyminds/api2go/badge.svg?branch=master)](https://coveralls.io/github/manyminds/api2go?branch=master)\n[![Go Report Card](https://goreportcard.com/badge/manyminds/api2go)](https://goreportcard.com/report/manyminds/api2go)\n\nA [JSON API](http://jsonapi.org) Implementation for Go, to be used e.g. as server for [Ember Data](https://github.com/emberjs/data).\n\n## TOC\n- [Installation](#installation)\n- [Basic functionality](#basic-functionality)\n- [Examples](#examples)\n- [Interfaces to implement](#interfaces-to-implement)\n  - [Responder](#responder)\n  - [EntityNamer](#entitynamer)\n  - [MarshalIdentifier](#marshalidentifier)\n  - [UnmarshalIdentifier](#unmarshalidentifier)\n  - [Marshalling with References to other structs](#marshalling-with-references-to-other-structs)\n  - [Unmarshalling with references to other structs](#unmarshalling-with-references-to-other-structs)\n- [Manual marshalling / unmarshalling](#manual-marshalling--unmarshalling)\n- [SQL Null-Types](#sql-null-types)\n- [Using api2go with the gin framework](#using-api2go-with-the-gin-framework)\n- [Building a REST API](#building-a-rest-api)\n  - [Query Params](#query-params)\n  - [Using Pagination](#using-pagination)\n  - [Fetching related IDs](#fetching-related-ids)\n  - [Fetching related resources](#fetching-related-resources)\n  - [Using middleware](#using-middleware)\n  - [Dynamic URL Handling](#dynamic-url-handling)\n- [Tests](#tests)\n\n# Installation\n\nFor the complete api2go package use:\n```go\ngo get github.com/manyminds/api2go\n```\n\nIf you only need marshalling and/or unmarshalling:\n```\ngo get github.com/manyminds/api2go/jsonapi \n```\n\n## Basic functionality\nApi2go will Marshal/Unmarshal exactly like the internal `json` package from Go\nwith one addition: It will decorate the Marshalled json with jsonapi meta\nobjects. Jsonapi wraps the payload inside an `attributes` object. The rest is\njust Meta-Data which will be generated by api2go.\n\nSo let's take this basic example:\n\n```go\ntype Article struct {\n\tID    string\n\tTitle string `json:\"title\"`\n}\n```\n\nWould `json.Marshal` into this Json:\n\n```json\n{\n  \"ID\": \"Some-ID\",\n  \"title\": \"the title\"\n}\n```\n\nFor api2go, you have to ignore tag the `ID` field and then the result could be\nsomething like this:\n\n```json\n{\n  \"type\": \"articles\",\n  \"id\": \"1\",\n  \"attributes\": {\n    \"title\": \"Rails is Omakase\"\n  },\n  \"relationships\": {\n    \"author\": {\n      \"links\": {\n        \"self\": \"/articles/1/relationships/author\",\n        \"related\": \"/articles/1/author\"\n      },\n      \"data\": { \"type\": \"people\", \"id\": \"9\" }\n    }\n  }\n}\n```\n\nAll the additional information is retrieved by implementing some interfaces.\n\n## Examples\n\n- Basic Examples can be found [here](https://github.com/manyminds/api2go/blob/master/examples/crud_example.go).\n- For a more real life example implementation of api2go using [jinzhu/gorm](https://github.com/jinzhu/gorm) and [gin-gonic/gin](https://github.com/gin-gonic/gin) you can have a look at hnakamur's [repository](https://github.com/hnakamur/api2go-gorm-gin-crud-example)\n\n## Interfaces to implement\nFor the following query and result examples, imagine the following 2 structs which represent a posts and\ncomments that belong with a has-many relation to the post.\n\n```go\ntype Post struct {\n  ID          int       `json:\"-\"`  // Ignore ID field because the ID is fetched via the\n                                    // GetID() method and must not be inside the attributes object.\n  Title       string    `json:\"title\"`\n  Comments    []Comment `json:\"-\"` // this will be ignored by the api2go marshaller\n  CommentsIDs []int     `json:\"-\"` // it's only useful for our internal relationship handling\n}\n\ntype Comment struct {\n  ID   int    `json:\"-\"`\n  Text string `json:\"text\"`\n}\n```\n\nYou must at least implement the [MarshalIdentifier](#marshalidentifier) interface, which is the one for marshalling/unmarshalling the primary `ID` of the struct\nthat you want to marshal/unmarshal. This is because of the huge variety of types that you could  use for the primary ID. For example a string,\na UUID or a BSON Object for MongoDB etc...\n\nIn the Post example struct, the `ID` field is ignored because api2go will use the `GetID` method that you implemented \nfor your struct to fetch the ID of the struct.\nEvery field inside a struct will be marshalled into the `attributes` object in\nthe json. In our example, we just want to have the `Title` field there.\n\nDon't forget to name all your fields with the `json:\"yourName\"` tag. \n\n### Responder\n```go\ntype Responder interface {\n\tMetadata() map[string]interface{}\n\tResult() interface{}\n\tStatusCode() int\n}\n```\n\nThe Responder interface must be implemented if you are using our API. It\ncontains everything that is needed for a response. You can see an example usage\nof it in our example project.\n\n### EntityNamer\n```go\ntype EntityNamer interface {\n\tGetName() string\n}\n```\n\nEntityNamer is an optional interface. Normally, the name of\na struct will be automatically generated in its plural form. For example if\nyour struct has the type `Post`, its generated name is `posts`. And the url\nfor the GET request for post with ID 1 would be `/posts/1`.\n\nIf you implement the `GetName()` method and it returns `special-posts`, then\nthis would be the name in the `type` field of the generated json and also the\nname for the generated routes.\n\nCurrently, you must implement this interface, if you have a struct type that\nconsists of multiple words and you want to use a **hyphenized** name. For example `UnicornPost`.\nOur default Jsonifier would then generate the name `unicornPosts`. But if you\nwant the [recommended](http://jsonapi.org/recommendations/#naming) name, you\nhave to implement `GetName`\n\n```go\nfunc (s UnicornPost) GetName() string {\n\treturn \"unicorn-posts\"\n}\n```\n\n### MarshalIdentifier\n```go\ntype MarshalIdentifier interface {\n\tGetID() string\n}\n```\n\nImplement this interface to marshal a struct.\n\n### UnmarshalIdentifier\n```go\ntype UnmarshalIdentifier interface {\n\tSetID(string) error\n}\n```\n\nThis is the corresponding interface to MarshalIdentifier. Implement this interface in order to unmarshal incoming json into\na struct.\n\n### Marshalling with References to other structs\nFor relationships to work, there are 3 Interfaces that you can use:\n\n```go\ntype MarshalReferences interface {\n\tGetReferences() []Reference\n}\n\n// MarshalLinkedRelations must be implemented if there are references and the reference IDs should be included\ntype MarshalLinkedRelations interface {\n\tMarshalReferences\n\tMarshalIdentifier\n\tGetReferencedIDs() []ReferenceID\n}\n\n// MarshalIncludedRelations must be implemented if referenced structs should be included\ntype MarshalIncludedRelations interface {\n\tMarshalReferences\n\tMarshalIdentifier\n\tGetReferencedStructs() []MarshalIdentifier\n}\n```\n\nImplementing those interfaces is not mandatory and depends on your use cases. If your API has any relationships, \nyou must at least implement `MarshalReferences` and `MarshalLinkedRelations`.\n\n`MarshalReferences` must be implemented in order for api2go to know which relations are possible for your struct.\n\n`MarshalLinkedRelations` must be implemented to retrieve the `IDs` of the relations that are connected to this struct. This method\ncould also return an empty array, if there are currently no relations. This is why there is the `MarshalReferences` interface, so that api2go\nknows what is possible, even if nothing is referenced at the time.\n\nIn addition to that, you can implement `MarshalIncludedRelations` which exports the complete referenced structs and embeds them in the json\nresult inside the `included` object.\n\n**That way you can choose how you internally manage relations.** So, there are no limits regarding the use of ORMs.\n\n### Unmarshalling with references to other structs\nIncoming jsons can also contain reference IDs. In order to unmarshal them correctly, you have to implement the following interfaces. If you only have to-one\nrelationships, the `UnmarshalToOneRelations` interface is enough. \n\n```go\n// UnmarshalToOneRelations must be implemented to unmarshal to-one relations\ntype UnmarshalToOneRelations interface {\n\tSetToOneReferenceID(name, ID string) error\n}\n\n// UnmarshalToManyRelations must be implemented to unmarshal to-many relations\ntype UnmarshalToManyRelations interface {\n\tSetToManyReferenceIDs(name string, IDs []string) error\n}\n```\n\n**If you need to know more about how to use the interfaces, look at our tests or at the example project.**\n\n## Manual marshalling / unmarshalling\nPlease keep in mind that this only works if you implemented the previously mentioned interfaces. Manual marshalling and\nunmarshalling makes sense, if you do not want to use our API that automatically generates all the necessary routes for you. You\ncan directly use our sub-package `github.com/manyminds/api2go/jsonapi` \n\n```go\ncomment1 = Comment{ID: 1, Text: \"First!\"}\ncomment2 = Comment{ID: 2, Text: \"Second!\"}\npost = Post{ID: 1, Title: \"Foobar\", Comments: []Comment{comment1, comment2}}\n\njson, err := jsonapi.Marshal(post)\n```\n\nwill yield\n\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"1\",\n      \"type\": \"posts\",\n      \"attributes\": {\n        \"title\": \"Foobar\"\n      },\n      \"relationships\": {\n        \"comments\": {\n          \"data\": [\n            {\n              \"id\": \"1\",\n              \"type\": \"comments\"\n            },\n            {\n              \"id\": \"2\",\n              \"type\": \"comments\"\n            }\n          ]\n        }\n      }\n    }\n  ],\n  \"included\": [\n    {\n      \"id\": \"1\",\n      \"type\": \"comments\",\n      \"attributes\": {\n        \"text\": \"First!\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"type\": \"comments\",\n      \"attributes\": {\n        \"text\": \"Second!\"\n      }\n    }\n  ]\n}\n```\n\nYou can also use `jsonapi.MarshalWithURLs` to automatically generate URLs for the rest endpoints that have a\nversion and BaseURL prefix. This will generate the same routes that our API uses. This adds `self` and `related` fields\nfor relations inside the `relationships` object.\n\nRecover the structure from above using. Keep in mind that Unmarshalling with\nincluded structs does not work yet. So Api2go cannot be used as a client yet.\n\n```go\nvar posts []Post\nerr := jsonapi.Unmarshal(json, \u0026posts)\n// posts[0] == Post{ID: 1, Title: \"Foobar\", CommentsIDs: []int{1, 2}}\n```\n## SQL Null-Types\nWhen using a SQL Database it is most likely you want to use the special SQL-Types from the `database/sql` package. These are\n\n- sql.NullBool\n- sql.NullFloat64\n- sql.NullInt64\n- sql.NullString\n\nThe Problem is, that they internally manage the `null` value behavior by using a custom struct. In order to Marshal and Unmarshal\nthese values, it is required to implement the `json.Marshaller` and `json.Unmarshaller` interfaces of the go standard library.\n\nBut you dont have to do this by yourself! There already is a library that did the work for you. We recommend that you use the types\nof this library: http://gopkg.in/guregu/null.v3/zero\n\nIn order to use omitempty with those types, you need to specify them as pointers in your struct.\n\n## Using api2go with the gin framework\n\nIf you want to use api2go with [gin](https://github.com/gin-gonic/gin) you need to use a different router than the default one.\nGet the according adapter using:\n\n```go get -tags=gingonic github.com/manyminds/api2go```\n\nCurrently the supported tags are: `gingonic`,`gorillamux`, or `echo`.\n\nAfter that you can bootstrap api2go the following way:\n```go\n  import (\n    \"github.com/gin-gonic/gin\"\n    \"github.com/manyminds/api2go\"\n    \"github.com/manyminds/api2go/routing\"\n    \"github.com/manyminds/api2go/examples/model\"\n    \"github.com/manyminds/api2go/examples/resource\"\n    \"github.com/manyminds/api2go/examples/storage\"\n  )\n\n  func main() {\n    r := gin.Default()\n    api := api2go.NewAPIWithRouting(\n      \"api\",\n      api2go.NewStaticResolver(\"/\"),\n      routing.Gin(r),\n    )\n\n    userStorage := storage.NewUserStorage()\n    chocStorage := storage.NewChocolateStorage()\n    api.AddResource(model.User{}, resource.UserResource{ChocStorage: chocStorage, UserStorage: userStorage})\n    api.AddResource(model.Chocolate{}, resource.ChocolateResource{ChocStorage: chocStorage, UserStorage: userStorage})\n\n    r.GET(\"/ping\", func(c *gin.Context) {\n      c.String(200, \"pong\")\n    })\n    r.Run(\":8080\")\n  }\n```\n\nKeep in mind that you absolutely should map api2go under its own namespace to not get conflicts with your normal routes.\n\nIf you need api2go with any different go framework, just send a PR with the according adapter :-)\n\n## Building a REST API\n\nFirst, write an implementation of either `api2go.ResourceGetter`, `api2go.ResourceCreator`, `api2go.ResourceUpdater`,  `api2go.ResourceDeleter`, or any combination of them.\nYou can also write an implementation the `CRUD` interface which embed all of them.\nYou have to implement at least one of these 4 methods:\n\n```go\ntype fixtureSource struct {}\n\n// FindOne returns an object by its ID\n// Possible success status code 200\nfunc (s *fixtureSource) FindOne(ID string, r api2go.Request) (Responder, error) {}\n\n// Create a new object. Newly created object/struct must be in Responder.\n// Possible status codes are:\n// - 201 Created: Resource was created and needs to be returned\n// - 202 Accepted: Processing is delayed, return nothing\n// - 204 No Content: Resource created with a client generated ID, and no fields were modified by\n//   the server\nfunc (s *fixtureSource) Create(obj interface{}, r api2go.Request) (Responder, err error) {}\n\n// Delete an object\n// Possible status codes are:\n// - 200 OK: Deletion was a success, returns meta information, currently not implemented! Do not use this\n// - 202 Accepted: Processing is delayed, return nothing\n// - 204 No Content: Deletion was successful, return nothing\nfunc (s *fixtureSource) Delete(id string, r api2go.Request) (Responder, err error) {}\n\n// Update an object\n// Possible status codes are:\n// - 200 OK: Update successful, however some field(s) were changed, returns updates source\n// - 202 Accepted: Processing is delayed, return nothing\n// - 204 No Content: Update was successful, no fields were changed by the server, return nothing\nfunc (s *fixtureSource) Update(obj interface{}, r api2go.Request) (Responder, err error) {}\n```\n\nIf you want to return a jsonapi compatible error because something went wrong inside the CRUD methods, you can use our\n`HTTPError` struct, which can be created with `NewHTTPError`. This allows you to set the error status code and add\nas many information about the error as you like. See: [jsonapi error](http://jsonapi.org/format/#errors)\n\nTo fetch all objects of a specific resource you can choose to implement one or both of the following\ninterfaces:\n\n```go\ntype FindAll interface {\n\t// FindAll returns all objects\n\tFindAll(req Request) (Responder, error)\n}\n\ntype PaginatedFindAll interface {\n\tPaginatedFindAll(req Request) (totalCount uint, response Responder, err error)\n}\n```\n\n`FindAll` returns everything. You could limit the results only by using Query Params which are described [here](#query-params)\n\n`PaginatedFindAll` can also use Query Params, but in addition to that it does not need to send all objects at once and can split\nup the result with pagination. You have to return the total number of found objects in order to let our API automatically generate\npagination links. More about pagination is described [here](#using-pagination)\n\nYou can then create an API:\n\n```go\napi := api2go.NewAPI(\"v1\")\napi.AddResource(Post{}, \u0026PostsSource{})\nhttp.ListenAndServe(\":8080\", api.Handler())\n```\n\nInstead of `api2go.NewAPI` you can also use `api2go.NewAPIWithBaseURL(\"v1\", \"http://yourdomain.com\")` to prefix all\nautomatically generated routes with your domain and protocoll.\n\nThis generates the standard endpoints:\n\n```\nOPTIONS /v1/posts\nOPTIONS /v1/posts/\u003cid\u003e\nGET     /v1/posts\nPOST    /v1/posts\nGET     /v1/posts/\u003cid\u003e\nPATCH   /v1/posts/\u003cid\u003e\nDELETE  /v1/posts/\u003cid\u003e\nGET     /v1/posts/\u003cid\u003e/comments            // fetch referenced comments of a post\nGET     /v1/posts/\u003cid\u003e/relationships/comments      // fetch IDs of the referenced comments only\nPATCH   /v1/posts/\u003cid\u003e/relationships/comments      // replace all related comments\n\n// These 2 routes are only created for to-many relations that implement EditToManyRelations interface\nPOST    /v1/posts/\u003cid\u003e/relationships/comments      // Add a new comment reference, only for to-many relations\nDELETE  /v1/posts/\u003cid\u003e/relationships/comments      // Delete a comment reference, only for to-many relations\n```\n\nFor the last two generated routes, it is necessary to implement the `jsonapi.EditToManyRelations` interface.\n\n```go\ntype EditToManyRelations interface {\n\tAddToManyIDs(name string, IDs []string) error\n\tDeleteToManyIDs(name string, IDs []string) error\n}\n```\n\nAll PATCH, POST and DELETE routes do a `FindOne` and update the values/relations in the previously found struct. This\nstruct will then be passed on to the `Update` method of a resource struct. So you get all these routes \"for free\" and just\nhave to implement the `ResourceUpdater` `Update` method.\n\n### Query Params\nTo support all the features mentioned in the `Fetching Resources` section of Jsonapi:\nhttp://jsonapi.org/format/#fetching\n\nIf you want to support any parameters mentioned there, you can access them in your Resource\nvia the `api2go.Request` Parameter. This currently supports `QueryParams` which holds\nall query parameters as `map[string][]string` unfiltered. So you can use it for:\n  * Filtering\n  * Inclusion of Linked Resources\n  * Sparse Fieldsets\n  * Sorting\n  * Aything else you want to do that is not in the official Jsonapi Spec\n\n```go\ntype fixtureSource struct {}\n\nfunc (s *fixtureSource) FindAll(req api2go.Request) (Responder, error) {\n  for key, values range req.QueryParams {\n    ...\n  }\n  ...\n}\n```\n\nIf there are multiple values, you have to separate them with a comma. api2go automatically\nslices the values for you.\n\n```\nExample Request\nGET /people?fields=id,name,age\n\nreq.QueryParams[\"fields\"] contains values: [\"id\", \"name\", \"age\"]\n```\n\n### Using Pagination\nApi2go can automatically generate the required links for pagination. Currently there are 2 combinations of query\nparameters supported:\n\n- page[number], page[size]\n- page[offset], page[limit]\n\nPagination is optional. If you want to support pagination, you have to implement the `PaginatedFindAll` method\nin you resource struct. For an example, you best look into our example project.\n\nExample request\n\n```\nGET /v0/users?page[number]=2\u0026page[size]=2\n```\n\nwould return a json with the top level links object\n\n```json\n{\n  \"links\": {\n    \"first\": \"http://localhost:31415/v0/users?page[number]=1\u0026page[size]=2\",\n    \"last\": \"http://localhost:31415/v0/users?page[number]=5\u0026page[size]=2\",\n    \"next\": \"http://localhost:31415/v0/users?page[number]=3\u0026page[size]=2\",\n    \"prev\": \"http://localhost:31415/v0/users?page[number]=1\u0026page[size]=2\"\n  },\n  \"data\": [...]\n}\n```\n\n### Fetching related IDs\nThe IDs of a relationship can be fetched by following the `self` link of a relationship object in the `links` object\nof a result. For the posts and comments example you could use the following generated URL:\n\n```\nGET /v1/posts/1/relationships/comments\n```\n\nThis would return all comments that are currently referenced by post with ID 1. For example:\n\n```json\n{\n  \"links\": {\n    \"self\": \"/v1/posts/1/relationships/comments\",\n    \"related\": \"/v1/posts/1/comments\"\n  },\n  \"data\": [\n    {\n      \"type\": \"comments\",\n      \"id\": \"1\"\n    },\n    {\n      \"type\":\"comments\",\n      \"id\": \"2\"\n    }\n  ]\n}\n```\n\n### Fetching related resources\nApi2go always creates a `related` field for elements in the `relationships` object of the result. This is like it's\nspecified on jsonapi.org. Post example:\n\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"1\",\n      \"type\": \"posts\",\n      \"title\": \"Foobar\",\n      \"relationships\": {\n        \"comments\": {\n          \"links\": {\n            \"related\": \"/v1/posts/1/comments\",\n            \"self\": \"/v1/posts/1/relationships/comments\"\n          },\n          \"data\": [\n            {\n              \"id\": \"1\",\n              \"type\": \"comments\"\n            },\n            {\n              \"id\": \"2\",\n              \"type\": \"comments\"\n            }\n          ]\n        }\n      }\n    }\n  ]\n}\n```\n\nIf a client requests this `related` url, the `FindAll` method of the comments resource will be called with a query\nparameter `postsID`.\n\nSo if you implement the `FindAll` method, do not forget to check for all possible query Parameters. This means you have\nto check all your other structs and if it references the one for that you are implementing `FindAll`, check for the\nquery Paramter and only return comments that belong to it. In this example, return the comments for the Post.\n\n### Using middleware\nWe provide a custom `APIContext` with\na [context](https://godoc.org/context) implementation that you\ncan use if you for example need to check if a user is properly authenticated\nbefore a request reaches the api2go routes.\n\nYou can either use our struct or implement your own with the `APIContexter`\ninterface\n\n```go\ntype APIContexter interface {\n    context.Context\n    Set(key string, value interface{})\n    Get(key string) (interface{}, bool)\n    Reset()\n}\n```\n\nIf you implemented your own `APIContexter`, don't forget to define\na `APIContextAllocatorFunc` and set it with `func (api *API) SetContextAllocator(allocator APIContextAllocatorFunc)`\n\nBut in most cases, this is not needed.\n\nTo use a middleware, it is needed to implement our\n`type HandlerFunc func(APIContexter, http.ResponseWriter, *http.Request)`. A `HandlerFunc` can then be \nregistered with `func (api *API) UseMiddleware(middleware ...HandlerFunc)`. You can either pass one or many middlewares \nthat will be executed in order before any other api2go routes. Use this to set up database connections, user authentication\nand so on.\n\n### Dynamic URL handling\nIf you have different TLDs for one api, or want to use different domains in development and production, you can implement a custom\nURLResolver in api2go. \n\nThere is a simple interface, which can be used if you get TLD information from the database, the server environment, or anything else\nthat's not request dependant:\n```go\ntype URLResolver interface {\n\tGetBaseURL() string\n}\n```\nAnd a more complex one that also gets request information:\n```go\ntype RequestAwareURLResolver interface {\n\tURLResolver\n\tSetRequest(http.Request)\n}\n```\n\nFor most use cases we provide a CallbackResolver which works on a per request basis and may fill\nyour basic needs. This is particulary useful if you are using an nginx proxy which sets `X-Forwarded-For` headers.\n\n```go\nresolver := NewCallbackResolver(func(r http.Request) string{})\napi := NewApiWithMarshalling(\"v1\", resolver, marshalers)\n```\n## Tests\n\n```sh\ngo test ./...\nginkgo -r                # Alternative\nginkgo watch -r -notify  # Watch for changes\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmanyminds%2Fapi2go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmanyminds%2Fapi2go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmanyminds%2Fapi2go/lists"}