Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
October 9, 2022 09:01 am GMT

HTTP based OOP

There is a reason why I don't like classic OOP. The primary one being that it destroys my creativity and ability to express myself. As proof of that, realise I just invented HTTP based OOP, with inheritance and polymorphism, with the capability of "overriding" an existing HTTP endpoint, and inject additional logic in my "HTTP interceptor", allowing me to "extend" the original HTTP invocation. This allows me to inject additional custom business logic in my original HTTP endpoint, without modifying it. And of course, it's almost impossible to implement using classic OOP.

In the video below I am demonstrating how to implement Stripe payments into "whatever" HTTP API you have from before, using polymorphism, and "overriding" my original HTTP invocation. Basically, I am demonstrating HTTP based OOP, overriding my existing endpoint.

The beauty of this is that it doesn't matter what your original HTTP endpoint is implemented in, as long as it accepts JSON and returns JSON. You can use this with ...

  • Python
  • PHP
  • GraphQL
  • PostgREST
  • Hasura
  • Supabase
  • C#
  • Java
  • "Whatever" really ...

More interestingly, this is almost impossible to achieve with classic OOP, due to OOP's "obsession with strongly typing". You can literally only do this in a non-OOP context, where you completely ignore strongly typing - Hyperlambda being one such example. Implying that Hyperlambda can basically "override" anything you might have from before, as long as it's based upon HTTP and JSON. The technique is easily understood by anyone understanding the concept of YALOA or "Yet Another Layer Of Abstraction".

In the video example above, I need to apply some (tiny) changes to my original backend, to allow for associating users with Stripe customer IDs, create a one to many relationship between users and payment methods, and store payments and subscriptions internally in my app. However, these changes would be microscopic in nature compared to the code required to implement Stripe manually in my own backend. Hence, I basically eliminate 90% of the burden required to implement Stripe. And, if I want to, I can probably create a generalised version of the above example, where I am no longer dependent upon Stripe, but can easily exchange my payment provider with any other payment provider by simply changing my Hyperlambda file. The last part allows me to change my payment provider, without touching my own backend, but instead simply providing an additional "overridden" HTTP method.

Notice, if you want to ensure your intercepted HTTP endpoint becomes the equivalent of "private", you might want to attach some "secret" token to the invocations towards your encapsulated endpoint, and only exposing it to your Magic cloudlet. If you don't do this, people capable of "guessing" the URL to your original endpoint might in theory be able to fake payments, getting product for free.

The process is quite simple.

  1. Create a Hyperlambda endpoint
  2. Invoke your own "extended" business logic in your Hyperlambda endpoint
  3. Invoke the "overridden" HTTP endpoint, optionally with additional data resulting from executing your Hyperlambda
  4. Return to the client whatever data your "encapsulated" endpoint returns

Paradoxically, HTTP based OOP is not only good OOP, but also good SOLID, and for the most parts obeys by the Open-Closed Principle, and there is zero OOP in it. To explain it a bit humorously with some "geek humour" ...

No classes where harmed while inventing HTTP OOP

Watch the above video to understand the concept. Now as to what to refer to this as? I've got no idea, however my initial intuition tells me it is O2, as in Objects to the second exponent or something - Suggestions ...? :D

At least that name would make Bjarne Stroustrup and Anders Hejlsberg choke for a while on their morning coffee ... ;)

I want to emphasise that this is (almost) 100% impossible using classic OOP, and requires a super dynamic programming language such as Hyperlambda.

To reproduce what I am doing, register for a cloudlet below, and start playing with O2 ...

Thank you for reading, now let the debate begin :D

Below is my code ...

echo.post.hl

add:x:+   get-nodes:x:@.arguments/*return

customer.post.hl

.arguments:*.description:Interceptor invoking Stripe to create a Stripe customer, for then to attach the customer ID to specified payload, before invoking intercepted endpoint./* * Invoking Stripe to create a customer for then to attach * the customer ID to the payload we're passing in to the * original endpoint, before invoking intercepted endpoint * now with a Stripe Customer ID, allowing you to associate * the user internally with a Stripe customer object. */.before   /*    * If you're using automatic tax calculations, you'll    * need to pass in the IP address of the client - At    * which point you'll have to uncomment the line of    * code below, and pass it into slot invocation.    */   request.headers.get:X-Real-IP   // Sanity checking invocation.   validators.mandatory:x:@.arguments/*/name   validators.mandatory:x:@.arguments/*/email   validators.email:x:@.arguments/*/email   // Invoking Stripe API.   unwrap:x:+/*   signal:stripe.customers.create      name:x:@.arguments/*/name      email:x:@.arguments/*/email      ip_address:x:@request.headers.get   // Attaching Stripe's customer id to the payload.   unwrap:x:+/*/*   add:x:../*/http.post/*/payload      .         stripe_customer_id:x:@signal// Evaluating Stripe lambda object.eval:x:@.before// Endpoint we're intercepting..endpoint:"https://tiger-polterguy.gb.aista.com/magic/modules/stripe-interceptor/echo"/* * Checking if we've got an Authorization HTTP header, * at which point we forward it to the original HTTP endpoint. */request.headers.get:Authorizationif   not-null:x:@request.headers.get   .lambda      add:x:../*/http.post/*/headers         .            Authorization:x:@request.headers.get// Forwarding arguments given to endpoint to intercepted endpoint.add:x:../*/http.post/*/payload   get-nodes:x:@.arguments/*// Invoking the intercepted HTTP endpoint.http.post:x:@.endpoint   headers      Content-Type:application/json   convert:true   payload// Returning the intercepted endpoint's status code.response.status.set:x:@http.post// Returning response payload from intercepted endpoint to caller.add:x:+   get-nodes:x:@http.post/*/content/*return

payment-method.post.hl

.arguments:*.description:Interceptor invoking Stripe to create a payment method for the specified customer, for then to attach the payment method id and payment method data to the specified payload, before invoking intercepted endpoint./* * Invoking Stripe to create a payment method and associate * it with the specified customer, for then to attach the * payment data to the original endpoint, before we invoke * intercepted endpoint. */.before   // Sanity checking invocation.   validators.mandatory:x:@.arguments/*/card_number   validators.mandatory:x:@.arguments/*/card_exp_month   validators.mandatory:x:@.arguments/*/card_exp_year   validators.mandatory:x:@.arguments/*/card_cvs   validators.mandatory:x:@.arguments/*/customer_id   // Invoking Stripe to create a payment method.   unwrap:x:+/*   signal:stripe.payment_methods.create      card_number:x:@.arguments/*/card_number      card_exp_month:x:@.arguments/*/card_exp_month      card_exp_year:x:@.arguments/*/card_exp_year      card_cvs:x:@.arguments/*/card_cvs   // Invoking Stripe to attach the payment method to the customer.   unwrap:x:+/*   signal:stripe.payment_methods.attach      customer_id:x:@.arguments/*/customer_id      payment_method:x:@.before/*/signal/[0,1]/*/id   // Making sure we pass in 4 last digits of card to intercepted endpoint.   strings.length:x:@.arguments/*/card_number   math.subtract:x:-      .:int:4   strings.substring:x:@.arguments/*/card_number      get-value:x:@math.subtract      .:int:4   /*     * Passing in brand, payment method id, and 4 last digits of card    * to intercepted endpoint.    */   unwrap:x:+/*/*   add:x:../*/http.post/*/payload      .         brand:x:@.before/*/signal/[0,1]/*/brand         card:x:@strings.substring         payment_method_id:x:@.before/*/signal/[0,1]/*/id   // Removing card data.   remove-nodes:x:@.arguments/*/card_number   remove-nodes:x:@.arguments/*/card_exp_month   remove-nodes:x:@.arguments/*/card_exp_year   remove-nodes:x:@.arguments/*/card_cvs// Evaluating [.before] lambda object.eval:x:@.before// Endpoint we're intercepting..endpoint:"https://tiger-polterguy.gb.aista.com/magic/modules/stripe-interceptor/echo"/* * Checking if we've got an Authorization HTTP header, * at which point we forward it to the original HTTP endpoint. */request.headers.get:Authorizationif   not-null:x:@request.headers.get   .lambda      add:x:../*/http.post/*/headers         .            Authorization:x:@request.headers.get// Forwarding arguments given to endpoint to intercepted endpoint.add:x:../*/http.post/*/payload   get-nodes:x:@.arguments/*// Invoking the intercepted HTTP endpoint.http.post:x:@.endpoint   headers      Content-Type:application/json   convert:true   payload// Returning the intercepted endpoint's status code.response.status.set:x:@http.post// Returning response payload from intercepted endpoint to caller.add:x:+   get-nodes:x:@http.post/*/content/*return

payment.post.hl

.arguments:*.description:Interceptor invoking Stripe to create a payment for a customer, for then to attach the payment data to specified payload, before invoking intercepted endpoint./* * Invoking Stripe to create a payment and associate * it with the customer, for then to attach the * payment data to the payload we're passing in to * the original endpoint. */.before   validators.mandatory:x:@.arguments/*/amount   validators.mandatory:x:@.arguments/*/currency   validators.mandatory:x:@.arguments/*/payment_method   validators.mandatory:x:@.arguments/*/customer_id   unwrap:x:+/*   signal:stripe.payments.create      amount:x:@.arguments/*/amount      currency:x:@.arguments/*/currency      payment_method:x:@.arguments/*/payment_method      customer_id:x:@.arguments/*/customer_id   // Passing in payment data to intercepted endpoint.   unwrap:x:+/*/*   add:x:../*/http.post/*/payload      .         payment_id:x:@signal/*/id// Evaluating [.before] lambda object.eval:x:@.before// Endpoint we're intercepting..endpoint:"https://tiger-polterguy.gb.aista.com/magic/modules/stripe-interceptor/echo"/* * Checking if we've got an Authorization HTTP header, * at which point we forward it to the original HTTP endpoint. */request.headers.get:Authorizationif   not-null:x:@request.headers.get   .lambda      add:x:../*/http.post/*/headers         .            Authorization:x:@request.headers.get// Forwarding arguments given to endpoint to intercepted endpoint.add:x:../*/http.post/*/payload   get-nodes:x:@.arguments/*// Invoking the intercepted HTTP endpoint.http.post:x:@.endpoint   headers      Content-Type:application/json   convert:true   payload// Returning the intercepted endpoint's status code.response.status.set:x:@http.post// Returning response payload from intercepted endpoint to caller.add:x:+   get-nodes:x:@http.post/*/content/*return

subscription.delete.hl

.arguments:*.description:Interceptor invoking Stripe to create a subscription for a customer, for then to attach the subscription id to specified payload, before invoking intercepted endpoint./* * Invoking Stripe to create a subscription and associate * it with the customer, for then to attach the * subscription data to the payload we're passing in to * the original endpoint. */.before   // Sanity checking invocation.   validators.mandatory:x:@.arguments/*/subscription   // Invoking Stripe.   unwrap:x:+/*   signal:stripe.subscriptions.cancel      subscription:x:@.arguments/*/subscription// Evaluating [.before] lambda object.eval:x:@.before// Endpoint we're intercepting..endpoint:"https://tiger-polterguy.gb.aista.com/magic/modules/stripe-interceptor/echo"/* * Checking if we've got an Authorization HTTP header, * at which point we forward it to the original HTTP endpoint. */request.headers.get:Authorizationif   not-null:x:@request.headers.get   .lambda      add:x:../*/http.post/*/headers         .            Authorization:x:@request.headers.get// Forwarding arguments given to endpoint to intercepted endpoint.add:x:../*/http.post/*/payload   get-nodes:x:@.arguments/*// Invoking the intercepted HTTP endpoint.http.post:x:@.endpoint   headers      Content-Type:application/json   convert:true   payload// Returning the intercepted endpoint's status code.response.status.set:x:@http.post// Returning response payload from intercepted endpoint to caller.add:x:+   get-nodes:x:@http.post/*/content/*return

subscription.post.hl

.arguments:*.description:Interceptor invoking Stripe to create a subscription for a customer, for then to attach the subscription id to specified payload, before invoking intercepted endpoint./* * Invoking Stripe to create a subscription and associate * it with the customer, for then to attach the * subscription data to the payload we're passing in to * the original endpoint. */.before   // Sanity checking invocation.   validators.mandatory:x:@.arguments/*/price   validators.mandatory:x:@.arguments/*/customer_id   validators.mandatory:x:@.arguments/*/payment_method   // Invoking Stripe.   unwrap:x:+/*   signal:stripe.subscriptions.create      price:x:@.arguments/*/price      payment_method:x:@.arguments/*/payment_method      customer_id:x:@.arguments/*/customer_id   // Passing in subscription data to intercepted endpoint.   unwrap:x:+/*/*   add:x:../*/http.post/*/payload      .         subscription_id:x:@signal/*/id         product:x:@signal/*/product// Evaluating [.before] lambda object.eval:x:@.before// Endpoint we're intercepting..endpoint:"https://tiger-polterguy.gb.aista.com/magic/modules/stripe-interceptor/echo"/* * Checking if we've got an Authorization HTTP header, * at which point we forward it to the original HTTP endpoint. */request.headers.get:Authorizationif   not-null:x:@request.headers.get   .lambda      add:x:../*/http.post/*/headers         .            Authorization:x:@request.headers.get// Forwarding arguments given to endpoint to intercepted endpoint.add:x:../*/http.post/*/payload   get-nodes:x:@.arguments/*// Invoking the intercepted HTTP endpoint.http.post:x:@.endpoint   headers      Content-Type:application/json   convert:true   payload// Returning the intercepted endpoint's status code.response.status.set:x:@http.post// Returning response payload from intercepted endpoint to caller.add:x:+   get-nodes:x:@http.post/*/content/*return

Original Link: https://dev.to/polterguy/http-based-oop-3lj7

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To