question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Simplifying return objects for methods with network requests

See original GitHub issue

Consider a simple case of reading and updating an item:

const item = await cosmos.item(id).read()

item.foo = "bar"

await cosmos.items.upsert(item)

While this API works for basic operations, it does not expose HTTP headers or any other raw request data. Many advanced uses of cosmos need this data. We currently solve this by returning a wrapper object for all methods with underlying network requests:

const { body: item, headers }  = await cosmos.item(id).read()

item.foo = "bar"

await cosmos.items.upsert(item)

Unfortunately, this complicates the returned object and API for simple usage. Ideally we could support both use cases. Return objects could be simple but also provide metadata that advanced users need. With newer JavaScript features this may be possible. These are some approaches we are considering.

1: Use Symbol

Cosmos SDK can use a symbol to store data directly on the returned database object.

// Cosmos SDK Code
cosmos.headers = Symbol('headers')

// User code
const item = await cosmos.item(id).read()
const headers = item[cosmos.headers]

#34 contains some previous discussion of this approach.

Pros

  • Getting headers looks just like normal object property access
  • Symbols as keys allows us to add metadata without conflicting with user data. These keys are omitted when iterated or stringified so users can safely pass them back to cosmos without polluting data.

Cons

  • Requires advanced users to be familiar with Symbol which is a relatively new JS language feature
  • Requires polyfill in IE

2: getHeaders method

This is a twist on proposal 1. Symbols are still used as keys, but we expose a utility method so symbols are not exposed to user code.

// Cosmos SDK Code
const headersKey = Symbol('headers')
comsos.getHeaders = obj => obj[headersKey]

// User code
const item = await cosmos.item(id).read()
const headers = cosmos.getHeaders(item)

Pros

  • Similar to apporach 1 but without exposing users to Symbol

Cons

  • Requires polyfill in IE
  • getHeaders may look like magic to some users

3: Extend Promise

This approach returns a special class of promise that would allow users to control the return type.


// Cosmos SDK code
class CosmosRequestPromise extends Promise {
	includeHeaders() { /* implementation ommited */ }
}

// User code
const item = await cosmos.item(id).read()

const { body: item, headers } = await cosmos.item(id).read().includeHeaders()

Pros

  • Doesn’t use Symbol at all

Cons

  • Requires creating and maintaining our own promise type
  • includeHeaders may look like magic to some users
  • Implementation details are still unclear. This approach seems possible, but we haven’t built a POC.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
christopherandersoncommented, Jul 16, 2018

1 & 2 are compatible. 2 is effectively just a utility method for getting the right index.

Other advantages of doing 1 & 2 together is supporting some intelligent utility methods. Most folks don’t want the headers, they want a specific property from the headers such as RUs or activity id. We could have client.getRUs and client.getActivityId methods as well, which short cut and abstract away the details for folks.

1reaction
reconbotcommented, Jul 16, 2018

I’m considering using something similar in an graph database client library I use at work. But instead of symbols, a non enumerable field.

Object.defineProperty(post, '_meta', { enumerable: false })

However we have a history of “private” underscored properties. I think a symbol works great!

Read more comments on GitHub >

github_iconTop Results From Across the Web

c# - Can I simplify using Observable.Create to return objects ...
Give this a go: return Observable.Defer(() => HttpClient().GetAsync(uri)) .SelectMany(async x => { x.EnsureSuccessStatusCode(); return x.
Read more >
Simplifying REST API calls - Salesforce Stack Exchange
I'm new to Java programming and I'm trying to reduce the number of REST API calls I make in my program to better...
Read more >
Simplify your browser fetch() calls - DEV Community ‍ ‍
The function returns a tuple of data , which is already handled response content (no need for response.json() call) and the original response ......
Read more >
Controller action return types in ASP.NET Core web API
A 404 status code is returned when the product represented by id doesn't exist in the underlying data store. The NotFound convenience method...
Read more >
Simplify your Ruby code with the Robustness Principle
You can apply this principle to your Ruby methods. The methods you write should accept reasonable input, and should return consistent output. Focusing...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found