Category Archives: RSS Feed

Node.js Weekly Update - 18 August

By Gergely Németh

Node.js Weekly Update - 18 August

Below you can find RisingStack‘s collection of the most important Node.js updates, projects & tutorials from this week:

Node v8.4.0 (Current) Released

Notable changes:

  • HTTP2:
    • Experimental support for the built-in http2 has been added via the –expose-http2 flag.
  • Inspector:
    • require() is available in the inspector console now.
    • Multiple contexts, as created by the vm module, are supported now.
  • N-API
    • New APIs for creating number values have been introduced. #14573
  • Stream
    • For Duplex streams, the high water mark option can now be set independently for the readable and the writable side.
  • Util
    • util.format now supports the %o and %O specifiers for printing objects.

Building an API Gateway using Node.js

Learn what are the benefits and best practices of API Gateways for microservices, and how you can start building yours using Node.js.

Node.js Weekly Update - 18 August

Services in a microservices architecture share some common requirements regarding authentication and transportation when they need to be accessible by external clients. API Gateways provide a shared layer to handle differences between service protocols and fulfills the requirements of specific clients like desktop browsers, mobile devices, and legacy systems.

Node pdf-bot

A Node queue API for generating PDFs using headless Chrome. Comes with a CLI, S3 storage and webhooks for notifying subscribers about generated PDFs

Node.js Weekly Update - 18 August

pdf-bot is installed on a server and will receive URLs to turn into PDFs through its API or CLI. pdf-bot will manage a queue of PDF jobs. Once a PDF job has run it will notify you using a webhook so you can fetch the API. pdf-bot supports storing PDFs on S3 out of the box. Failed PDF generations and Webhook pings will be retryed after a configurable decaying schedule.

ES Modules in Node Today!

This fast, small, zero dependency package is all you need to enable ES modules in Node 4+ today.

Node.js Weekly Update - 18 August

I’m excited to announce the release of @std/esm (standard/esm), an opt-in, spec-compliant, ECMAScript (ES) module loader that enables a smooth transition between Node and ES module formats with near built-in performance!

Node.js Config Best-Practices

This article talks about the DOs and DON’Ts of Node config handling.

When building any kind of server side app, you will eventually have the following thoughts:

  • I would like to bind my app to a specific port.
  • I would like to enter a connection string so I can connect to my database.
  • I would like to use a third-party service through a provided API key or credentials.

Puppeteer – A Headless Chrome Node API

Puppeteer is a Node library which provides a high-level API to control headless Chrome over the DevTools Protocol. It can also be configured to use full (non-headless) Chrome.

What can it do?

Most things that you can do manually in the browser can be done using Puppeteer! Here are a few examples to get you started:

  • Generate screenshots and PDFs of pages.
  • Crawl a SPA and generate pre-rendered content (i.e. “SSR”).
  • Scrape content from websites.
  • Automate form submission, UI testing, keyboard input, etc.
  • Create an up-to-date, automated testing environment. Run your tests directly in the latest version of Chrome using the latest JavaScript and browser features.
  • Capture a timeline trace of your site to help diagnose performance issues.

Async/Await will Make Your Code Simpler

With the rise of single-page javascript web apps and the widening adoption of Node.js, handling concurrency gracefully is more important than ever for Javascript developers.

Async/await alleviates many of the bug-inducing control-flow issues that have plagued Javascript codebases for decades and is pretty much guaranteed to make any async code block significantly shorter, simpler, and more self-evident.

About that hash flooding vulnerability in Node.js…

Early July this year, Node.js released a security update for all currently maintained branches to address a hash flooding vulnerability. This intermediate fix comes at the cost of a significant startup performance regression. In the meantime, V8 has implemented a solution which avoids the performance penalty.

In this post, we want to give some background and history on the vulnerability and the eventual solution.

Previously in the Node.js Weekly Update

In the previous Node.js Weekly Update we read about HTTP/2 for Node.js Core, the Constant HashTable Seeds Vulnerability, Cars.com’s adoption story, and so much more..

We help you to stay up-to-date with Node.js on a daily basis too. Check out our Node.js news page and its Twitter feed!

Source:: risingstack.com

Company offsite in Spain 2017

At thoughtram we are pretty much a fully distributed team. While some of us live in the same city, the bulk of the team is spread across the entire planet. With such a setting, spending some time together in a pleasant environment naturally comes as a welcoming change from the daily routine. This is why we sat out to bring the entire team with their partners to Spain for two weeks of fun, learning and getting some work done. Unfortunately, Thomas was unable to attend the offsite in Spain. He was needed in the USA to take care of his wife who was having knee surgery.

Machine Learning Summer School

The first stop for us was the Machine Learning Summer School in Bilbao.This event came along with perfect timing, because we just started a new journey with a company called “MachineLabs” which aims to make the entire Machine Learning field explorable, shareable and accessible to everyone. There were five days of talks about machine learning issues like “Deep learning in the brain” or “Applications of Deep Learning models in human computer interaction research”. It turned out that some talks were quite difficult to follow, mainly because they were theory-driven with very little hands-on experience. However, others were a bit easier to grasp. One talk about how the human brain works and how deep learning relates to functions of the brain, was discussed in a way that the audience could easily connect the dots. We had a super intense time at this summer school and got a lot of new input. These days in Bilbao enabled us to dive deeper into the world of machine learning, which was awesome!

One of the conference rooms with a huge organ.


We loved our super comfy airbnb in Bilbao.

Bilbao itself is a really nice city with an old town centre. In this ancient centre was our amazing airbnb.

After spending some interesting days with lots of input on machine learning in Bilbao, we travelled to Sitges, about 40 km from Barcelona at the seaside.

Hacking on MachineLabs

Our new founded entity is called “MachineLabs, Inc.”. MachineLabs is a platform which could probably be best described as the CodePen for Machine Learning, you can find the announcement here. We announced it and its mission a few weeks ago. As mentioned earlier, MachineLabs tries to solve the problem of lowering the barrier to enter the Machine Learning field. While we were in Bilbao and Sitges, we had enough time to talk about common goals with MachineLabs, find solutions and organize all the legal stuff as well. As we have been all together for two weeks, the time was perfect to collaborate on code and discuss the legal background.

Enjoying life together

On some of the hot days, we went to the seaside and just loved to refresh every now and then in the cold water and feel this chilly sea breeze. As the beaches in Sitges were pretty crowded, we chose some closeby but much more lonelier beachside.

We also explored the area around Sitges with racing bikes. We rent those from a really friendly Cuban guy in the city. He recommended a tour through the backyard over 50 kilometers which we really enjoyed, although, it was quite tough sometimes. However, the views were amazing, we passed a pretty castle, some lakes, fields full of melons and pears, horses and cows and great green fields. For lunch we got some huge ice cream and other sweet food, cold drinks, shade and just enjoyed to take some time off and relax.


The hardest part was a hill that we went up in the lowest gear while the sun was nearly burning our bodies!

Our Airbnb in Sitges had an awesome rooftop terrace. We had a great BBQ there during the sunset. We also had some super funny moments during the BBQ, probably the best was with Dominic having a laugh attack with tears in his eyes – unforgettable!

The other evenings we mostly checked out some closeby restaurants and tried Pintxos (Tapas), seafood and other delicious food, or cooked something nice for everyone. We talked a lot about our lives, our common goals for thoughtram, the next milestones with MachineLabs and more.


We loved the rooftop terrace a lot, every morning we’ve had breakfast there, felt the sun and the happiness of being there.

As Barcelona is not too far away from Sitges, we went there for our last day by car and explored the area. We saw the Sagrada Familia, ate great food, visited the old city centre, grabbed some fantastic ice-cream and enjoyed the Spanish sun for our last hours…

Wrapping up

We were happy to spend this time together, to get to know each other a bit better, to explore the area and to work on current topics and collaborate on them – all in all: to share some special memories! It was a great mixture of fun and of course, good food, hard work and great solutions, doing sports like jogging and trying to follow these pretty hard talks about machine learning topics. Definitely a must for the next year – hopefully with all team members! 🙂

Source:: Thoughtram

Repatch - the simplified Redux

By Péter Hauszknecht

Repatch - the simplified Redux

I’ve been involved in reactredux projects for several years. After I first met with flux, I was impressed by its expressive power that describes complicated use cases in contrast to other dataflow concepts, which caused many troubles when the complexity of a project increased.

The action controlled dataflow concept is simple and clear. Data changes can be described as actions with a minimal payload. These actions make a deterministic, time-independent history of the application’s life. The application’s state at a given point is reducible by picking an action in the chain.

The concept of Redux has many theoretical principles and advantages, but I do not intend to talk about them. There is only one major disadvantage of immutability: the cost of it. But the price we must pay for immutable data handling is multiple refunded by avoiding re-renders and reflows in React applications. We can always keep track of the difference between two consecutive states, and that is something why I cannot list immutability as a disadvantage of Redux.

Motivation

Redux has one more disadvantage: it is painfully verbose.

Let’s suppose we want to create an async action, which fetches users and saves them in a Redux store instance. We need 3 action definitions:

const START_FETCHING_USERS = "START_FETCHING_USERS";  
const RESOLVE_FETCHING_USERS = "RESOLVE_FETCHING_USERS";  
const REJECT_FETCHING_USERS = "REJECT_FETCHING_USERS";  

The first action type START_FETCHING_USERS starts the process,RESOLVE_FETCHING_USERS provides the new set of users, and REJECT_FETCHING_USERS is emitted if there is an error during fetching.

Let’s see the action creators:

const startFetchingUsers = () => ({ type: START_FETCHING_USERS });  
const resolveFetchingUsers = users => ({ type: RESOLVE_FETCHING_USERS, users });  
const rejectFetchingUsers = error => ({ type: RESOLVE_FETCHING_USERS, error });  

and the reducer:

const initState = {  
 isFetching: false,
 users: [],
 error: null
}

const reducer = (state = initState, action) => {  
 switch (action.type) {
   case START_FETCHING_USERS: return {
     ...state,
     isFetching: true
   };
   case RESOLVE_FETCHING_USERS: return {
     ...state,
     isFetching: false,
     users: action.users
   };
   case REJECT_FETCHING_USERS: return {
     ...state,
     isFetching: false,
     error: action.error
   };
   default: return state;
 }
}

All that remains is to implement the async thunk action creator:

const fetchUsers = () => async (dispatch, getState, { api }) => {  
 dispatch(startFetchingUsers());
 try {
   const users = await api.get('/users');
   dispatch(resolveFetchingUsers(users));
 } catch (error) {
   dispatch(rejectFetchingUsers(error.message));
 }
}

Okay, we finished the Redux parts & we’re almost done. Now we just need to connect the action creators and the state to the React component, and we are good to go!

For this simple feature, we needed to type a lot of lines for

  • action types,
  • action creators,
  • action handlers in the reducer,

and we have not written any view components yet.

This is especially inconvenient when we are involved in developing a large application with thousands of action types, action creators, and sub-reducers. It causes further difficulties too, because these resources are separated in many files, in different places. So if we want to trace the effect of an action, we have to follow the flow of data across many files, which makes it easy to get lost.

By looking around in npm, we are most likely to find a bunch of libraries/helpers/middlewares, which help us to avoid typing, but using them introduces some other type of typing overhead as we need to import them in every file.

Maybe we should think of a simpler way and consider which features we really need from Redux.

1) Do we have to keep the data immutable? Mutability is the highway to hell. So this is not a solution. Especially not in React applications.

2) Do we have to know the name of an action? In most cases, the actions are used only in single place. We do not need to keep them reproducible. What if you have a way to dispatch anonymous actions? This would be great.

3) Do we have to be able to serialize the actions? There are use cases where you absolutely need to be serializable, but in most applications, you do not. So let’s continue with the assumption that this is not a requirement for now.

We should adhere to the first restriction, while we can safely forget the others.

We should transform the Redux concepts to make it possible that we can create actions briefly. We want to describe an action as a single function, either in place.

Repatch

Repatch drops action types and action creators from the definition set, and answers the question: “What if reducers were the payload of the actions?”. The creed of this library is:

DISPATCH REDUCERS

store.dispatch(state => ({ ...state, counter: state.counter + 1 }));  

In this terminology, an action is a function that returns a reducer:

const increment = amount => state => ({  
  ...state,
  counter: state.counter + amount
});

store.dispatch(increment(42));  

Repatch also has a Store class that we can instantiate with the initial state:

import Store from 'repatch';

const store = new Store(initialState);  

Repatch’s interface is very similar as redux‘s, therefore we can use it with the react-redux library. The dispatch and subscribe methods have the same signature as in the Redux’s Store.

Middlewares and Async Actions

Repatch also has an interface for chaining middlewares. This is convenient for using your favorite async-action middleware. The package provides a thunk middleware – similar to redux-thunk – which is useful for creating async actions. If your reducer returns a function, it will be automatically considered an async action by the middleware. The dispatch and getState functions will be passed as arguments to it by the store instance. You can set up the middleware to provide one extra argument to. You can use that, for example to inject your client API library.

Let’s see the example related to our use-case below:

const fetchUsers = () => _ => async (dispatch, getState, { api }) => {  
 dispatch(state => ({ ...state, isFetching: true }));
 try {
   const users = await api.get('/users');
   dispatch(state => ({ ...state, users }));
 } catch (error) {
   dispatch(state => ({ ...state, error: error.message }));
 } finally {
   dispatch(state => ({ ...state, isFetching: false }))
 }
}

Using this thunk middleware shows the real power of repatch as we can describe async actions in only a few lines of code. As you can see, we did not need to define verbose action types, action creators and action handlers in the reducer, as we could simply dispatch an arrow function defined in place, thus creating an anonymous action. How cool is that? This makes it possible that actions either can also be created from a component.

All that remains is the Store instantiation with the initial state:

const store = new Store({  
 isFetching: false,
 users: [],
 error: null
});

and somewhere dispatching the action:

store.dispatch(fetchUsers())  

Let’s see an other example:

const updateUser = delta => state => async (dispatch, getState, { api }) => {  
 try {
   const editedUserId = getState().editedUser;
   dispatch(toggleSpinner(true));
   await api.put(`/users/${editedUserId}`, { body: delta });
   await dispatch(fetchUsers());
   dispatch(toggleSpinner(false));
 } catch (error) {
   dispatch(state => ({ ...state, isFetching: false, error: error.message }));
 }
};

You can see from the function signature that in this example the extra argument is our client API object, as I mentioned previously. Also, note that the reducer’s state argument is not always satisfactory for reading the state because it is a momentary representation from the time when the action was fired. Therefore we need to use the getState function instead of state.

In this example, toggleSpinner is a regular synchronous action that we can dispatch. The api.put method is a simple async method to call the API, there is no obstacle in the way of awaiting for it. The line await dispatch(fetchUsers()) is a bit more interesting. Using redux-thunk we got used to embedding async actions within each other and waiting for them.

Sub-reducers

Sub-reducers in Redux

Redux’s reducers are composable to form a hierarchical structure. This way we do not need to define one giant reducer, instead, we can separate them to smaller nested reducers. Combining reducers is not magic, we just create a reducer that reduces the parts one by one to an object using their sub-state.

const rootReducer = (state, action) => ({  
 foo: fooReducer(state.foo, action),
 bar: barReducer(state.bar, action)
});

is equivalent to

const rootReducer = redux.combineReducers({  
  foo: fooReducer,
  bar: barReducer
});

Sub-reducers in Repatch

Repatch also offers a way to combine sub-reducers. We just define a function that takes a nested reducer as argument, and returns a reducer that reduces the whole state:

const reduceFoo = fooReducer => state => ({  
 ...state,
 foo: fooReducer(state.foo)
});

Now reducing the foo property is easy. Let’s suppose we would like to set an x property in the foo object:

const setX = x => reduceFoo(state => ({ ...state, x }));  

It will be really useful if the sub-reducer describes a deeply nested property:

const reduceFoo = reducer => state => ({  
  ...state,
  bar: {
    ...state.bar,
    foo: reducer(state.bar.foo)
  }
});

Testing

How about testing? Writing unit tests for a reducer is simple:

import * as assert from 'assert';  
import { changeName } from './actions';

// ...

it('changeName', () => {  
 const state = { name: 'john' };
 const nextState = changeName('jack')(state);
 assert.strictEqual(nextState.name, 'jack');
});

Async actions are a bit more complicated because they take effect by depending on external resources such as the store instance and other APIs. But external resources always need to be mocked in all environments.

import Store, { thunk } from 'repatch';  
import * as assert from 'assert';

const mockUsers = [{ username: 'john' }];  
const mockApi = {  
 getUsers: () => Promise.resolve(mockUsers)
}

// ...

it('fetchUsers', async () => {  
 const state = { users: [] };
 const store = new Store(state)
   .addMiddleware(thunk.withExtraArgument({ api: mockApi }));
 await store.dispatch(fetchUsers());
 const nextState = store.getState();
 assert.deepEqual(nextState.users, mockUsers);
});

The TODO app

Every javascript library has a todo example, so repatch has one too. If you are looking for the TypeScript example, you can find it here.

Source:: risingstack.com

Build a Secure Notes Application with Kotlin, TypeScript, and Okta

By Matt Raible

OAuth 2.0 Actors

I love my job as a developer advocate at Okta. I get to learn a lot, write interesting blog posts and create example apps with cool technologies like Kotlin, TypeScript, Spring Boot, and Angular, which I’m about to demo. When it comes to writing Hello World apps with authentication, I can whip one out in a few minutes. That isn’t because I’m a particularly good programmer, it’s because the languages, frameworks, tools, and platforms available to developers are impressive.

In this tutorial, I’ll show you how to write a note-taking application in Kotlin and TypeScript – two of the fastest growing languages of 2017. You’ll use two popular frameworks, Spring Boot and Angular, to make development super fast. Along the way, I’ll show you a few tips and tricks from my favorite development IDE, IntelliJ IDEA. Finally, we’ll leverage Angular CLI and start.spring.io to generate application skeletons.

As with any good example app, you’ll want to deploy it securely, so I’ll show you how to do that using Okta’s Identity APIs and our new Spring Boot starter. The Okta Spring Boot starter allows you to make your API into a resource server that can read and validate access tokens sent to it. The diagram below shows how a resource server fits into an OAuth architecture.

Phew! That’s a lot of buzzwords for one article. Don’t worry, I’ve confirmed it’s possible to develop this app in even less time than it takes to deploy and secure it. And developing is fun, so let’s get started!

Build a Notes API with Kotlin and Spring Boot

Start building the API for your application by navigating your favorite browser to start.spring.io. Select Kotlin as your language, and choose Web, H2, JPA, Rest Repositories, and DevTools. You’ll notice in the screenshot below that I changed the group and artifact names too. Please use these same names, so your package and class names match this tutorial.

start.spring.io

Click Generate Project and expand the zip file after downloading. If you don’t have IntelliJ IDEA installed, now’s a good time to try it out. It’s a great IDE for Java, Kotlin, Groovy, TypeScript, JavaScript, HTML, and Sass/CSS. One of its killer features is the ability to copy/paste Java code into a Kotlin class and have it auto-converted to Kotlin on-the-fly!

You can also turn on automatic-compilation-on-save and reap the benefits of Spring Boot’s DevTools that restart your app when files change.

  • Go to Preferences > Build, Execution, Deployment > Compiler and enable “Build project automatically”
  • Open the Action window:
    • Linux: CTRL+SHIFT+A
    • Mac: SHIFT+COMMAND+A
    • Windows: CTRL+ALT+SHIFT+/
  • Enter Registry… and enable compiler.automake.allow.when.app.running

Start by creating a new Note entity in src/main/kotlin/com/okta/developer/notes/NotesApplication.kt.

@SpringBootApplication
class NotesApplication

fun main(args: Array<String>) {
    SpringApplication.run(NotesApplication::class.java, *args)
}

@Entity
data class Note(@Id @GeneratedValue var id: Long? = null,
                var text: String? = null, var user: String? = null)

Kotlin’s data classes are built to hold data. By adding the data keyword, your class will get equals(), hashCode(), toString(), and a copy() function. The Type? = null syntax means the arguments are nullable when creating a new instance of the class.

Create a NotesRepository for persisting the data in your notes. Add the following lines of code just below your Note entity.

@RepositoryRestResource
interface NotesRepository : JpaRepository<Note, Long>

The extends syntax differs from Java and is a lot more concise (a colon instead of extends).

Create a DataInitializer bean that populates the database with some default data on startup.

@Component
class DataInitializer(val repository: NotesRepository) : ApplicationRunner {

    @Throws(Exception::class)
    override fun run(args: ApplicationArguments) {
        listOf("Note 1", "Note 2", "Note 3").forEach {
            repository.save(Note(text = it, user = "user"))
        }
        repository.findAll().forEach { println(it) }
    }
}

This example shows constructor injection, but Kotlin also supports field injection with @Autowired.

Start the app in your IDE using its Spring Boot tooling, or from the command line using mvnw spring-boot:run. If you’re on a Mac or Linux, you might need to use ./mvnw spring-boot:run.

You should see the following printed to your console on startup.

Note(id=1, text=Note 1, user=user)
Note(id=2, text=Note 2, user=user)
Note(id=3, text=Note 3, user=user)

I recommend installing HTTPie, a command-line HTTP client that is much easier to use than curl. Use HTTPie to query the /notes endpoint provided by Spring Data REST’s @RepositoryRestResource.

http localhost:8080/notes

The result will look like the following screenshot.

http request screenshot

Create a HomeController (in the same NotesApplication.kt file) and use it to filter notes by the currently logged-in user.

import java.security.Principal

@RestController
class HomeController(val repository: NotesRepository) {

    @GetMapping("/")
    fun home(principal: Principal): List<Note> {
        println("Fetching notes for user: ${principal.name}")
        val notes = repository.findAllByUser(principal.name)
        if (notes.isEmpty()) {
            return listOf()
        } else {
            return notes
        }
    }
}

The findAllByUser() method doesn’t exist on NotesRepository, so you’ll need to add it. Thanks to Spring Data JPA, all you need to do is add the method definition to the interface, and it will handle generating the finder method in the implementation.

interface NotesRepository : JpaRepository<Note, Long> {
    fun findAllByUser(name: String): List<Note>
}

If you try to access this new endpoint, you’ll get an error that the Principal parameter is not defined.

$ http localhost:8080
HTTP/1.1 500
Connection: close
Content-Type: application/json;charset=UTF-8
Date: Fri, 11 Aug 2017 07:36:46 GMT
Transfer-Encoding: chunked
{
    "error": "Internal Server Error",
    "exception": "java.lang.IllegalArgumentException",
    "message": "Parameter specified as non-null is null: method 
                com.okta.developer.notes.HomeController.home, parameter principal",
    "path": "/",
    "status": 500,
    "timestamp": 1502437006005
}

Spring MVC throws a 500 error because it has no knowledge of a logged-in user. Add the Spring Security starter to your pom.xml to enable security in your application.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Restart the Maven process to download this new dependency and add it to the classpath.

If you navigate to http://localhost:8080 in your browser, you will see a basic authentication dialog. The command line will yield similar results.

{
    "error": "Unauthorized",
    "message": "Full authentication is required to access this resource",
    "path": "/",
    "status": 401,
    "timestamp": 1502437281185
}

The Spring Security starter creates a default user with username “user” and a password that changes every time you start the application. You can find this password in your terminal, similar to the one below.

Using default security password: 103c55b4-2760-4830-9bca-a06a87d384f9

Change the user’s password so it’s the same every time by adding the following to src/main/resources/application.properties.

security.user.password=kotlin is fun!

After the change, verify that this HTTPie command works.

$ http --auth user:'kotlin is fun!' localhost:8080
HTTP/1.1 200
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: application/json;charset=UTF-8
Date: Fri, 11 Aug 2017 07:47:10 GMT
Expires: 0
Pragma: no-cache
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
Transfer-Encoding: chunked
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
[
    {
        "id": 1,
        "text": "Note 1"
    },
    {
        "id": 2,
        "text": "Note 2"
    },
    {
        "id": 3,
        "text": "Note 3"
    }
]

The reason you don’t see the user property in the JSON above is because I added a @JsonIgnore annotation to the Note class.

import com.fasterxml.jackson.annotation.JsonIgnore

@Entity
data class Note(@Id @GeneratedValue var id: Long? = null,
                var text: String? = null,
                @JsonIgnore var user: String? = null)

To automatically add the username to a note when it’s created, add a RepositoryEventHandler that is invoked before creating the record.

@Component
@RepositoryEventHandler(Note::class)
class AddUserToNote {

    @HandleBeforeCreate
    fun handleCreate(note: Note) {
        val username: String =  SecurityContextHolder.getContext().getAuthentication().name
        println("Creating note: $note with user: $username")
        note.user = username
    }
}

After adding the handler, saving your files, and waiting for your API to restart, you’ll be able to run the following commands with wild success.

http --auth user:'kotlin is fun!' POST localhost:8080/notes text='Note 4'
http --auth user:'kotlin is fun!' PUT localhost:8080/notes/4 text='Remember the Milk!'
http --auth user:'kotlin is fun!' DELETE localhost:8080/notes/4

Your API works and is locked down, but you still only have one user. Rather than spending time setting up database tables and encrypting passwords, you can use Okta’s APIs to manage, authenticate, and authorize your users securely. To get started with Okta, sign up for a free-forever developer account.

The Okta Spring Boot Starter

Okta provides a Spring Boot starter that integrates with Spring Security and its OAuth 2.0 support. Replace the Spring Security starter with the Okta Spring Security starter.

<dependency>
      <groupId>com.okta.spring</groupId>
      <artifactId>okta-spring-security-starter</artifactId>
      <version>0.1.0</version>
</dependency>    

You’ll also need to upgrade the OAuth library used by Spring Security to the latest version.

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.2.0.RELEASE</version>
        </dependency>
    </dependencies>
</dependencyManagement>

After modifying your pom.xml, configure it with your Okta settings.

Add an Authorization Server

Log in to your Okta account and click the Admin button in the top right. Navigate to Security > API in the top menu and click on the Add Authorization Server button. Use a name and audience that works for you. For example, I chose:

  • Name: My AS
  • Audience: people-of-earth

My AS

Copy and paste the Issuer URL and audience values into application.properties:

okta.oauth.issuer={issuer}
okta.oauth.audience={audience}

The Okta Spring Security starter expects you to have a custom claim called groups. Define a custom claim with these values:

  • Name: groups
  • Value Type: Groups
  • Filter: Regex.*

You’ll also need to add a new Access Policy and Rule that gives everyone access. Of course, you can lock these down if you want to, but it’s best to use the defaults for this tutorial.

Finally, navigate to Security > API > Trusted Origins and add http://localhost:4200 as an Origin URL with CORS support.

Add an OpenID Connect Application

Navigate to Applications and click on Add Applications > Create New App. Select Single Page App (SPA) using OpenID Connect and click Create. Give the application a name (e.g. “My OIDC App”) and specify http://localhost:4200 as a Login redirect URI. Your upcoming Angular client will use this value. Click Save and admire your handiwork!

My OIDC App

Click on the Assignments tab and click Assign. Assign the “Everyone” group and click Done.

Copy the Client ID value into application.properties.

okta.oauth.clientId={client-id}

Before you start building the Angular client, add a CORS filter to NotesApplication so cross-origin requests can succeed.

class NotesApplication {

    @Bean
    open fun simpleCorsFilter(): FilterRegistrationBean {
        val source = UrlBasedCorsConfigurationSource()
        val config = CorsConfiguration()
        config.allowCredentials = true
        config.allowedOrigins = listOf("http://localhost:4200")
        config.allowedMethods = listOf("*");
        config.allowedHeaders = listOf("*")
        source.registerCorsConfiguration("/**", config)
        val bean = FilterRegistrationBean(CorsFilter(source))
        bean.order = Ordered.HIGHEST_PRECEDENCE
        return bean
    }
}

fun main(args: Array<String>) {
    SpringApplication.run(NotesApplication::class.java, *args)
}
…

You can see the final version of this file on GitHub.

I hope you’ve enjoyed this quick tour of Kotlin and saw how its concise syntax can be a lot of fun. In May 2017, Kotlin was announced as an officially supported language on Android, giving the language quite a bit of attention. You can learn more about Kotlin on kotlinlang.org.

Build an Angular UI with TypeScript and Angular CLI

Angular CLI is a convenient way to create Angular applications. It generates a project skeleton, installs all the dependencies, and configures Webpack to compile TypeScript and optimize for production.

Install Angular CLI using Facebook’s Yarn.

yarn add global @angular/cli

Or using npm (npm install -g @angular/cli).

Then create a new project using its ng command.

ng new client

It takes a minute or two to install all the dependencies. After it finishes, you can run ng serve to view the app, or ng test to run unit tests. If you want to verify that the end-to-end tests pass, run ng e2e.

Create a service and component using the generate (alias: g) command. You can use s as an alias for service and c as an alias for component.

ng g service note
ng g component note-list
ng g c note-detail
ng g c login

The service files are generated in client/src/app by default, but I like to move them into a shared/{service} directory.

mkdir -p src/app/shared/note
mv src/app/note.service.* src/app/shared/note

At this point, I’d recommend opening your Angular client in IntelliJ IDEA. It has excellent TypeScript support and will auto-import classes for you, just like it does for Java and Kotlin.

Add the NoteService to the providers list in client/src/app/app.module.ts. Notice that Angular CLI has already added the generated components to the declarations list.

@NgModule({
  declarations: [
    AppComponent,
    NoteListComponent,
    NoteDetailComponent,
    LoginComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [NoteService],
  bootstrap: [AppComponent]
})
export class AppModule {
}

Modify client/src/app/shared/note/note.service.ts to have a getAll() method that talks to the API.

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class NoteService {
  public API = 'http://localhost:8080';
  public NOTE_API = this.API + '/notes';

  constructor(private http: HttpClient) {
  }

  getAll(): Observable<any> {
    return this.http.get(this.API);
  }
}

TIP: If you’re using IntelliJ IDEA, I recommend you install the Angular 2 TypeScript Live Templates. They drastically reduce the amount of code you have to write with several code-generation shortcuts.

In client/src/app/notes-list/note-list.component.ts, add a dependency on NoteService and get all the user’s notes when the component loads.

import { NoteService } from '../shared/note/note.service';

export class NoteListComponent implements OnInit {
  notes: Array<any>;

  constructor(private noteService: NoteService) {
  }

  ngOnInit() {
    this.noteService.getAll().subscribe(data => {
      this.notes = data;
    }, error => console.error(error));
  }
}

Replace the HTML in client/src/app/note-list/note-list.component.html with a few lines to render the notes list.

<h2>Notes List</h2>
<div *ngFor="let note of notes">
  {{note.text}}
</div>

If you try to make things work at this point, you won’t be able to access your API because it expects you to send an access token in an Authorization header.

Install the Okta Sign-In Widget to authenticate using the “My OIDC” app you already created and get an access token.

yarn add @okta/okta-signin-widget

Create an OktaAuthService that can be used to render the Sign-In Widget and handle authentication. The following TypeScript code should be in client/src/app/shared/okta/okta.service.ts. Be sure to replace {dev-id}, {client-id}, and {as-server-url} with values appropriate for your Okta application and authorization server.

import { Injectable } from '@angular/core';
import * as OktaSignIn from '@okta/okta-signin-widget/dist/js/okta-sign-in.min.js'
import { ReplaySubject } from 'rxjs/ReplaySubject';
import { Observable } from 'rxjs/Observable';
import { Router } from '@angular/router';

@Injectable()
export class OktaAuthService {

  signIn = new OktaSignIn({
    baseUrl: 'https://dev-{dev-id}.oktapreview.com',
    clientId: '{client-id}',
    redirectUri: 'http://localhost:4200',
    authParams: {
      issuer: '{as-server-url}',
      responseType: ['id_token', 'token'],
      scopes: ['openid', 'email', 'profile']
    }
  });

  private userSource: ReplaySubject<any>;
  public user$: Observable<any>;

  constructor(private router: Router) {
    this.userSource = new ReplaySubject<any>(1);
    this.user$ = this.userSource.asObservable();
  }

  isAuthenticated() {
    // Checks if there is a current accessToken in the TokenManger.
    return !!this.signIn.tokenManager.get('accessToken');
  }

  login(next?: string) {
    if (next) {
      this.router.navigate(['login', {next: next}]);
    } else {
      this.router.navigate(['login']);
    }
  }

  showLogin() {
    // Launches the widget and stores the tokens
    try {
      this.signIn.renderEl({el: '#okta-signin-container'}, response => {
        if (response.status === 'SUCCESS') {
          response.forEach(token => {
            if (token.idToken) {
              this.signIn.tokenManager.add('idToken', token);
            }
            if (token.accessToken) {
              this.signIn.tokenManager.add('accessToken', token);
            }
          });
          this.userSource.next(this.idTokenAsUser);
          this.signIn.hide();
        } else {
          console.error(response);
        }
      });
    } catch (exception)  {
      // An instance of the widget has already been rendered. Call remove() first.
    }
  }

  get idTokenAsUser() {
    const token = this.signIn.tokenManager.get('idToken');
    return {
      name: token.claims.name,
      email: token.claims.email,
      username: token.claims.preferred_username
    };
  }

  async logout() {
    // Terminates the session with Okta and removes current tokens.
    this.signIn.tokenManager.clear();
    await this.signIn.signOut();
    this.signIn.remove();
    this.userSource.next(undefined);
    this.login();
  }
}

NOTE: I realize this is quite a bit of code to render a sign-in form. The good news is we’ll be wrapping much of it into an okta-angular library soon.

Create an OktaAuthGuard in client/src/app/shared/okta/okta.guard.ts. You’ll use this to guard routes so they can’t be activated if the user isn’t authenticated.

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
import { OktaAuthService } from './okta.service';

@Injectable()
export class OktaAuthGuard implements CanActivate {
  signIn;
  authenticated;

  constructor(private oktaService: OktaAuthService) {
    this.signIn = oktaService;
  }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    this.authenticated = this.oktaService.isAuthenticated();
    if (this.authenticated) {
      return true;
    }
    this.signIn.login();
    return false;
  }
}

Create an OktaAuthInterceptor in client/src/app/shared/okta.interceptor.ts to automatically add an Authorization header to HTTP requests.

import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor, HttpErrorResponse, HttpResponse
} from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { OktaAuthService } from './okta.service';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

@Injectable()
export class OktaAuthInterceptor implements HttpInterceptor {

  constructor(private oktaService: OktaAuthService) {
  }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    if (this.oktaService.isAuthenticated()) {
      const accessToken = this.oktaService.signIn.tokenManager.get('accessToken');
      request = request.clone({
        setHeaders: {
          Authorization: `${accessToken.tokenType} ${accessToken.accessToken}`
        }
      });
    }

    return next.handle(request).map((event: HttpEvent<any>) => {
      if (event instanceof HttpResponse) {
        return event;
      }
    }).catch(error => {
      if (error instanceof HttpErrorResponse) {
        if (error.status === 401) {
          this.oktaService.login();
          return Observable.create(error);
        }
      }
    });
  }
}

In client/src/app/app.module.ts, define the routes for the application, with canActivate guards for the note-related routes.

const appRoutes: Routes = [
  {path: 'login', component: LoginComponent},
  {path: 'notes', component: NoteListComponent, canActivate: [OktaAuthGuard]},
  {path: 'notes/:id', component: NoteDetailComponent, canActivate: [OktaAuthGuard]},
  {path: '', redirectTo: '/notes', pathMatch: 'full'}
];

Import HttpClientModule and RouterModule, configure OktaAuthService and OktaAuthGard as providers, and define OktaAuthInterceptor as an HTTP interceptor.

@NgModule({
  declarations: [
    AppComponent,
    NoteListComponent,
    NoteDetailComponent,
    LoginComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    RouterModule.forRoot(appRoutes)
  ],
  providers: [NoteService, OktaAuthService, OktaAuthGuard, {
    provide: HTTP_INTERCEPTORS,
    useClass: OktaAuthInterceptor,
    multi: true
  }],
  bootstrap: [AppComponent]
})
export class AppModule {
}

Modify LoginComponent (in client/src/app/login/login.component.ts) to show the homepage if the user is logged-in, or the sign-in widget if not.

export class LoginComponent implements OnInit {

  constructor(private oktaService: OktaAuthService,
              private router: Router) {
  }

  ngOnInit() {
    if (this.oktaService.isAuthenticated()) {
      this.router.navigate(['/']);
    } else {
      this.oktaService.showLogin();
    }

    // user authentication listener
    this.oktaService.user$.subscribe(user => {
      this.router.navigate(['/']);
    });
  }
}

In the same directory, update login.component.html to have a div for the sign-in widget to render in.

<div id="okta-signin-container"></div>

Modify client/src/app/app.component.html to show the user’s name and add a for rendering all the routes.

<h1>{{title}}</h1>

<div *ngIf="user">
  Welcome {{user?.name}}!
  <button (click)="oktaService.logout()">Logout</button>
</div>

<router-outlet [hidden]="!user"></router-outlet>

Then update client/src/app/app.component.ts so it has a reference to user and oktaService. Notice that this class populates the user variable if the user is already authenticated (for example, they refreshed their browser) or if they sign in with the widget. The this.oktaService.user$ is an Observable that can be subscribed to for changes in the user.

export class AppComponent implements OnInit {
  title = 'My Notes';
  user;

  constructor(public oktaService: OktaAuthService) {
  }

  ngOnInit() {
    if (this.oktaService.isAuthenticated()) {
      this.user = this.oktaService.idTokenAsUser;
    }

    this.oktaService.user$.subscribe(user => {
      this.user = user;
    });
  }
}

To make the Okta Sign-In Widget look good, add its default CSS files to client/src/styles.

@import '~https://ok1static.oktacdn.com/assets/js/sdk/okta-signin-widget/2.1.0/css/okta-sign-in.min.css';
@import '~https://ok1static.oktacdn.com/assets/js/sdk/okta-signin-widget/2.1.0/css/okta-theme.css';

After making all these changes, you should be able to fire up http://localhost:4200 (using ng serve) and see a sign in form.

Sign-In Widget

After signing in, you should see the notes list, but no records in it.

Empty Notes List

To make sure I could add, edit, and delete notes, I wrote a bunch of TypeScript and HTML. I also added Angular Material using yarn add @angular/material @angular/cdk.

You can see the results in the GitHub repository for this article. In particular, the code in the following files:

The final client/src/app/app.module.ts shows all the imports needed for Angular Material. Its stylesheets are referenced in client/src/styles.css. If you copy the code from these files into your project, you’ll have a working notes app with authentication!

The screenshots below show the fruits of my labor.

Material Notes List

Add Note

Edit Note

NOTE: There’s one issue with Okta’s Sign-In Widget I still haven’t fully figured out. Not every time, but everyone once it in a while, it requires me to move my mouse or click on the screen to make the notes list load after logging in. I opened an issue for this and tried the suggested solution, but it doesn’t work 100% of the time.

You now know how to build an Angular client with TypeScript, using Okta’s Sign-In Widget for authentication.

If you’re ambitious, you could even turn the client into a progressive web app (PWA), enabling offline access and faster load times. There are a couple of posts about developing PWAs on the Okta Developer Blog if you’re interested in learning more.

I also published The Ultimate Guide to Progressive Web Applications on scotch.io earlier this summer.

My good buddy Josh Long and I recently hosted a live-coding session where we developed a Spring Boot microservices architecture on the backend and an Angular PWA on the front-end. The code we wrote is very similar to the code in this article. You can check the video out for reference on YouTube.

Deploy to Production

It’s cool to see an application running locally, but it’s even better to see it up and running in production.

My platform of choice for deployment is Cloud Foundry. To get started, you’ll need to create an account and install the command line tools.

brew tap cloudfoundry/tap && brew install cf-cli
cf login -a api.run.pivotal.io

Before deploying, you’ll need to create a couple of files to build the application artifacts and tell Cloud Foundry where everything lives. Create a manifest.yml file in the root directory and specify where the files to upload are. Note that this file expects your apps to be in the same directory, with Spring Boot in a server subdirectory and the Angular app in a client subdirectory.

---
applications:

- name: notes-server 
  host: notes-by-kotlin
  path: ./server/target/notes-0.0.1-SNAPSHOT.jar
  env :
    FORCE_HTTPS: true

- name: notes-client
  host: notes-with-typescript
  path: ./client/dist/
  env :
    FORCE_HTTPS: true

Then, create a build.sh script that packages the server and client, and replaces the development URLs with the production URLs.

#!/bin/bash

start=`pwd`

# set origin for client on server
sed -i -e "s|http://localhost:4200|https://notes-with-typescript.cfapps.io|g" $start/server/src/main/kotlin/com/okta/developer/notes/NotesApplication.kt

mvn clean package -f $start/server/pom.xml

cd $start/client
rm -rf dist
# set API URL
sed -i -e "s|http://localhost:8080|https://notes-by-kotlin.cfapps.io|g" $start/client/src/app/shared/note/note.service.ts
# set redirectURI to client URI
sed -i -e "s|http://localhost:4200|https://notes-with-typescript.cfapps.io|g" $start/client/src/app/shared/okta/okta.service.ts
yarn && ng build -prod --aot
touch dist/Staticfile

cd $start
cf push

# reset and remove changed files
git checkout $start
rm -rf $start/server/src/main/kotlin/com/okta/developer/notes/NotesApplication.kt-e
rm -rf $start/client/src/app/shared/note/note.service.ts-e

After logging into Cloud Foundry, you can run the build script (using sh build.sh) and deploy everything. If you receive an error about the host name being in use, try a different host name in manifest.yml.

Run cf apps to see the URLs of the applications you deployed.

name           requested state   instances   memory   disk   urls
notes-client   started           1/1         1G       1G     notes-with-typescript.cfapps.io
notes-server   started           1/1         1G       1G     notes-by-kotlin.cfapps.io

When you try to log in, you’ll get a CORS error.

Cloud Foundry Login

To fix this, log in to your Okta dashboard once more and navigate to Security > API > Trusted Origins. Add http://notes-with-typescript.cfapps.io as an Origin URL with CORs support. You’ll also need to add https://notes-with-typescript.cfapps.io as a Login Redirect URI to your “My OIDC App”.

You can now log in and add a note.

Success in Production

Learn More

Congrats! You’re well on your way to becoming a Kotlin and TypeScript developer who understands Spring Boot and Angular. All of the code used in this article is available on GitHub.

If you liked what you learned here, check out the Okta Developer Blog for tons more like it.

If you have questions about this code or technologies you want to see in my next post, let me know on Twitter @mraible!

Source:: scotch.io

Understanding the JavaScript For...of Loop

By Orinami Olatunji

What is the For…of Loop?

The for...of statement creates a loop that iterates over iterable objects. For...of loop was introduced in ES6 to be an alternative to both for..in and forEach() and supports the new iteration protocol. For..of lets you loop over data structures that are iterable such as Arrays, strings, Maps, Sets, and more.

Syntax

for (variable of iterable) {
  statement
}
  • variable – For every iteration the value of the property is assigned to the the variable.
  • iterable – An object which has enumerable properties and can be iterated upon.

Use Cases

Let’s explore some use cases.

Arrays

Arrays are simply list-like objects. Array prototype has various methods that allow operations to be performed on it such as mutation and traversing operations. Here’s a for...of operation on an array:

// array-example.js
const iterable = ['mini', 'mani', 'mo'];

for (const value of iterable) {
  console.log(value);
}

// Output:
// mini
// mani
// mo

The result is a print-out of every value in the iterable array.

Demo: https://jsbin.com/dimahag/edit?js,console

Map

The Map object holds key-value pairs. Objects and primitive values can be used as either a key or a value. A Map object iterates through elements based on how it was inserted. In order words, for...of loop returns an array of key-value pair for each iteration.

// map-example.js
const iterable = new Map([['one', 1], ['two', 2]]);

for (const [key, value] of iterable) {
  console.log(`Key: ${key} and Value: ${value}`);
}

// Output:
// Key: one and Value: 1
// Key: two and Value: 2

Demo: https://jsbin.com/lofewiw/edit?js,console

Set

The Set object allows you store unique values of any type, which could be primitive values or objects. Set objects are simply collections of values. Iteration on the elements of a Set is based on insertion order. A value in the Set may only occur once. In order words, if you create a set that has the same element more than once, it is still considered as a single element.

// set-example.js
const iterable = new Set([1, 1, 2, 2, 1]);

for (const value of iterable) {
  console.log(value);
}
// Output:
// 1
// 2

Even though we have a set that has multiple 1’s and 2’s, we have the output as just 1 and 2.

Demo: https://jsbin.com/fajozob/edit?js,console

String

Strings are used to store data in text form.

// string-example.js
const iterable = 'javascript';

for (const value of iterable) {
  console.log(value);
}

// Output:
// "j"
// "a"
// "v"
// "a"
// "s"
// "c"
// "r"
// "i"
// "p"
// "t"

Here, iteration in performed on a string and the character on each index is printed out.

Demo: https://jsbin.com/rixakeg/edit?js,console

Arguments Object

Think of an argument’s object simply as an Array-like object corresponding to the arguments passed to a function. Here’s a use case:

// arguments-example.js
function args() {
  for (const arg of arguments) {
    console.log(arg);
  }
}

args('a', 'b', 'c');
// Output:
// a
// b
// c

You might be wondering, what is going on?! As I said earlier on, arguments recieves any argument passed into the args() function when the function is called. So, if we pass 20 arguments to the args() function, we have 20 arguments printed out.

Demo: https://jsbin.com/ciqabov/edit?js,console

Generators

Generators are functions which can be exited and later re-entered.

// generator-example.js
function* generator(){ 
  yield 1; 
  yield 2; 
  yield 3; 
}; 

for (const g of generator()) { 
  console.log(g); 
}

// Output:
// 1
// 2
// 3

The function* defines a generator function, which returns a Generator object. For more on Generators, check here.

Demo: https://jsbin.com/faviyi/edit?js,console

Closing Iterators

JavaScript offers four known methods of terminating a loop execution namely: break, continue, return and throw. Let’s look at an example:

const iterable = ['mini', 'mani', 'mo'];

for (const value of iterable) {
  console.log(value);
  break;
}

// Output:
// mini

In this example, we use the break keyword to terminate the loop after one execution and only mini gets printed out.

Demo: https://jsbin.com/tisuken/edit?js,console

Plain objects are not iterable

For...of loop only works with iterables. Plain objects are not iterable. Let’s have a look:

const obj = { fname: 'foo', lname: 'bar' };

for (const value of obj) { // TypeError: obj[Symbol.iterator] is not a function
    console.log(value);
}

Here we define a plain object obj and when we try the for...of operation on it, we get an error TypeError: obj[Symbol.iterator] is not a function.

Demo: https://jsbin.com/sotidu/edit?js,console

We can by-pass this by converting an array-like object to an Array. The object would have a length property and its element would have to be indexed. Let’s look at an example:

// object-example.js
const obj = { length: 3, 0: 'foo', 1: 'bar', 2: 'baz' };

const array = Array.from(obj);
for (const value of array) { 
    console.log(value);
}
// Output:
// foo
// bar
// baz

The Array.from() method creates a new Array instance from an array-like or iterable object.

Demo: https://jsbin.com/miwofin/edit?js,console

For…of vs For…in

The for...in loop will iterate over all enumerable properties of an object.

//for-in-example.js
Array.prototype.newArr = () => {};
Array.prototype.anotherNewArr = () => {};
const array = ['foo', 'bar', 'baz'];

for (const value in array) { 
  console.log(value);
}
// Outcome:
// 0
// 1
// 2
// newArr
// anotherNewArr

For...in doesn’t only enumerate the array declaration above, it also looks for inherited non-enumerable properties from the constructor’s prototype, in this case newArr and anotherNewArr and prints them out also.

Demo: https://jsbin.com/quxojof/edit?js,console

For...of is more specific to collections such as arrays and object but doesn’t include all objects.

Note: Any element that has the Symbol.iterator property is iterable.

Array.prototype.newArr = function() {};
const array = ['foo', 'bar', 'baz'];

for (const value of array) { 
  console.log(value);
}
// Outcome:
// foo
// bar
// baz

For...of doesn’t considered non-enumerable properties of the constructor’s prototype. It simply just looks for the enumerable properties and prints it out.

Demo: https://jsbin.com/sakado/edit?js,console

Summary

Understanding the usage of For...of loop can save you a lot of time during development. Hopefully this article helped you understand and write better loop constructs in your JavaScript development. Happy coding!

Source:: scotch.io