New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Example usage of new internal utils api #17
Conversation
docs/examples/context_definition.js
Outdated
}, | ||
|
||
// superset of Hull API - helpers/utils: | ||
agent: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think all those methods should be standard methods in hull client
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to standard client.
docs/examples/context_definition.js
Outdated
del: () => {}, | ||
}, | ||
|
||
// OPTIONAL - method to queue jobs to internal queue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this method name should be a verb. either enqueue
or perform_async
/ perform_later
. We have also see that some jobs need to be scheduled / performed in the future. You can also have a look at Sidekiq's API which works quite well for us already ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to enqueue
.
// yet may be adjusted freely by ship developer | ||
service: { | ||
client: { | ||
get: () => {}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess actions performed on the service by the ship should be encapsulated in the service agent. I think we should keep this structure as simple as possible. No need to expose the client
and agent
separately here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can simplify that for the default architecture. The structure here is elastic and allows connector developer to pick best solution.
…fhandler handlers
* @param {Object} user Hull user object | ||
* @return {Boolean} | ||
*/ | ||
export default function filterUserSegments(ctx, user) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@michaloo as discussed earlier let's make the path configurable, and / or allow to pass a list of segment Ids also
if (segment) { | ||
search.segment_id = segment.id; | ||
} | ||
const url = URI(`https://${hostname}`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would pass the hostname explicitly here. Not use the ctx directly.
hostname
is bot available in a worker context, right ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All helpers
functions needs adjustments, I've bound them to the context for the simplicity and consistency of the signature, but I agree it's too heavy dependency for most of them. I will rework them.
src/utils/action-handler.js
Outdated
const router = Router(); | ||
router.use(requireHullMiddleware); | ||
router.post("/", (req, res, next) => { | ||
return Promise.resolve(handler(req.hull, _.pick(req, ["body", "query"]))).then(next, next); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would directly pass the whole req
object to the handler here. @michaloo do you see any reason not to do so ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found it quite confusing if I have fn(req.hull, req)
as arguments, since I can get first from the second one. What would you tell about:
handler(req.hull, _.omit(req, ["hull"]))
?
src/utils/response-middleware.js
Outdated
* @param {Object} res | ||
* @param {Function} next | ||
*/ | ||
export default function segmentsMiddleware(result, req, res, next) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops wrong function name ?
@@ -0,0 +1,37 @@ | |||
import _ from "lodash"; | |||
|
|||
const fieldPath = "ship.private_settings.synchronized_segments"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can use synchronized_segments
as a naming convention and default value here but let's make this configurable.
docs/CONNECTOR.md
Outdated
```js | ||
import Hull from "hull"; | ||
|
||
const app = new Hull.App({ port, hostSecret, service }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we don't want to take over
the app. We want to be an enhancement to an express app.
for 2 reasons
1 - it's less scary. People know how express works, and they understand it.
2 - sometimes (such as Slack bot or when integrating in your own stack) you just can't create a new app, you have to enhance an existing one in a specific way. Look at https://github.com/hull-ships/hull-slack/blob/develop/server/server.js
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@unity just to sum up our discussion here - I all agree with your arguments, I find the express based architecture a good choice too.
I will just tell you that all that parts going far from plain express app, are caused by slightly different approach which I had in mind. After discussions with you and @sbellity trying to bring together your perspectives I came to a conclusion that the express application is only some part of our ship application, btw. the part which could be replaced or changed in some point in the future (for other http framework as koa or dropped for other solution).
But after seeing all the discussion here, I clearly see that you are all for having the express
as a first citizen of the whole architecture. So this is my proposition which should reconcile everybody here :)
- Let's make the sacred
const app = express();
line being called within the ship - Let's make the current
Hull.App
a class returning a set of middlewares, routers and commands (so a method which takes theapp
and mutates it, applying some custom logic) - my perspective here is if I were the external ship developer I would find theapp = express
approach most comfortable for the reason you've brought here up. Yet observing the first actual developers doing their first ships I see that they are much much more focused on the business logic, the parts related to the 3rd party API that to the ships internals or infrastructure parts. I would say that the mind flow of a developer could be totally opposite to the natural flow of the application. That's why I will suggest having a "super command" method where you can start very easily having all the basics set up on our current convention (like manifest, README, templates), then you can turn it off and switch to more low level elements.
docs/CONNECTOR.md
Outdated
|
||
// ... application configuration | ||
|
||
app.start(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same thing here.
I don't know what app
is but I know it's not express, and start()
doesnt let me decide on the port in the place I'm used to. I don't know what routes are available, exposed and configured. Black box
As a regular Node developer knows app
to be an express
instance. Here it's app
but it's something different.
docs/CONNECTOR.md
Outdated
```js | ||
const app = new Hull.App({ port, hostSecret, service }); | ||
|
||
const server = app.server(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This entertains the confusion even more.
We are using app
(which is still not an express app) and calling server
to create an express app...
And then we're not calling it app
but server
, and we're not setting it up.
The reason we want to set it up:
-
we want control over the port
-
we might want to add middlewares before and after hull does it's job
-
we want to be able to set the engines and static assets. Hull shouldn't force and own this. it's "good" boilerplate.
-
we can't setup an express router here unfortunately since routers can't have engines.
router.set
isn't supported
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we might want to add middlewares before and after hull does it's job
This is still the hardest point of the architecture. Before we had the handlers/routers a blackboxes with all middlewares being applied (https://github.com/hull/hull-node/blob/master/src/notif-handler.js#L173), without the option to inject some custom logic between selected middlewares. Right now, they are split into a app level and router level, this allows for some degree of customization, but still not perfect.
I will come up with some new examples here too.
docs/CONNECTOR.md
Outdated
const worker = app.worker(); | ||
|
||
worker.attach({ | ||
customJob: (req) => { process } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
attach
isn't very clear. should add docs on how it works
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that attach might not be the right verb here.
Why not use
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem, I will switch the naming here.
docs/CONTEXT.md
Outdated
[Hull API client](../README.md) initialized to work with current organization | ||
|
||
#### ship | ||
Ship object with manifest information and `private_settings` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needs some example data
docs/MIDDLEWARES.md
Outdated
```js | ||
import Hull from "hull"; | ||
|
||
app.use(Hull.Middleware({ hostSecret: "supersecret" })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here, what is app
. is it an express
app or a hull
app?
It seems here it's express
- example of confusion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know it's my paragraph here ;P
docs/MIDDLEWARES.md
Outdated
- If the configuration or the secret is invalid, an error will be thrown that you can catch using express error handlers. | ||
|
||
```js | ||
app.use(function(req, res, next){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is a very important one.
Developer MUST be allowed to define his own middleware in the middle of the stack to define how the Token will be retrieved and put in the right place (req.hull.token
) or the right keys (req.hull.config
)
docs/MIDDLEWARES.md
Outdated
|
||
app.use((req, res) => { res.json({ message: "thanks" }); }); | ||
|
||
app.use(function(err, res, req, next){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here. this MUST be something the developer can do. a generic error catching middleware to avoid crashes where he can decide what to return
Cant' take this away from them
docs/MIDDLEWARES.md
Outdated
|
||
## serviceMiddleware | ||
This is a middleware which helps to inject the custom ship modules to the request object. | ||
Thanks to that, all the custom functions and classes are automatically bind to the context object: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"bound"
docs/MIDDLEWARES.md
Outdated
app.post("/get-segments", (req, res) => { | ||
const { service } = req.hull; | ||
|
||
service.getSegmentIds({ limit: 500 }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do this. I feel
import getSegmentIds from "get-segment-ids"
...
getSegmentIds({limit: 500, context: req.hull })
is just as simple and has even less side-effects.
What's the benefit here?
I'm creating this PR to get an agreement on new API and context dependency container.