Laravel: Passing down a parameter in a route prefix/route group

Working through an issue today, I needed to pass a parameter through to sub-routes inside a route group in Laravel. It’s not very well documented, and very powerful.

E.g. a signed in user can have a few apps. App with ID 3, 6, 10 etc.

Anything they do, once they’ve chosen which app they’re working on, should include the app ID in the URL.

Route::group(['prefix'=>'/apps/{id}'],function(){

    Route::get('/test', function($id) {
        echo $id;
    });
});

There it is, nice and easy. the $id parameter from the group will pass down to the individual endpoints. Now we can have URLs like¬†https://www.mydomain.com/apps/5/summary, which is so much nicer and self describing than relying on a session variable for the ‘selected’ app. Now multiple users in the same team can share links with each other, or a user can bookmark pages that are useful to them without losing state.

 

 

Laravel 5: Logging all requests and responses

It’s important when deploying a new platform to monitor the first few interactions and keep an eye out for unintended issues.

Logging requests and responses against the server is a great way to get a birds eye view of the action.

With Laravel 5, this is best done with middleware.

  1. Create a clean git branch to do this work on ūüôā
  2. Create the LogAfterRequest.php middleware file, in App\Http\Middleware\LogAfterRequest.php, and paste the following contents:
    <?php
    namespace App\Http\Middleware;
    
    use Illuminate\Support\Facades\Log;
    class LogAfterRequest {
        public function handle($request, \Closure $next)
        {
            return $next($request);
        }
        public function terminate($request, $response)
        {
          $url=$request->fullUrl();
          $ip=$request->ip();
          $r=new \App\Models\Request();
          $r->ip=$ip;
          $r->url=$url;
          $r->request=json_encode($request->all());
          $r->response=$response;
          $r->save();
        }
    }
  3. Wire up the middleware in App\Http\Kernel.php
    protected $middleware = [
    \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
    \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
    \App\Http\Middleware\LogAfterRequest::class,
    \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    ];
  4. Create a migration to hold the requests/responses in your database, and create a model to pass to the database.
     php artisan make:migration log_requests_responses
     php artisan make:model Models/Request
  5. Add the following structure to the new migrations file in app/database/migrations:
    public function up()
    {
    Schema::create("requests",function(Blueprint $table){
     $table->increments("id");
     $table->text("request");
     $table->text("response");
     $table->string("url", 1024);
     $table->string("ip", 16);
     $table->timestamps();
    });
    }
  6. run php artisan migrate and check that the requests are recording.
  7. Be super careful about this code finding its way to production and for how long.
    There’s a real cost to your page load if storing all of this in your database, and huge security implications to storing whole requests/responses (such as live tokens, passwords).
    Also, you should be aware of XSS implications of storing/retrieving unsanitized inputs (as we are above)
  8. You should make further adjustments to the logging code to scrub tokens and passwords at the very least.

Chrome: Disable Web Security

Pretty often when debugging a mobile app in a web browser, we need to disable access control allow origin, OPTIONS checks, and SSL.

Creating a new Chrome shortcut on the desktop with the following flags will allow you to run Chrome without web security.

Mac:

open -n -a Google\ Chrome --args --disable-web-security --user-data-dir=/Users/[you]/chromedev/

Windows:

"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --user-data-dir="C:/chromedev" --disable-web-security

React Native: Writing a native Android module

It’s difficult to find clear, up-to-date instructions for writing a native Android module for your React Native project.

I spent about half a day piecing this all together from a few sources, so here’s how it ended up.

Prerequisites:

  • React Native is installed and up and running
  • If you used expo, you should have ejected already, and already got the packager up and running again (it’s a little bit of a battle)
  • Android Studio is handy for pointing out syntax errors and code highlighting for .java files.

What will we achieve?

By the end of this article, you’ll have a module written in java that runs native code on your android device and returns the result to your javascript/React Native environment.

You’ll have:

  • A module, which holds the Java class that runs your native functionality.
  • A package, which connects (through code) your module to your React Native code.
  • A javascript connector that you can call easily from your React Native code.

Preparing the module file

Pick a name for your module. This article uses “MyTestModule” for a module name and¬†com.tester.tester_nativemodules for a package name.

Using the above, create a subfolder for your project files under

<project root>/android/app/src/main/java/com/<projectname>/tester_nativemodules/

Create MyTestModule.java inside that folder, and paste the following code.

Note where I’ve bolded the package name, and the module name is italic.

package com.tester.tester_nativemodules;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.NativeModule;

import java.util.Map;
import java.util.HashMap;

public class MyTestModule extends ReactContextBaseJavaModule {
  public MyTestModule(ReactApplicationContext reactContext) {
    super(reactContext);
  }

  @Override
  public String getName() {
    return "MyTestModule"; /* Must match class name above! */
  }

  // Available as NativeModules.MyTestModule.processString
  @ReactMethod
  public void processString(String personName, Callback callback) {
    callback.invoke("Hi there: " + personName);
  }
}

The function in blue is the actual code that will be available from ReactNative. You can make as many of these as you need.

@ReactMethod makes this function available over in React Native land.

You can use any primitive types you need in the method signature, and you can add as many of these methods as you need. Above, we¬†accept a “personName” string and a callback. We’ll pass our function output to callback so it can make it’s way back to React Native land.

Creating the package

The package is a file that exists just to bridge our module with React Native. It’s pretty generic, just make sure to set your package name and module name correctly. I’ve bolded/italicised them again below.

This file is “MyTestPackage.java”, and lives alongside MyTestModule.java in¬†<project root>/android/app/src/main/java/com/<projectname>/tester_nativemodules/

package com.tester.tester_nativemodules;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class MyTestPackage implements ReactPackage {

    @Override
    public List createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }

    @Override
    public List createNativeModules(
            ReactApplicationContext reactContext) {
        List modules = new ArrayList<>();

        modules.add(new MyTestModule(reactContext));

        return modules;
    }

}

Link it to the Android Packages list

The last step on java side is telling the android project your package exists. Open up  <project root>/android/app/src/main/java/com/<projectname>/MainApplication.java and add your package name to the list of available packages. It should look something like this:

     protected List getPackages() {
       return Arrays.asList(
           new MainReactPackage(),
           new SvgPackage(),
           new MyTestPackage() /* The name of your package class above */
       );
     }

Using the package in javascript

The new package is available at NativeModules.MyTestModule.

Add an import at the top of your JS file,

import {NativeModules} from 'react-native';

and then you can call the processString function inside your JS file like this:

NativeModules.MyTestModule.processString("Rhys", function (response) {
  console.log(response); //Will log out "Hi there: Rhys"
})

All done

That’s all there is to adding native code to a React Native project. Adding something trivial like above ensures you have all the nuts and bolts in place before adding more complicated functionality.

React Native – using Flow

I’m backporting Flow into a large React Native project of mine. It’s unclear sometimes how to do things ‘the right way’ with Flow.

This is what’s working so far:

  • Any type that is used across multiple components should exist in it’s own JS file, and be imported as a type. Here’s how that looks in the component (e.g. follow the Order type from import. We expect to store an array of Order in this.state.orders.
  • Occasionally, rigorously defining¬†a type just isn’t¬†worth stuffing around with. For example, the navigation object passed around with react-navigation (via this.props.navigation. etc).
    I receive no real benefit from having this correctly typed. It’s not increasing visibility of my code or re-use, it’s not cleaning up bugs. After a quick google showed it’d be a battle, I settled that props.navigation is going to be of type¬†any. *This is the only case of this. I might circle back and fix it later* 

    Here’s what that little cheat looks like:

    I should emphasise again, if you find yourself doing this often, you’re missing the point.

  • Passing functions in as props is a common pattern in React. Strongly typing these will quickly shrink your surface area for bugs (It’s amazing the bugs you find when backporting Flow into an existing project :D)

WooCommerce: To perform the requested action, WordPress needs to access your web server

Seeing this error? “WooCommerce: To perform the requested action, WordPress needs to access your web server”

This permissions issue haunts me after every new WordPress install. There’s a one-liner fix that doesn’t involve 777’ing your whole server.

 

Here’s the magic cure:

  1. Open wp-config.php
  2. Add
    define( 'FS_METHOD', 'direct' );

    at the end

  3. Save and close, install plugins!

Thanks to https://wordpress.stackexchange.com/questions/228591/to-perform-the-requested-action-wordpress-needs-to-access-your-web-server-pleas

GuzzleClientException truncated

By default, a Guzzle error thrown in Laravel will truncate the response body. When you’re deep in an API integration, this is a productivity killer.

Here’s an easy way to error log the full response body from the API.

try {

$response = $client->request( "POST", $this::$resource, [ 'json' => $item ] );

$body = json_decode( $response->getBody()->getContents() );

return $body;
} catch ( \GuzzleHttp\Exception\ClientException $e) {
// here's the good stuff
Log::error($e->getResponse()->getBody()->getContents());
throw $e;

}

Code Workshop is locking in ReactJS.

There’s a common complaint among the javascript ecosystem, from new developers and seasoned developers alike. We’re all exhausted from learning, building with, and then maintaining the new hot framework of the day. Below, we’ve detailed how we decided to lock in ReactJS.

New JS Frameworks.. We're locking in ReactJS.
From https://www.exceptionnotfound.net/wait-pick-learn-ignore-dealing-with-javascript-framework-fatigue/

Who are we?

I’m Rhys Williams. I run Code Workshop, a Sydney app development company. We’re small sized – I run the business by myself from day to day and do the lion’s share of development and client relations. We’ve got tight relationships with a tiny army of Sydney based contractors who look after our UI/UX, WordPress development and QA process.

We take on 2-3 decent sized client projects per year which are either completely written in javascript or some sprinkling on an otherwise laravel back-end application. In the last 5 years, this has been jQuery, AngularJS, VueJS, and most recently ReactJS.

For mobile app development we’ve had similar framework churn to follow the times. Some jQuery, PhoneGap, Ionic, and recently ReactNative.

We’re locking in ReactJS and React Native until 2023.

Now, in 2018, we’re¬†making a call. JS framework churn is over. The toolset has matured and ReactJS won. The toolchain is still evolving (somewhat frustratingly.. Like removing propTypes) but for the next 5 years¬†all of our client side development will be ReactJS/React Native.

We’ve worked on successful ReactJS projects for our eCommerce and traditional business clients in the last 12 months. Supporting the apps is easy, maintaining them is easy, and working on old code is easy.

ReactJS and React Native are well supported and actively developed by huge communities. I suspect it’s a breath of fresh air for developers who’ve followed the same path of us through jQuery, Angular, and a few minor players along the way.

Who uses React Native or ReactJS?

I had a chat with a client last week about who uses React Native, and I was shocked to see just how big the ecosystem has really become.

It’s important to know that some big names use a platform because it means they’re solving huge problems with it successfully. Experimental, toy technologies will often fall to pieces quickly when you use them in anger.

Big apps/projects build using React Native:

Apps using ReactNative

Big websites using ReactJS:

yeah, Netflix uses ReactJS.

This is a much bigger list – ReactJS has been around a few years longer than React Native and has reached something of a saturation point. Here’s a few notable standouts:

  • Yahoo
  • Atlassian
  • KhanAcademy
  • NetFlix
  • New York Times
  • WhatsApp
  • Tesla
  • Visa
  • Spotify
  • Dropbox

Why is it cheaper to build with ReactJS?

Popular frameworks spin out enormously useful and technically amazing resources for developers. React is an open source ecosystem by default, so most of the huge companies listed above also give back to the community.

This typically means large pieces of ReactJS custom code we would otherwise need to write for your app project are written, debugged, QA tested, already in production and open sourced for us to use on your project.

It also means there’s a wealth of technical knowledge and know-how for nearly any problem in the mobile app/web app space. Need a mapping library? Here’s a good one. Images won’t cache properly? Here’s why. There’s a new iOS release? Here’s the permissions updates. The depth of knowledge means problems are solved faster and we’re back to the app build quicker.

React Native is A LOT cheaper.

On the native front, React Native does away with two teams and replaces it with one. It wasn’t so long ago you needed native Android developers and native iOS developers to bring your app to market (unless you used Phonegap, shudder). We develop your app once in React Native. Only building and physical testing is carried out on the two types of devices, which speeds up development time significantly.

React Native also benefits from Expo, a free and open source toolchain to bring your app to market cheaper. Common functionality that is useful for any app development (push notifications, automated build toolchain, filesystem access, social authentication, location awareness, live debugging, sending apps to external parties) is provided out of the box with Expo. Again, this ensures we’re not charging clients to build the same functionality over and over! It’s commoditized code that we don’t need to re-write.

Expo for cross platform native apps

It’d be dishonest to pretend the codebase is 100% out of the box the same between the two platforms with no effort. However, in a recent app build we finished, the code lives in a single repository and differences are handled inline in the code. The future is here, your iOS and Android app can live in one code base. And… it works fine.

The App Store and Google Play both accept React Native apps without a problem, requiring only the typical reviews any app needs.

Talk to us about ReactJS and React Native

We’re locking our business into the React ecosystem for new projects for the next 5 years.

Support and ongoing maintenance are an important part of our business and client relationships, so it’s important to vocally commit and make it clear we’ll be around to support React based projects well into the future.

If you’ve got an app or website project coming up, let us know. We¬†can help you put together a budget, spec out the project, and dive in and build the project when you’re ready. Most importantly, down the track we’ll be around to help with ongoing support, maintenance, and¬†keeping your app or site fresh with the times.