@awatson1978 Hey no worries and thanks for all the input!! With all the positive feedback i’m going to open source this soon. I’ll also be dogfooding it once I can clean up my proprietary version of this and switch. Also apologies for the long reply… so many things to digest (this really helps me externalize decisions too)
I think this might even be a viable setup for a headless API only setup just because of the advantages of fibers (that’s what i’m doing… no subscriptions or DDP yet).
So… curiously interesting. Wouldn’t have necessarily occurred to me to write the REST API in a functional paradigm; but I don’t see why this couldn’t work splendidly
Same here… I didn’t think about that either until I started tinkering in other languages and their frameworks. One of my favorites is Phoenix which is where a lot of the inspiration comes from with this. One of the perks of tinkering in vary different langs is that they tend to creep back into your JS for the better
Functional programming doesn’t mean we need to ditch namespaces. My hunch is that the general approach will be made more clear by introducing a bit of namespace
Whoops I forgot to add some of the de-structuring. Yep, totally agree! Ideally we’d have ES6 modules and could import those. I’ve been mimicking them in my non-webpack apps with a module namespace. Using Elixir modules is very much like this with the exception of how it imports them. I now tend to have a module per file and do this:
ApiUtils = {
parseResponse(foo, bar) {
return ...
},
};
function myPrivateFunc(foo, bar) {
return 'baz'
}
// then use them with or w/o the namespace depending on what the context is
const {parseResponse} = ApiUtils;
//import {parseResponse} from './utils/api';
parseResponse('blah');
ApiUtils.parseResponse('blah');
So currently most the global looking things are de-structured from the Restful
(working name) namespace, though I forgot to add some to the (const {scope, get} = Restful;
).
For example without the ES6 de-structuring it would look like this:
var authenticateJWT = YourMiddlewares.authenticateJWT;
var ItemController = YourContNamespace.ItemController;
Restful.applyMiddleware(
Restful.acceptJSON(),
authenticateJWT({except: 'post.user'}),
);
Restful.scope('/v1', () => {
Restful.resources('/users', UserController, {except: 'delete'})
Restful.get('/items/', ItemController, 'index')
Restful.post('/items', ItemController, 'create')
})
Any chance you could take a look at oauth2orize and make any recommendations on how to get started with an integration?
Yep! I will look into this. So i’m just using connect under the hood so any connect middleware will plug right in (no pun intended). Then you could use the awesome Passport lib and oauth2orize will hook into that very easily. Speaking of i’m using the simple rest package to utilize basic http auth for logging into an existing meteor account
So… this is a pretty standard server-side MVC approach. We’re in agreement with the controller being a controller; but the Models and Views will confuse some people accustomed to client-side MVC paradigms.
Yep I was afraid this would be kind of vague. So the model namespace would be user provided (Models.Post
) and the model (and Repo
) wouldn’t be in the same package as they aren’t really required. Anyhow, the repo and model are based off of the functional Ecto.Model. It’s basically just an object literal with some functions and config stuff to utilize simple-schema for validation. The Repo package would recognize the format and use it to auto validate and throw errors. I’m still trying to iron these out.
The views are tricky. Also this namespace is user defined so it’s more less by convention. So the thought was that they could choose between a JSON, XML, Text, or even an HTML view (with ES6 strings… something bare bones). Currently i’m only using JSON with my setup. I agree the name is awkward. This is also inspired from Phoenix but i’m not sure what else to call it (ideas?). This would have to be super clear in the docs and opt in of course. Here’s a brief overview of them (http://blog.rokkincat.com/json-views-in-phoenix/). The main thing I like is abstracting out the things like converting unix timestamps and other things that can be messy to test in a controller.
So, the question is whether this ought to be isomorphic. Should it be available on the client?
I was thinking about this too… My gut is to make it not crash on the client by checking for isServer under the hood so it can be loaded in a ‘both’ folder. However I can’t really see much overlap on the client. Keeping it focused (server only) is the plan so far.
So, are you familiar with monads yet?
Not well enough. My thoughts from a Haskell point of view is that a monad is just an acedemic loophole to call something thats a side effect ‘pure’… which confuses me because at the end of the day the monad is not going to undo the log/db insert if you roll back/forward in a time traveling debugger.
The biggest return-on-investment with adding functional programming to javascript apps that we’ve found is when there are clear computational pipelines that need to be created.
Yep, totally! This is what draws me into the lodash/underscore ‘chain’ functionality. Another perk i’ve noticed is that when you explicitly pass in what you’re using it’s very clear what it does/does-not do.
I’m just tossing some ideas out here, but I could imagine a method chaining pattern that connects with the Mongo collections could be extremely useful
This is super cool! One thing that might get messy though is if you have to do things like send out emails, SMS, hit a webhook, etc… then it starts to look like using picker (just a bunch of stuff in one callback). Perhaps something similar for an opt in thing where you don’t really need a controller (like a findOne or find all). Hmmmm