{"action":"created","comment":{"url":"https://api.github.com/repos/fnproject/fdk-go/pulls/comments/225206477","pull_request_review_id":164757311,"id":225206477,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIyNTIwNjQ3Nw==","diff_hunk":"@@ -3,94 +3,142 @@ package fdk\n import (\n \t\"context\"\n \t\"io\"\n+\t\"log\"\n \t\"net/http\"\n \t\"os\"\n-\n-\t\"github.com/fnproject/fdk-go/utils\"\n+\t\"time\"\n )\n \n+// Handler is a function handler, representing 1 invocation of a function\n type Handler interface {\n-\tServe(ctx context.Context, in io.Reader, out io.Writer)\n+\t// Serve contains a context with request configuration, the body of the\n+\t// request as a stream of bytes, and a writer to output to; user's may set\n+\t// headers via the resp writer using the fdk's SetHeader/AddHeader methods -\n+\t// if you've a better idea, pipe up.\n+\tServe(ctx context.Context, body io.Reader, resp io.Writer)\n }\n \n+// HandlerFunc makes a Handler so that you don't have to!\n type HandlerFunc func(ctx context.Context, in io.Reader, out io.Writer)\n \n+// Serve implements Handler\n func (f HandlerFunc) Serve(ctx context.Context, in io.Reader, out io.Writer) {\n \tf(ctx, in, out)\n }\n \n-// Context will return an *fn.Ctx that can be used to read configuration and\n+// GetContext will return an fdk Context that can be used to read configuration and\n // request information from an incoming request.\n-func Context(ctx context.Context) *Ctx {\n-\tutilsCtx := utils.Context(ctx)\n-\treturn &Ctx{\n-\t\tHTTPHeader: utilsCtx.HTTPHeader,\n-\t\tHeader:     utilsCtx.Header,\n-\t\tConfig:     utilsCtx.Config,\n-\t\tRequestURL: utilsCtx.RequestURL,\n-\t\tMethod:     utilsCtx.Method,\n-\t}\n+func GetContext(ctx context.Context) Context {\n+\treturn ctx.Value(ctxKey).(Context)\n }\n \n-func WithContext(ctx context.Context, fnctx *Ctx) context.Context {\n-\tutilsCtx := &utils.Ctx{\n-\t\tHTTPHeader: fnctx.HTTPHeader,\n-\t\tHeader:     fnctx.Header,\n-\t\tConfig:     fnctx.Config,\n-\t\tRequestURL: fnctx.RequestURL,\n-\t\tMethod:     fnctx.Method,\n-\t}\n-\treturn utils.WithContext(ctx, utilsCtx)\n+// WithContext adds an fn context to a context context. It is unclear why this is\n+// an exported method but hey here ya go don't hurt yourself.\n+func WithContext(ctx context.Context, fnctx Context) context.Context {\n+\treturn context.WithValue(ctx, ctxKey, fnctx)\n+}\n+\n+type key struct{}\n+\n+var ctxKey = new(key)\n+\n+// Context contains all configuration for a function invocation\n+type Context interface {\n+\t// Config is a map of all env vars set on a function, the base set of fn\n+\t// headers in addition to any app and function configuration.\n+\tConfig() map[string]string\n+\n+\t// Header are the headers sent to this function invocation\n+\tHeader() http.Header\n+\n+\t// ContentType is Header().Get(\"Content-Type\") but with 15 less chars, you are welcome\n+\t// XXX(discuss): is this necessary? Header.Get(\"Content-Type\") is easy enough for a caveman...\n+\tContentType() string\n+\n+\t// CallID is the call id for this function invocation\n+\tCallID() string\n+\n+\t// TODO should we unwind all known env var fields as methods here, as well?\n+}\n+\n+// HTTPContext contains all configuration for a function invocation sourced\n+// from an http gateway trigger, which will make the function appear to receive\n+// from the client request they were sourced from, with no additional headers.\n+type HTTPContext interface {\n+\tContext\n+\n+\t// RequestURL is the request url from the gateway client http request\n+\tRequestURL() string\n+\n+\t// RequestMethod is the request method from the gateway client http request\n+\tRequestMethod() string\n+}\n+\n+type baseCtx struct {\n+\theader http.Header\n+\tconfig map[string]string\n+\tcallID string\n }\n \n-// Ctx provides access to Config and Headers from fn.\n-type Ctx struct {\n-\t// Header are the unmodified headers as sent to the container, see\n-\t// HTTPHeader for specific trigger headers\n-\tHeader http.Header\n-\t// HTTPHeader are the request headers as they appear on the original HTTP request,\n-\t// for an http trigger.\n-\tHTTPHeader http.Header\n-\tConfig     map[string]string\n-\tRequestURL string\n-\tMethod     string\n+type httpCtx struct {\n+\t// XXX(reed): if we embed we won't preserve the original headers. since we have an\n+\t// interface handy now we could change this under the covers when/if we want... idk\n+\tbaseCtx\n+\trequestURL    string\n+\trequestMethod string\n+}\n+\n+func (c baseCtx) Config() map[string]string { return c.config }\n+func (c baseCtx) Header() http.Header       { return c.header }\n+func (c baseCtx) CallID() string            { return c.callID }\n+func (c baseCtx) ContentType() string       { return c.header.Get(\"Content-Type\") }\n+\n+func (c httpCtx) RequestURL() string    { return c.requestURL }\n+func (c httpCtx) RequestMethod() string { return c.requestMethod }\n+\n+func ctxWithDeadline(ctx context.Context, fnDeadline string) (context.Context, context.CancelFunc) {\n+\tt, err := time.Parse(time.RFC3339, fnDeadline)\n+\tif err == nil {\n+\t\treturn context.WithDeadline(ctx, t)\n+\t}\n+\treturn context.WithCancel(ctx)\n }\n \n-// AddHeader will add a header on the function response, for hot function\n-// formats.\n+// AddHeader will add a header onto the function response\n func AddHeader(out io.Writer, key, value string) {\n-\tif resp, ok := out.(*utils.Response); ok {\n-\t\tresp.Header.Add(key, value)\n+\tif resp, ok := out.(http.ResponseWriter); ok {\n+\t\tresp.Header().Add(key, value)\n \t}\n }\n \n-// SetHeader will set a header on the function response, for hot function\n-// formats.\n+// SetHeader will set a header on the function response\n func SetHeader(out io.Writer, key, value string) {\n-\tif resp, ok := out.(*utils.Response); ok {\n-\t\tresp.Header.Set(key, value)\n+\tif resp, ok := out.(http.ResponseWriter); ok {\n+\t\tresp.Header().Set(key, value)\n \t}\n }\n \n-// WriteStatus will set the status code to return in the function response, for\n-// hot function formats.\n+// WriteStatus will set the status code to return in the function response\n func WriteStatus(out io.Writer, status int) {","path":"fdk.go","position":204,"original_position":163,"commit_id":"38e7cd683945f7efa2e4d49d572e4cc7922e5871","original_commit_id":"3429ad29b658fbf2bc14de8b7c2405ecdc758d1e","user":{"login":"rdallman","id":2935111,"node_id":"MDQ6VXNlcjI5MzUxMTE=","avatar_url":"https://avatars0.githubusercontent.com/u/2935111?v=4","gravatar_id":"","url":"https://api.github.com/users/rdallman","html_url":"https://github.com/rdallman","followers_url":"https://api.github.com/users/rdallman/followers","following_url":"https://api.github.com/users/rdallman/following{/other_user}","gists_url":"https://api.github.com/users/rdallman/gists{/gist_id}","starred_url":"https://api.github.com/users/rdallman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rdallman/subscriptions","organizations_url":"https://api.github.com/users/rdallman/orgs","repos_url":"https://api.github.com/users/rdallman/repos","events_url":"https://api.github.com/users/rdallman/events{/privacy}","received_events_url":"https://api.github.com/users/rdallman/received_events","type":"User","site_admin":false},"body":"semantically this works the same as `http.Header.Set` - there's also `AddHeader(io.Writer, key, value string)` to get at what you're asking - so gonna say no, open to ideas about making headers more accessible I still find this interaction slightly awkward, however we have `http.Handler` wrapper now so I think users that want to set headers should probably use that anyway...","created_at":"2018-10-15T15:17:43Z","updated_at":"2018-10-15T15:17:44Z","html_url":"https://github.com/fnproject/fdk-go/pull/39#discussion_r225206477","pull_request_url":"https://api.github.com/repos/fnproject/fdk-go/pulls/39","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/fnproject/fdk-go/pulls/comments/225206477"},"html":{"href":"https://github.com/fnproject/fdk-go/pull/39#discussion_r225206477"},"pull_request":{"href":"https://api.github.com/repos/fnproject/fdk-go/pulls/39"}},"in_reply_to_id":223074267},"pull_request":{"url":"https://api.github.com/repos/fnproject/fdk-go/pulls/39","id":220578839,"node_id":"MDExOlB1bGxSZXF1ZXN0MjIwNTc4ODM5","html_url":"https://github.com/fnproject/fdk-go/pull/39","diff_url":"https://github.com/fnproject/fdk-go/pull/39.diff","patch_url":"https://github.com/fnproject/fdk-go/pull/39.patch","issue_url":"https://api.github.com/repos/fnproject/fdk-go/issues/39","number":39,"state":"open","locked":false,"title":"WIP: first rev of fdk 2.0","user":{"login":"rdallman","id":2935111,"node_id":"MDQ6VXNlcjI5MzUxMTE=","avatar_url":"https://avatars0.githubusercontent.com/u/2935111?v=4","gravatar_id":"","url":"https://api.github.com/users/rdallman","html_url":"https://github.com/rdallman","followers_url":"https://api.github.com/users/rdallman/followers","following_url":"https://api.github.com/users/rdallman/following{/other_user}","gists_url":"https://api.github.com/users/rdallman/gists{/gist_id}","starred_url":"https://api.github.com/users/rdallman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rdallman/subscriptions","organizations_url":"https://api.github.com/users/rdallman/orgs","repos_url":"https://api.github.com/users/rdallman/repos","events_url":"https://api.github.com/users/rdallman/events{/privacy}","received_events_url":"https://api.github.com/users/rdallman/received_events","type":"User","site_admin":false},"body":"would like some eyes before going whole hog please :)\r\n\r\nlargely, this changes the context object to an interface, which makes doing\r\nshenanigans with the headers nice and transparent to users, where they'll\r\naccess the headers the same whether they are http gateway headers or invoke\r\nheaders. this also drops support for all non-http-stream formats, be gone\r\npests. this also gets rid of the utils package and makes this all top level\r\nagain instead of coercing contexts back and forth, since we don't need to futz\r\nwith pipes for tests maybe we can get creative without having a separate\r\npackage for that stuff anymore.\r\n\r\nuseful points of feedback I'm asking for without making any presuppositions by\r\ncommitting something (but don't let that starve your critical creativity):\r\n\r\ndo you want `hctx := fdk.GetHTTPContext(ctx)` ? should it return nil if it's\r\nnot an http context? should we make the user cast so that they have to panic\r\nand not us? do lions have the ability to communicate with dolphins? one thing\r\nto consider is that there is overlap between the http context and vanilla\r\ncontext, so using the vanilla context type from `fdk.GetContext(ctx)` will\r\nstill allow getting at the (modified) headers and config, and getting at the\r\nhttp context is only required for the request method and url (for users).\r\n\r\nthis totally breaks the API since now these things are addressed by interface\r\nmethods instead of fields on a concrete type. I should have been smacked 12\r\nmonths ago, I blame everyone else no way this was my fault, nope. is this OK?\r\nshould we worry about compat? the changes are really easy in a lot of cases\r\n(add parens...) and the trade offs seem ok (and we don't have a stable API and\r\nthe heat death of the universe is imminent?)\r\n\r\ni really did try to make the godoc look nice. if you are anywhere near as anal\r\nas i am i would appreciate a review of `$ godoc .`\r\n\r\ni'm hesitant to make the out writer on the handler an http.ResponseWriter, but\r\nit would make a whole lot of sense. kind of the whole point was to get away\r\nfrom that, but in any event if we do want this, it's a good chance to do it.\r\nwe can change the handler signature if we'd like but that may be a slightly\r\nharder breakage for users to fix up. open to ideas anyway.\r\n\r\n... if this is the right path forward, I will add more tests to this and go\r\nfix up the test image in fn (possibly punting the latter for a couple weeks\r\noff when i'll have time to properly kill format in fn).","created_at":"2018-10-05T03:53:20Z","updated_at":"2018-10-15T15:17:44Z","closed_at":null,"merged_at":null,"merge_commit_sha":"1a6a3f94c805cde3d597eac86133f5a808005f01","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/fnproject/fdk-go/pulls/39/commits","review_comments_url":"https://api.github.com/repos/fnproject/fdk-go/pulls/39/comments","review_comment_url":"https://api.github.com/repos/fnproject/fdk-go/pulls/comments{/number}","comments_url":"https://api.github.com/repos/fnproject/fdk-go/issues/39/comments","statuses_url":"https://api.github.com/repos/fnproject/fdk-go/statuses/38e7cd683945f7efa2e4d49d572e4cc7922e5871","head":{"label":"fnproject:http-context","ref":"http-context","sha":"38e7cd683945f7efa2e4d49d572e4cc7922e5871","user":{"login":"fnproject","id":30273834,"node_id":"MDEyOk9yZ2FuaXphdGlvbjMwMjczODM0","avatar_url":"https://avatars2.githubusercontent.com/u/30273834?v=4","gravatar_id":"","url":"https://api.github.com/users/fnproject","html_url":"https://github.com/fnproject","followers_url":"https://api.github.com/users/fnproject/followers","following_url":"https://api.github.com/users/fnproject/following{/other_user}","gists_url":"https://api.github.com/users/fnproject/gists{/gist_id}","starred_url":"https://api.github.com/users/fnproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fnproject/subscriptions","organizations_url":"https://api.github.com/users/fnproject/orgs","repos_url":"https://api.github.com/users/fnproject/repos","events_url":"https://api.github.com/users/fnproject/events{/privacy}","received_events_url":"https://api.github.com/users/fnproject/received_events","type":"Organization","site_admin":false},"repo":{"id":105084898,"node_id":"MDEwOlJlcG9zaXRvcnkxMDUwODQ4OTg=","name":"fdk-go","full_name":"fnproject/fdk-go","private":false,"owner":{"login":"fnproject","id":30273834,"node_id":"MDEyOk9yZ2FuaXphdGlvbjMwMjczODM0","avatar_url":"https://avatars2.githubusercontent.com/u/30273834?v=4","gravatar_id":"","url":"https://api.github.com/users/fnproject","html_url":"https://github.com/fnproject","followers_url":"https://api.github.com/users/fnproject/followers","following_url":"https://api.github.com/users/fnproject/following{/other_user}","gists_url":"https://api.github.com/users/fnproject/gists{/gist_id}","starred_url":"https://api.github.com/users/fnproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fnproject/subscriptions","organizations_url":"https://api.github.com/users/fnproject/orgs","repos_url":"https://api.github.com/users/fnproject/repos","events_url":"https://api.github.com/users/fnproject/events{/privacy}","received_events_url":"https://api.github.com/users/fnproject/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/fnproject/fdk-go","description":"Go language helper funcs for fn","fork":false,"url":"https://api.github.com/repos/fnproject/fdk-go","forks_url":"https://api.github.com/repos/fnproject/fdk-go/forks","keys_url":"https://api.github.com/repos/fnproject/fdk-go/keys{/key_id}","collaborators_url":"https://api.github.com/repos/fnproject/fdk-go/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/fnproject/fdk-go/teams","hooks_url":"https://api.github.com/repos/fnproject/fdk-go/hooks","issue_events_url":"https://api.github.com/repos/fnproject/fdk-go/issues/events{/number}","events_url":"https://api.github.com/repos/fnproject/fdk-go/events","assignees_url":"https://api.github.com/repos/fnproject/fdk-go/assignees{/user}","branches_url":"https://api.github.com/repos/fnproject/fdk-go/branches{/branch}","tags_url":"https://api.github.com/repos/fnproject/fdk-go/tags","blobs_url":"https://api.github.com/repos/fnproject/fdk-go/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/fnproject/fdk-go/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/fnproject/fdk-go/git/refs{/sha}","trees_url":"https://api.github.com/repos/fnproject/fdk-go/git/trees{/sha}","statuses_url":"https://api.github.com/repos/fnproject/fdk-go/statuses/{sha}","languages_url":"https://api.github.com/repos/fnproject/fdk-go/languages","stargazers_url":"https://api.github.com/repos/fnproject/fdk-go/stargazers","contributors_url":"https://api.github.com/repos/fnproject/fdk-go/contributors","subscribers_url":"https://api.github.com/repos/fnproject/fdk-go/subscribers","subscription_url":"https://api.github.com/repos/fnproject/fdk-go/subscription","commits_url":"https://api.github.com/repos/fnproject/fdk-go/commits{/sha}","git_commits_url":"https://api.github.com/repos/fnproject/fdk-go/git/commits{/sha}","comments_url":"https://api.github.com/repos/fnproject/fdk-go/comments{/number}","issue_comment_url":"https://api.github.com/repos/fnproject/fdk-go/issues/comments{/number}","contents_url":"https://api.github.com/repos/fnproject/fdk-go/contents/{+path}","compare_url":"https://api.github.com/repos/fnproject/fdk-go/compare/{base}...{head}","merges_url":"https://api.github.com/repos/fnproject/fdk-go/merges","archive_url":"https://api.github.com/repos/fnproject/fdk-go/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/fnproject/fdk-go/downloads","issues_url":"https://api.github.com/repos/fnproject/fdk-go/issues{/number}","pulls_url":"https://api.github.com/repos/fnproject/fdk-go/pulls{/number}","milestones_url":"https://api.github.com/repos/fnproject/fdk-go/milestones{/number}","notifications_url":"https://api.github.com/repos/fnproject/fdk-go/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/fnproject/fdk-go/labels{/name}","releases_url":"https://api.github.com/repos/fnproject/fdk-go/releases{/id}","deployments_url":"https://api.github.com/repos/fnproject/fdk-go/deployments","created_at":"2017-09-28T00:54:00Z","updated_at":"2018-09-27T18:14:39Z","pushed_at":"2018-10-06T01:38:30Z","git_url":"git://github.com/fnproject/fdk-go.git","ssh_url":"git@github.com:fnproject/fdk-go.git","clone_url":"https://github.com/fnproject/fdk-go.git","svn_url":"https://github.com/fnproject/fdk-go","homepage":null,"size":91,"stargazers_count":14,"watchers_count":14,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":5,"mirror_url":null,"archived":false,"open_issues_count":6,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":5,"open_issues":6,"watchers":14,"default_branch":"master"}},"base":{"label":"fnproject:master","ref":"master","sha":"1c783fe496250a3e27445273fb43cace6fd4ee2b","user":{"login":"fnproject","id":30273834,"node_id":"MDEyOk9yZ2FuaXphdGlvbjMwMjczODM0","avatar_url":"https://avatars2.githubusercontent.com/u/30273834?v=4","gravatar_id":"","url":"https://api.github.com/users/fnproject","html_url":"https://github.com/fnproject","followers_url":"https://api.github.com/users/fnproject/followers","following_url":"https://api.github.com/users/fnproject/following{/other_user}","gists_url":"https://api.github.com/users/fnproject/gists{/gist_id}","starred_url":"https://api.github.com/users/fnproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fnproject/subscriptions","organizations_url":"https://api.github.com/users/fnproject/orgs","repos_url":"https://api.github.com/users/fnproject/repos","events_url":"https://api.github.com/users/fnproject/events{/privacy}","received_events_url":"https://api.github.com/users/fnproject/received_events","type":"Organization","site_admin":false},"repo":{"id":105084898,"node_id":"MDEwOlJlcG9zaXRvcnkxMDUwODQ4OTg=","name":"fdk-go","full_name":"fnproject/fdk-go","private":false,"owner":{"login":"fnproject","id":30273834,"node_id":"MDEyOk9yZ2FuaXphdGlvbjMwMjczODM0","avatar_url":"https://avatars2.githubusercontent.com/u/30273834?v=4","gravatar_id":"","url":"https://api.github.com/users/fnproject","html_url":"https://github.com/fnproject","followers_url":"https://api.github.com/users/fnproject/followers","following_url":"https://api.github.com/users/fnproject/following{/other_user}","gists_url":"https://api.github.com/users/fnproject/gists{/gist_id}","starred_url":"https://api.github.com/users/fnproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fnproject/subscriptions","organizations_url":"https://api.github.com/users/fnproject/orgs","repos_url":"https://api.github.com/users/fnproject/repos","events_url":"https://api.github.com/users/fnproject/events{/privacy}","received_events_url":"https://api.github.com/users/fnproject/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/fnproject/fdk-go","description":"Go language helper funcs for fn","fork":false,"url":"https://api.github.com/repos/fnproject/fdk-go","forks_url":"https://api.github.com/repos/fnproject/fdk-go/forks","keys_url":"https://api.github.com/repos/fnproject/fdk-go/keys{/key_id}","collaborators_url":"https://api.github.com/repos/fnproject/fdk-go/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/fnproject/fdk-go/teams","hooks_url":"https://api.github.com/repos/fnproject/fdk-go/hooks","issue_events_url":"https://api.github.com/repos/fnproject/fdk-go/issues/events{/number}","events_url":"https://api.github.com/repos/fnproject/fdk-go/events","assignees_url":"https://api.github.com/repos/fnproject/fdk-go/assignees{/user}","branches_url":"https://api.github.com/repos/fnproject/fdk-go/branches{/branch}","tags_url":"https://api.github.com/repos/fnproject/fdk-go/tags","blobs_url":"https://api.github.com/repos/fnproject/fdk-go/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/fnproject/fdk-go/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/fnproject/fdk-go/git/refs{/sha}","trees_url":"https://api.github.com/repos/fnproject/fdk-go/git/trees{/sha}","statuses_url":"https://api.github.com/repos/fnproject/fdk-go/statuses/{sha}","languages_url":"https://api.github.com/repos/fnproject/fdk-go/languages","stargazers_url":"https://api.github.com/repos/fnproject/fdk-go/stargazers","contributors_url":"https://api.github.com/repos/fnproject/fdk-go/contributors","subscribers_url":"https://api.github.com/repos/fnproject/fdk-go/subscribers","subscription_url":"https://api.github.com/repos/fnproject/fdk-go/subscription","commits_url":"https://api.github.com/repos/fnproject/fdk-go/commits{/sha}","git_commits_url":"https://api.github.com/repos/fnproject/fdk-go/git/commits{/sha}","comments_url":"https://api.github.com/repos/fnproject/fdk-go/comments{/number}","issue_comment_url":"https://api.github.com/repos/fnproject/fdk-go/issues/comments{/number}","contents_url":"https://api.github.com/repos/fnproject/fdk-go/contents/{+path}","compare_url":"https://api.github.com/repos/fnproject/fdk-go/compare/{base}...{head}","merges_url":"https://api.github.com/repos/fnproject/fdk-go/merges","archive_url":"https://api.github.com/repos/fnproject/fdk-go/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/fnproject/fdk-go/downloads","issues_url":"https://api.github.com/repos/fnproject/fdk-go/issues{/number}","pulls_url":"https://api.github.com/repos/fnproject/fdk-go/pulls{/number}","milestones_url":"https://api.github.com/repos/fnproject/fdk-go/milestones{/number}","notifications_url":"https://api.github.com/repos/fnproject/fdk-go/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/fnproject/fdk-go/labels{/name}","releases_url":"https://api.github.com/repos/fnproject/fdk-go/releases{/id}","deployments_url":"https://api.github.com/repos/fnproject/fdk-go/deployments","created_at":"2017-09-28T00:54:00Z","updated_at":"2018-09-27T18:14:39Z","pushed_at":"2018-10-06T01:38:30Z","git_url":"git://github.com/fnproject/fdk-go.git","ssh_url":"git@github.com:fnproject/fdk-go.git","clone_url":"https://github.com/fnproject/fdk-go.git","svn_url":"https://github.com/fnproject/fdk-go","homepage":null,"size":91,"stargazers_count":14,"watchers_count":14,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":5,"mirror_url":null,"archived":false,"open_issues_count":6,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":5,"open_issues":6,"watchers":14,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/fnproject/fdk-go/pulls/39"},"html":{"href":"https://github.com/fnproject/fdk-go/pull/39"},"issue":{"href":"https://api.github.com/repos/fnproject/fdk-go/issues/39"},"comments":{"href":"https://api.github.com/repos/fnproject/fdk-go/issues/39/comments"},"review_comments":{"href":"https://api.github.com/repos/fnproject/fdk-go/pulls/39/comments"},"review_comment":{"href":"https://api.github.com/repos/fnproject/fdk-go/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/fnproject/fdk-go/pulls/39/commits"},"statuses":{"href":"https://api.github.com/repos/fnproject/fdk-go/statuses/38e7cd683945f7efa2e4d49d572e4cc7922e5871"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"rdallman"}}