• GraphQL Best Practices: Testing Resolvers

    Getting started with GraphQL and Python most of the documentation is focused on the basics: basic queries, filtering using pre-built libraries and so forth. This is great for quick “Hello World” APIs, but there isn’t much discussion for best practices that discuss how to build out larger APIs, testing, or maintenance. Perhaps it’s just too early in the Python-GraphQL story for the best practices to have been fully established and documented.

    Introductory GraphQL examples online don’t really require much testing of the resolver specifically. This is because these examples  just return the results of a Django Queryset directly. For those types of fields executing a full query is usually enough. But how to you handle more complex resolvers, ones that have some processing?

    Accessing your resolver directly from a unit test is difficult and cumbersome. To properly test a resolver, you're going to need to  split the parts that warrant independent testing into their own functions / classes. Then once it's split, you can pass the required input for processing, and return the results.

    However passing or returning Graphene objects to your functions will make testing them difficult in much of the same way that calling your resolver outside of a GraphQL request is difficult: you can't access the attribute values directly - they must be resolved.

    blog = Blog(title="my title")
    assert blog.title === "my title" # fail

    Where Blog is a Graphene object, the above test will fail. As blog.title will not be a String as you'd think, but rather a graphene wrapper that will eventually return "my title" when passed through the GraphQL machine.

    There's two ways to work around this:


    1. Pass in `namedtuples`  that match attribute for attribute your Graphene objects in their place. This is will become a maintenance headache as each time your object changes, you'll need to also update your named tuples to match.

    2. Pass/return primitive values into your functions and box them into GraphQL objects in your resolver directly before return.

    I've done both in my code and think that the second method is a best practice when writing GraphQL apis.

    By passing the values from graphene as primitives to your processing functions your code is no longer tied directly to graphene directly. You can change frameworks and re-use the same code.

    It's also easier to write tests as you pass in common objects like dict and int which are quite easy to assert equality and simpler to reason about.

    Takeaways:


    1. Break your logic out of your resolver and into specialized functions / classes.

    2. Pass/return primitive or other such values from these functions to maximize reuse.

  • I Didn't Know iCloud Photo Was a Thing

    When sharing photos at work most of my co-workers would simply post a link to Google Photos in our company Slack. As an iCloud user, I thought my photos were only visible on my Mac or iPhone - machines logged in to my Apple account and setup to sync photos. So if I wanted to share photos with co-workers on Slack, I had to either upload them to Flickr or upload them directly into Slack. I always just uploaded them into Slack.

    I just realized today that I can view all of my photos from the web via iCloud Photos. What’s more is I can share photos with a URL just like my co-workers have been with Google Photos. The shared link also expires after 1 month, which is a nice additional security / privacy feature.

    Knowing that I can access my photos outside of Apple devices eases my mind. While I can’t ever see myself switching to Android from iOS, I could see myself using a Thinkpad + Linux for my desktop computing needs.

  • Using MarsEdit with DigitalOcean One-Click Wordpress Installs

    My website has recently come full circle back to Wordpress. It’s been a number of years since I’ve used Wordpress. The last time was probably in college on the cheapest shared host I could find. I avoided coming back to Wordpress because I didn’t want to maintain a server; I fiddle enough with them at work. Already being a Digital Ocean customer, the 1-Click setup/hardened server seemed like the best way to go. 

    I quickly got it configured with all of the IndieWeb plugins to facilitate back-feeding content that I create on other platforms onto my website. The final step starting to use MarsEdit, my old favorite blog editor. Except it couldn’t connect to my website.

    Turns out the reason is that the majority of Wordpress security issues stem from bots abusing the xmlrpc api and the digital ocean install blocks it at a low level by default. Disabling this block on the server allows programs to use the xmlrpc api and hence MarsEdit to work. Execute the following commands to disable the xmlrpc block.

    sudo a2disconf block-xmlrpc
    sudo systemctl reload apache2

  • Checkin to Ootoya (大戸屋)

    in Yokohama, Kanagawa, Japan
  • Checkin to IKEA

    in Yokohama, Kanagawa, Japan
    Can’t visit IKEA and not eat meatballs.
  • Thinking about the Nissan Leaf

    I'm thinking of buying a (used) Nissan Leaf to drive around town and have been collecting some facts and figures to see how it compares with other cars here in Japan. I'm leaning heavily towards the leaf for three reasons: it's cheaper to own/operate, no stopping for gas stations (can charge at home), and I don't want pump out CO2 (and think about it) every time I drive.

    The data below was written with Emacs Orgmode (using it's fantastic spreadsheet capabilities). As I update my local orgfile, I will also update this page as well and make a small announcement on the blog.

    Data Setup

    2020/01/06 gas prices source





































    ModelMPGMPLKPLCapacity kw/lEnergy Consumption / 100km
    Leaf11229.58747.6164016.9
    Note ePower7732.732.736473.06





























    Gas/Liter JPYGas/Gallon JPYGas/Liter USDGas/Gallon USDElectricity Min.Electricity Max
    146.900556.0771.3545.12523.6726.41

    Running Costs


























    ModelJPY / KMFill Up
    Leaf4.00023946.8
    ePower4.495146904.3

    Common Destinations

    Starting location: Home in Yokohama
    Routing done via Apple Maps
    Costs are 1-way. Train is 1-way, per person, using the route I'd probably take.

































    DestinationDistance (km)Leaf (¥)e-Power (¥)Train
    In-laws5.823.20133426.071812242
    Costco1560.0034567.4271609

  • Windows 7 reached its EOL the other day. I think I managed to use it...twice?

  • Planning to buy a car soon (probably an EV). Using Org mode to collect my research and the inline spreadsheet mode makes it suuper easy to make tables with formulas in the appropriate cell all with plain text.

  • Checked in at Yokohama World Porters (横浜ワールドポーターズ)

  • Checkin to Yokohama World Porters (横浜ワールドポーターズ)

    in Yokohama, Kanagawa, Japan
Previous 186 of 359 Next