Coder Social home page Coder Social logo

octoris's Introduction

Welcome

Hello! ๐Ÿ‘‹ Welcome to my profile

I'm Dustin, a Fullstack Software Engineer,

I'm a Functional Developer at heart, and my most used toolset/language is JavaScript. I've authored many cool and fun libraries for the language!

I'm always looking to expand my horizons though and I've been delving little by little into other languages like Haskell, Clojure, Elm, and Scheme/Racket!

Thanks for taking the time to read this, check out my toolsets and feel free to ask questions/open issues/contibute where you see fit.

Dustin's GitHub stats Top Langs

octoris's People

Contributors

dhershman1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

mahramus

octoris's Issues

Current router setup doesn't work well with Async

The current setup for the router and response handlers/methods does not seem to cooperate very well with async structure.

Which makes sense when looking at them. They're sort of pushed down a path of required to be returned themselves to the listener. Which needs to be tweaked since this breaks setups for html with modules like fs when using them async.

They work just fine when using sync, but we need to support async too.

See the "simple-html" example for failing code, and see why it fails with our current setup (should be pretty obvious future me)

  • Fix Handler Setup for Async support
  • Tweak for perhaps using a promise architecture
    • We don't need to worry about async/await since this is a rather wasteful syntax and just uses promises anyway

This may go hand in hand with #3 cleanup and tweaking the way http methods work. Since these also need to be re approached.

Params storing not found paths

There's an issue with parameters as it seems like even when I don't have a route defined the item will try to go and match a parameter, thus causing it to use the first route method.

This issue is reproducible if you do npm run core and then go to a route like /homr which doesn't exist.

It will still give you the home page with Hello World!.

It should give me a 404 instead.

There also seems to be an issue with favicon (maybe this is the brunt of the problem) since one does not exist you see the home map come back with a param attached for 'favicon.ico' this should also not be a thing, the favicon should also give back a 404.

This will go along for our 404 handling within the router. #2

Clean up Require/Import setup

This is a issue ticket to talk about cleaning up the way importing/requiring of octoris works.

Currently the idea was:

const { send } = require('octoris/response')
const { GET } = require('octoris/methods')
const { route, fixed, routeReducer } = require('octoris/router')

But my fear is that this may become to cumbersome to fully use, I also feel like I might be making it a bit to "micro" when it comes to separation of concerns.

So a new proposed idea of handling this might be just making everything a module object apart of octoris so requiring them would be super easy:

const { router, methods, response } = require('octoris')

There is also the theory that combining methods and response into router might be a solid idea but I am not 100% sold on this just yet.

I like being able to do

const { router, methods, response } = require('octoris')

methods.GET
response.send

Vs having to do

const { router } = require('octoris')

router.methods.GET
router.response.send

This is all subject to change and is mainly theory and ideas for now. More will come in the future.

Thoughts? Concerns? Comments?

Response API

As per usual, things are subject to change

Related Issues

  • #2 Routing API
  • Context when an issue is created

Tasks

Note: The following task list below is not fully fleshed out as more functions will probably be added at a later date

  • send response function
  • json response function
  • Handles status codes
  • Handles redirect function
  • Properly handle 404 responses
  • Optimized partial application and flow

Description

The Response API would be in charge of working directly with Routing. It would handle all things related to building a proper response and giving it to the client.

Once again it will be a module of functions you can bring in like so:

const { send } = require('octoris/response')

send won't be the only available function here, as there will be many you can use to respond properly. Each function will be granted it's own issue.

As of right now I am unsure how I want to handle responses completely. For example status codes, would I rather attach a status code to the function? Or use a different function like setStatus to set a status code?

Usage

The below example is simply giving the status code to the function and then the data, as mentioned above this may or may not be a thing.

const { redirect, send } = require('octoris/response')

const getHandler = ctx => {
   // Context isn't fleshed out enough yet to nail down an example
  if (!ctx.something) {
    return redirect(404, '/')
  }

  return send(200, 'You did it!')
}

Core API

This issue may be broken down into multiples if needed

Tasks

  • Core server functionality
  • Hosts server on desired port
  • Accepts routing setup from routeReducer
  • Gives back a new promise on startup
  • HTTP create server
  • Optimized route tree navigation
  • Optimized startup process (Ongoing)

The core to octoris will be the primary module you get when just importing/requiring octoris like so:

const octoris = required('octoris')

This will give you a function that accepts two parameters.

Parameters

  • options: Object - The options given to octoris
    • options.port: Number - The port number to run on
  • routes: Function|Object (Not decided Yet) - These will be the collected and built out routes octoris should listen too

There is ideas of passing a middleware array to options as well, this has not been confirmed because there is also the idea of helper functions to achieve this as well as many other things. These issues (once created) will be linked to this one at a later date

Usage

const octoris = require('octoris')
const routes = require('./routes')

octoris({ port: 8080 }, routes)
  .then(() => console.log('server started!'))
  .catch(console.error)

Make Middleware more end user friendly

Right now we require the end users middleware to do a lot of the heavy lifting in order to conform to the way the octoris framework functions.

Instead we could probably run a Promise.resolve on the return value of the middleware function. This will allow us to maintain a consistent interface internally, but make it slightly nicer for our end users to build middleware.

Request API

This is subject to change as the planning continues and grows

Related Issues

  • #2 Routing API
  • #3 Response API

Description

The Request API would work a lot like Response does in the sense, it's job is to handle the request object and provide easy ways to work with the data.

It will be contained within the request module and usable like so:

const { parse } = require('octoris/request')

Now also like response parse won't be it's only function it's just the only one in planning atm. Each function will be granted it's own issue.

Usage

The below example is simply giving the status code to the function and then the data, as mentioned above this may or may not be a thing.

const { parse } = require('octoris/request')
const { send } = require('octoris/response')

const postHandler = ctx => {
  const data = parse(ctx.data)

  if (!data) {
    return send(500, 'No Data Provided')
  }

  return send(200, 'Data Saved!')
}

Middleware Engine/API

Warning this one is still in theory mode so the issue may be long

Tasks

  • Basic Middleware support
  • Middleware added into flow
  • Simplified how middleware should be passed and called
  • Middleware is able to update the context object
  • Pass along new context to proper method functions

Description

The Middleware engine and API will be pretty straight forward. For info on what it may look like please visit the middleware.md notes

As of this moment I am unsure whether or not we will need a octoris/middleware require or if we will only have a single function to handle middleware and that function can live in the octoris/utils (or maybe even just have it live in octoris/router) instead.

Usage

The flow will work something like this: (Or at least the idea is this)

const { route, static } = require('octoris/router')
const { send } = require('octoris/response')
const { GET } = require('octoris/methods')
const { use } = require('octoris/utils')
const someMiddleware = require('someMiddleware')

const homeHandler = () => send(200, 'hello world!')

route([static('home')], [
  GET(homeHandler),
  use(someMiddleware)
])

The problem here is how does the GET(homeHandler) know about the use(someMiddleware)? They're not exactly connected or related that well aside from the fact that one comes after the other.

A quick solution to this might be to change the above route to something more like this:

route([static('home')], [
  [GET(homeHandler), use(someMiddleware)]
])

So now when route sees this array it will know that the GET is also expecting something else like middleware.

My only problem with the above is that we are now needing to handle different data expectations, sometimes it could be a function sometimes its an array. Which isn't the worst but it isn't that good either.

Middleware Branch Concept

(We still need a way to get it to the radix tree which is what the above proposal would do)

Another theory/concept could be that middleware is given a branch within the Radix Tree of routes. For instance /home with a GET forms a Radix tree that looks like this:

Map {
  'home': Map {
    type: 'static'
    optional: false,
    methods: Map {
      'GET': Function
    }
  }
}

So what if a middleware being attached to a route method just becomes a value within that Map something like this:

Map {
  'home': Map {
    type: 'static'
    optional: false,
    methods: Map {
      'GET': Map(?*) {
        handler: Function,
        middleware: Function[] || Set
      }
    }
  }
}

(?*): This doesn't need to be a Map, this could easily just be an Object here

With the above when the /home route is triggered it will look at the GET handler and see if any middleware is also there, if so use that first and then the handler.

Important: This layout would be used even if there was no attached middleware, in that instance middleware would just be an empty Array/Set

send Response Function

send is a function for the Response module of octoris. It's prime use is to just send data back to the client

Concept

We set status on the response

const { send } = require('octoris/response')

// Works
send(200, 'You did a thing!')

// Does not work still
send(200, { a: 1 })

This approach is nice because we tell our response "everything is 200 OK here is some data" so it's more straight forward and easy to see what is going on.

Testing API

Tasks

  • inject Function
  • Probably more...

Description

A Testing API that provides functionality for testing parts of your app as you build it out within Octoris

How we want to access this is another story, I am unsure if I want this to be it's own section or simply live within the utiles:

const { inject } = require('octoris/testing')

// OR

const { inject } = require('octoris/utils')

Usage

This example is currently how inject works, however I plan in the future its usage will most likely change

const { inject } = require('octoris/testing')
const { send } = require('octoris/response')
const { GET } = require('octoris/methods')
const { route, fixed, routeReducer } = require('octoris/router')

function homeHandler (ctx) {
  return send(200, 'Hello World!')
}

const home = route([fixed('home')], [GET(homeHandler)]

inject({ method: 'GET', url: '/home' }, routeReducer([home]))
  .then()
  .catch()

The above is a general idea of how the flow runs with inject. A few things I want to change for it are needing routeReducer, I'd much rather just allow you to give me the route itself and I will take it from there. (Maybe using routeReducer behind the scenes)

Routing API

As the project grows this is subject to change
This may be broken down into multiple smaller issues if needed

Note: static was renamed to fixed due to it being a keyword in js classes for whatever reason

Related Issues

  • #4 Request API
  • #3 Response API
  • #5 Methods

Tasks

  • Basic Routing Method Support
  • Support for Accepted Methods
  • Route Builders
  • Route Reducer
  • Support for route params
  • Support for query params
  • Complete Radix Tree Setup
  • Create basic Context Object
  • Optimized Router Builder
  • Context can be re built with middleware
  • Catch All Route support
  • Route Middleware handling
  • 404 Handling
  • Reliable Error handling/feedback
  • Route Logging and reports
  • Optimized lifecycle of finding and using a route

Description

The routing api is obviously the key piece in allowing and listening to routes the user specifies. With our completely functional approach with octoris we have a lot of ways we can approach this.

With that being said, expect this ticket to change a lot.

The router will be a separate module of functions like everything else, what functions this module contains is yet to be determined. It will look a little like this:

const { route } = require('octoris/router')

Usage

Following the goal of not having magic happening the function might look like so:

const { route, fixed } = require('octoris/router')
const { GET, POST } = require('octoris/methods')

router([fixed('home')], [
  GET(getHandler),
  POST(postHandler)
])

For more info on octoris/methods please see the {link issue here} methods issue

Where in the above the handlers will be route handling functions you can build out to handle when the specified route is hit with the specific method.

Regardless of how many methods a route uses even if it only has a GET it should still live in an Array:

const { fixed, route } = require('octoris/router')
const { GET } = require('octoris/methods')

router([fixed('home')], [GET(getHandler)])

HTTP Methods

This is subject to change as the planning continues and grows

Related Issues

  • #2 Routing API

Tasks

  • Create supported HTTP Method Functions
    • Tweak these if we need each one to act just a little differently
  • Have methods support middleware (Possibly)
  • Improve flow based on above

Methods

The methods below have been implemented with basic functionality. I am unsure if much tweaking is needed for them to do anything "particular" at this point. However clean up is recommended as currently it is just the same function with different names, I also don't like how these are handled and written out. Should for sure revisit this soon.

  • CONNECT
  • DELETE
  • GET
  • HEAD
  • OPTIONS
  • PATCH
  • POST
  • PUT
  • TRACE

Description

The HTTP methods will be what kind of methods are allowed/able to be handled for a route They will come as functions that you will give your handler too, and then assigned to a route listener.

You can grab them from the methods module like so:

const { GET, POST } = require('octoris/modules')

You can use destructure to grab all of the methods you want/need

Usage

const { route, static } = require('octoris/router' 
const { GET, POST } = require('octoris/methods')

// Use them directly with the route array
route([static('about')], [
  GET(getHandler),
  POST(postHandler)
])

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.