How in node to access pug attributes in javascript via a script include

If you found this article then you have a very specific kinda problem, just like I did.

I have a node app on which I am running express to serve pages, i’m also wanting to use Pug to organise my ‘views’.  All of this works fine until you throw javascript into the mix.

Sure, you could just embed the code directly in your .pug page, but that’s not very tidy now is it.

//index.pug
doctype html
  html(lang="en")
    head
    script.
      var foo = bar;
      console.log(foo);
      

Note that there is a . at the end of script.. This allows you to write code directly in the template, rather than have pug evaluate everything within it.

For my purposes I want to keep js away from the template to keep things neat and tidy so it needs to be kept in a specific .js file.

Including a script file in pug/jade is quite simple:

script
  include ./assets/js/tidy.js

But then how would you reference the pug attributes that you have access to within index.pug in the external javascript file?

The first change I had to made was in my app.js file where I was passing in the data to the .pug template. Originally I was passing just the object (so I could then reference the attributes directly) but this makes things tricky for the next step, so I changed the object I was passing in so that I could pick up the data by name.

//app.js
app.get('/product_options', (req, res) => {
  Shopify.get_product_options(req.query.pid).then(product =>
    res.render('product_options', {product: product})
  );
});

This means that I can reference product from my template directly, which will be handy when we stringify its content in order to pass it over to the js file.

//index.pug
doctype html
html(lang="en")
  head
    script.
      var l = !{JSON.stringify(product)}
    script  
      include ../assets/js/product_options.js

Note the !{} interpolation syntax, rather than the standard {}, this prevents any escaping and allows us to take the string value of the products option and write it out to the page in the var l = assignment.

We should now be able to reference l from any external js.

//tidy.js
$( document ).ready(function(){
  console.log(l);
});

It feels like there should be a better way of handling this, so if you know of one please leave a comment and let me know. It might not be pretty but it achieves good separation and allows you to benefit from pugs, otherwise, excellent templating.

Python Multi-Part Post files and data

Sending data and a file using python, to a rest api?  Then you’ll need a multipart post request and this post might save you a little bit of time!

I’ll show you how to construct a basic script that will allow you to send both form data and an arbitrary file (in this case a csv), and point out where I initially had a few issues.

The finished article:

import requests

file = { 'file' : ('csvtest.csv', open('csvtest.csv', 'rt'), 'text/csv') }
payload = { 'parser' : '{object trimmed for comment}' } 
headers = { 'accept': "application/json", 'authorization': "Basic ZGxhZG1pbjp0aGlua2JpZw==", } 
url = "http://localhost:8400/proxy/v1/schema-discovery/hive/sample‌-file" 
req = requests.post(url, data=payload, files=file, headers=headers) pprint(req.text) 

Lets go through that part by part:

import requests

This makes the ‘requests‘ library available to Python.  Its very similar in nature to the http.client package, but has additional attributes that you can call that make putting together a multipart request a lot more simple.

file = { 'file' : ('csvtest.csv', open('csvtest.csv', 'rt'), 'text/csv') }

This constructs a tuple with the name of the file, the file contents, and the file type.  In a lot of the documentation I found the name and type were optional, but for the api I was using I needed to specify both for it to be accepted.

One additional thing to note is the open() method.  Again, most tutorials I found suggested opening in binary mode ‘rb’, but in order to get the text to appear in the request body within the multipart request I needed it setting as text (‘rt’).

payload = { 'parser' : '{object trimmed for comment}' }

This the data I wanted to send alongside the file. The parser value was a huge json string, so i’ve trimmed it here for readability.

headers = { 'accept': "application/json", 'authorization': "Basic ZGxhZG1pbjp0aGlua2JpZw==", }

The thing to note here is the absence of the ‘content-type’ header. By supplying the header it seems to confuse things, as in the last step where we make the post request we specify both file and data which is recognised and the relevant headers built for us when the request is build.

url = "http://localhost:8400/proxy/v1/schema-discovery/hive/sample‌-file"

The URI for the Rest API I am trying to hit.

req = requests.post(url, data=payload, files=file, headers=headers)

This is the basic construct for the request.  The verb (“post”) is set as a method (although you can call this in a different way).  We add by name the data, files and headers and make the request.

The package then creates the request body and sets the relevant multipart boundaries and inserts the relevant data.

I believe that you can pass an array of files into the files argument although I have not tested that here.

Hopefully this will save someone the time it took me to figure it out.

Level Up – Privacy Policy

Privacy

LevelUp respects your privacy.

Any personal information you provide to us including and similar to your name, address, telephone number and e-mail address will not be released, sold, or rented to any entities or individuals outside of LevelUp.

Credit card details

LevelUp will never ask for Credit Card details and request that you do not enter it on any of the forms on LevelUp.

External Sites.

LevelUp is not responsible for the content of external internet sites. You are advised to read the privacy policy of external sites before disclosing any personal information.

Cookies

A “cookie” is a small data text file that is placed in your browser and allows LevelUp to recognize you each time you visit this site(customisation etc). Cookies themselves do not contain any personal information, and LevelUp does not use cookies to collect personal information. Cookies may also be used by 3rd party content providers such as newsfeeds.

Remember The Risks Whenever You Use The Internet

While we do our best to protect your personal information, we cannot guarantee the security of any information that you transmit to LevelUp and you are solely responsible for maintaining the secrecy of any passwords or other account information. In addition other Internet sites or services that may be accessible through LevelUp have separate data and privacy practices independent of us, and therefore we disclaim any responsibility or liability for their policies or actions.

Please contact those vendors and others directly if you have any questions about their privacy policies.

Black Box Thinking

Black Box Thinking This is another one of those books that I think that everyone should read.  A volume outlining the real dangers of not learning from your mistakes, and the many benefits of embracing your own evolution through (controlled) trial and error.

Having been a startup CEO, and now Head of Technology at another startup I’ve worked, in context, enough to see Cognitive dissonance at play in the majority of businesses I see.  This, for me, was one of those books that gives you that super human power of ‘hindsight’, the time you need to really think about your own actions and the way that I went about trying to build a business.

From the harrowing examples given in the first few chapters to the more focused technical thinking of the later this book gave me that “aha!” feeling about the whole “fail fast” movement.

Being through accelerators and having attended more events and pitches than you can shake a stick at I have been left with a feeling of, almost, rage when thinking about the way so many people talk with pride about how they’ve spunked 100k, half a £1m, £3m away.  Now I realise why I was hearing the story, and what I should try to do about it.  The lessons that they learnt cost them £3m, the same thing just cost me £14 and 12 hours of being challenged and entertained.

MAIN TAKEAWAY:  It’s easy to create a reality where the decisions you are making are the right ones, and to think that you are right in every way.  Personally, I will be writing hypothesis and actions before I take them from now on so that I can hold myself accountable and maximise the learning, and opportunity,  that can come from failure.

You can purchase the book on amazon here.