Giter VIP home page Giter VIP logo

api2go's Introduction

api2go

GoDoc Build Status

A JSON API Implementation for Go, to be used e.g. as server for Ember Data.

import "github.com/univedo/api2go"

api2go works, but we're still working on some rough edges. Things might change. Open an issue and join in!

Usage

Take the simple structs:

type Post struct {
  ID          int
  Title       string
  Comments    []Comment
  CommentsIDs []int
}

type Comment struct {
  ID   int
  Text string
}

Building a REST API

First, write an implementation of api2go.DataSource. You have to implement 5 methods:

type fixtureSource struct {}

func (s *fixtureSource) FindAll(r api2go.Request) (interface{}, error) {
  // Return a slice of all posts as []Post
}

func (s *fixtureSource) FindOne(ID string, r api2go.Request) (interface{}, error) {
  // Return a single post by ID as Post
}

func (s *fixtureSource) FindMultiple(IDs string, r api2go.Request) (interface{}, error) {
  // Return multiple posts by ID as []Post
  // For example for Requests like GET /posts/1,2,3
}

func (s *fixtureSource) Create(obj interface{}) (string, error) {
  // Save the new Post in `obj` and return its ID.
}

func (s *fixtureSource) Delete(id string) error {
  // Delete a post
}

func (s *fixtureSource) Update(obj interface{}) error {
  // Apply the new values in the Post in `obj`
}

As an example, check out the implementation of fixtureSource in api_test.go.

You can then create an API:

api := api2go.NewAPI("v1")
api.AddResource(Post{}, &PostsSource{})
http.ListenAndServe(":8080", api.Handler())

This generates the standard endpoints:

OPTIONS /v1/posts
OPTIONS /v1/posts/<id>
GET     /v1/posts
POST    /v1/posts
GET     /v1/posts/<id>
PUT     /v1/posts/<id>
DELETE  /v1/posts/<id>
GET     /v1/posts/<id>,<id>,...

Query Params

To support all the features mentioned in the Fetching Resources section of Jsonapi: http://jsonapi.org/format/#fetching

If you want to support any parameters mentioned there, you can access them in your Resource via the api2go.Request Parameter. This currently supports QueryParams which holds all query parameters as map[string][]string unfiltered. So you can use it for:

  • Filtering
  • Inclusion of Linked Resources
  • Sparse Fieldsets
  • Sorting
  • Aything else you want to do that is not in the official Jsonapi Spec
type fixtureSource struct {}

func (s *fixtureSource) FindAll(req api2go.Request) (interface{}, error) {
  for key, values range r.queryParams {
    ...
  }
  ...
}

If there are multiple values, you have to separate them with a komma. api2go automatically slices the values for you.

Example Request
GET /people?fields=id,name,age

req["people"] contains values: ["id", "name", "age"]

Use Custom Controllers

By using the api2go.DataSource and registering it with AddResource, api2go will do everything for you automatically and you cannot change it. This means that you cannot access the request, perform some user authorization and so on...

In order to register a Controller for a DataSource, implement the api2go.Controller interface:

type Controller interface {
  // FindAll gets called after resource was called
  FindAll(r *http.Request, objs *interface{}) error

  // FindOne gets called after resource was called
  FindOne(r *http.Request, obj *interface{}) error

  // Create gets called before resource was called
  Create(r *http.Request, obj *interface{}) error

  // Delete gets called before resource was called
  Delete(r *http.Request, id string) error

  // Update gets called before resource was called
  Update(r *http.Request, obj *interface{}) error
}

Now, you can access the request and for example perform some user authorization by reading the Authorization header or some cookies. In addition, you also have the object out of your database, in case you need that too.

To deny access you just return a new httpError with api2go.NewHTTPError

...
func (c *yourController) FindAll(r *http.Request, objs *interface{}) error {
  // do some authorization stuff
  return api2go.NewHTTPError(someError, "Access denied", 403)
}
...

Register your Controller with the DataSource together

api := api2go.NewAPI("v1")
api.AddResourceWithController(Post{}, &PostsSource{}, &YourController{})
http.ListenAndServe(":8080", api.Handler())

Manual marshaling / unmarshaling

comment1 = Comment{ID: 1, Text: "First!"}
comment2 = Comment{ID: 2, Text: "Second!"}
post = Post{ID: 1, Title: "Foobar", Comments: []Comment{comment1, comment2}}

json, err := api2go.MarshalJSON(post)

will yield

{
  "posts": [
    {
      "id": "1",
      "links": {"comments": ["1", "2"]},
      "title": "Foobar"
    }
  ],
  "linked": {
    "comments": [
      {"id": "1", "text": "First!"},
      {"id": "2", "text": "Second!"}
    ]
  }
}

Recover the structure from above using

var posts []Post
err := api2go.UnmarshalFromJSON(json, &posts)
// posts[0] == Post{ID: 1, Title: "Foobar", CommentsIDs: []int{1, 2}}

Note that when unmarshaling, api2go will always fill the CommentsIDs field, never the Comments field.

Conventions

Structs MUST have:

  • A field called ID that is either a string or int.

Structs MAY have:

  • Fields with struct-slices, e.g. Comments []Comment. They will be serialized as links (using the field name) and the linked structs embedded.
  • Fields with int / string slices, e.g. CommentsIDs. They will be serialized as links (using the field name minus an optional IDs suffix), but not embedded.
  • Fields of struct type, e.g. Author Person. They will be serialized as a single link (using the field name) and the linked struct embedded.
  • Fields of int / string type, ending in ID, e.g. AuthorID. They will be serialized as a single link (using the field name minus the ID suffix), but not embedded.

Tests

go test
ginkgo                # Alternative
ginkgo watch -notify  # Watch for changes

api2go's People

Contributors

lucas-clemente avatar mantenie avatar sharpner avatar wwwdata avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.