Build a CRUD Application with Kotlin and React

Build a CRUD Application with Kotlin and React

This tutorial walks you through creating a basic CRUD application with Kotlin and React. In this tutorial, you’re going to build a client and server application using React for the frontend and Kotlin with Spring Boot for the backend. To secure the React frontend, you’ll use OAuth 2.0 login, and for the backend, you’ll use a JSON Web Token and Spring Boot’s resource server OAuth implementation.

In this tutorial, you’re going to build a client and server application using React for the frontend and Kotlin with Spring Boot for the backend. You’ll first build the app unsecured before securing it using Okta. To secure the React frontend, you’ll use OAuth 2.0 login, and for the backend, you’ll use a JSON Web Token and Spring Boot’s resource server OAuth implementation.

This tutorial covers a lot of ground. It also uses a lot of technologies. Because of this, it doesn’t dive too deep into any one of them and assumes a basic familiarity with React, Kotlin, Spring Boot, and REST APIs.

Install Kotlin and React Project Dependencies

You’ll need to install a few things before you get started.

Java 11: If you don’t have Java 11, you can install OpenJDK. The OpenJDK website has instructions for installation. OpenJDK can also be installed using Homebrew. SDKMAN is another excellent option for installing and managing Java versions.

Node 12: You’ll need Node to create and run your React application. You can install it with Homebrew or download it from nodejs.org.

Yarn: Yarn is a JavaScript package manager. You’ll use it for the React UI application. To install Yarn, head to their website for instructions.

HTTPie: This is a simple command-line utility for making HTTP requests. You’ll use this to test the REST application. Check out the installation instructions on their website.

Okta Developer Account: You’ll be using Okta as an OAuth/OIDC provider to add JWT authentication and authorization to the application.

Download a Kotlin Starter Project With Spring Initializr

To get the party started, you’re going to use the Spring Initializr. It’s a great resource that makes getting started with Spring Boot projects super simple. If you want to dig into the options, take a look at the Spring Initializr GitHub page.

Open this link to a pre-configured project for this tutorial.

Take a moment to peruse the pre-selected options. Note a feature that I really like: you can explore the project online using the Explore button at the bottom of the page.

To highlight some of the important settings:

  • Project: Gradle project (vs. Maven, because XML. Ugh. Holy 1999!)
  • Language: Kotlin
  • Group: com.okta.kotlin (this defines the package of the app files)
  • Artifact: resourceserver (determines the project identifier as well as the name of the generated artifact)
  • Dependencies:
    • Spring Web (Spring Boot’s basic web capabilities)
    • Spring Data JPA (Spring Boot’s data model Java persistence)
    • Rest Repositories (Spring Boot’s ability to turn JPA repositories directly into REST APIs)
    • H2 Database (In-memory SQL database for data model persistence)

Once you’re ready, click the green Generate button at the bottom of the Spring Initializr page. Download the project and move it to a suitable parent directory before unzipping it. You’re also going to create a React frontend, so you might want to make a kotlin-react-app parent directory for both projects.

Test the Kotlin Starter App

You can test the starter project by opening a shell and running the following command from the resource server project’s base directory.

./gradlew bootRun

Give that a few seconds to run. You should see something like this:

2020-01-10 13:54:05.692  INFO 41512 --- [    main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-01-10 13:54:05.696  INFO 41512 --- [    main] c.o.k.ResourceServerApplicationKt : Started ResourceServerApplicationKt in 3.276 seconds (JVM running for 3.624)
<==========---> 80% EXECUTING [29s]
> :bootRun

Open a separate shell and use HTTPie to make a simple request.

$ http :8080

HTTP/1.1 200
Connection: keep-alive
Content-Type: application/hal+json
...

{
  "_links": {
    "profile": {
      "href": "http://localhost:8080/profile"
    }
  }
}

You may be wondering why, without even defining a controller, you have any response at all. This is because by including the spring-boot-starter-data-rest starter dependency, you have included Spring’s auto-magic “hypermedia-based RESTful front end” (as Spring describes it in their docs).

A “hypermedia-based RESTful front end” is a REST API that uses Hypertext Application Language (HAL) format to output descriptive JSON. It’s essentially a systematic way for a REST API to describe itself to client applications and for the client applications to easily navigate between the various endpoints.

The /profile endpoint that you see is an endpoint automatically added by the spring-boot-starter-data-rest starter dependency.

Otherwise, there isn’t much going on yet. That’s about to change!

Create a Kotlin REST API

The next step is to create a REST API using Kotlin and Spring Boot. For this example application, you’re going to model a list of coffee shops (‘cause I spend a lot of time in coffee shops, and not all coffee shops are created equal).

One of the nice things about Spring Boot is that if you define a data model and a repository, it can automatically expose that data as a REST API using the aforementioned HAL. In practice, in production, you may find yourself needing to create custom controllers for your REST APIs, since you may need to inject business logic between the data and the client apps. However, this auto-generated REST API is a great start and may be enough for simple applications.

So, step 1. Define the data model.

Create a new Kotlin class called CoffeeShopModel.kt in the src/main/kotlin/com/okta/kotlin directory.

package com.okta.kotlin

import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id

@Entity
data class CoffeeShopModel(
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    var id: Long = -1,
    var name: String = "",
    var address: String = "",
    var phone: String = "",
    var priceOfCoffee: Double = 0.0,
    var powerAccessible: Boolean = true,
    var internetReliability: Short = 3 // 1-5
) {}

Step 2. Define the repository. Create a Kotlin class called CoffeeShopRepository.kt in the same package.

package com.okta.kotlin  

import org.springframework.data.repository.CrudRepository  
import org.springframework.data.rest.core.annotation.RepositoryRestResource  

@RepositoryRestResource(collectionResourceRel = "coffeeshops", path = "coffeeshops")  
interface CoffeeShopRepository : CrudRepository <CoffeeShopModel, Long >{  
}

That’s all you have to do to turn a data model into a REST API with full CRUD (Create, Read, Update, and Delete) capabilities. The magic happens primarily with two technologies: Spring Data JPA and the Spring Data @RepositoryRestResource annotation. Spring Data JPA is what turns the data model into a persisted entity, using our H2 database. In our case, the database is in-memory by default, so nothing will be persisted across database restarts. Obviously, in a production app, you’d need to connect the app to an actual SQL database instance.

The @RepositoryRestResource and the CrudRepository are what take the persisted model and turn it into a REST API. You can inspect the CrudRepository to see what methods it exposes to get an idea of its capabilities (see its API docs).

Before you test the REST API, you need to make a change to the ResourceServerApplication class. This is not a functional change. It adds a couple of sample coffees shop to your in-memory database so that you have something to work with.

package com.okta.kotlin

import org.springframework.boot.ApplicationRunner
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean

@SpringBootApplication
class ResourceServerApplication  {

  @Bean
  fun run(repository: CoffeeShopRepository) = ApplicationRunner {
    repository.save(CoffeeShopModel(
      name = "Oblique",
      address = "3039 SE Stark St, Portland, OR 97214",
      phone = "555-111-4444",
      priceOfCoffee = 1.50,
      powerAccessible = true,
      internetReliability = 5
    ))
    repository.save(CoffeeShopModel(
      name = "Epoch Coffee",
      address = "221 W N Loop Blvd, Austin, TX 78751",
      phone = "555-111-2424",
      priceOfCoffee = 2.50,
      powerAccessible = true,
      internetReliability = 3
    ))
  }

}

fun main(args: Array<String>) {
    runApplication<ResourceServerApplication>(*args)
}

Restart everything and test your new REST API.

$ http :8080/coffeeshops

HTTP/1.1 200
...

{
  "_embedded": {
    "coffeeshops": [
      {
        "_links": {
          "coffeeShopModel": {
            "href": "http://localhost:8080/coffeeshops/1"
          },
          "self": {
            "href": "http://localhost:8080/coffeeshops/1"
          }
        },
        "address": "3039 SE Stark St, Portland, OR 97214",
        "internetReliability": 5,
        "name": "Oblique",
        "phone": "555-111-4444",
        "powerAccessible": true,
        "priceOfCoffee": 1.5
      },
      {
        "_links": {
          "coffeeShopModel": {
            "href": "http://localhost:8080/coffeeshops/2"
          },
          "self": {
            "href": "http://localhost:8080/coffeeshops/2"
          }
        },
        "address": "221 W N Loop Blvd, Austin, TX 78751",
        "internetReliability": 3,
        "name": "Epoch",
        "phone": "555-111-2424",
        "powerAccessible": true,
        "priceOfCoffee": 2.5
      }
    ]
  },
  "_links": {
    "profile": {
      "href": "http://localhost:8080/profile/coffeeshops"
    },
    "self": {
      "href": "http://localhost:8080/coffeeshops"
    }
  }
}

Before you move on to the React UI, make two more changes to the REST API. You’ll notice above that the id field is not being returned as part of the JSON. This is inconvenient. Also, it’d be better if the REST API was set to have a base context path of /api, making the full path /api/coffeeshops.

To make these changes, you need to add a RepositoryRestConfigurer configuration class.

Add RestConfiguration.kt at src/main/kotlin/com/okta/kotlin/RestConfiguration.kt.

package com.okta.kotlin

import org.springframework.context.annotation.Configuration  
import org.springframework.data.rest.core.config.RepositoryRestConfiguration  
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer  

@Configuration  
open class RestConfiguration : RepositoryRestConfigurer {  
  override fun configureRepositoryRestConfiguration(config: RepositoryRestConfiguration?) {  
    config?.exposeIdsFor(CoffeeShopModel::class.java) 
    config?.setBasePath("/api"); 
  }  
}

If you re-start the resource server and execute an http :8080/api/coffeeshops request, you’ll find that the id field is now included in the JSON response.

Create the React Frontend

You will use Create React App to create the starter React application. The project is well documented on the Create React App homepage. It does a lot of routine work for us, setting up a React application.

From the root directory of the project (the parent directory of the Spring Boot resource server project), run the following command:

yarn create react-app client

If that doesn’t work, as it didn’t for me, failing with a 404 error, you can use npx instead (requires that Node be installed):

npx create-react-app client

Once the client application is created, navigate into the client directory and add a few dependencies:

yarn add bootstrap react-router-dom reactstrap

This installs Bootstrap, React Router, and Reactstrap. It’s unlikely I have to tell you what Bootstrap is, but if you want to dig deeper, take a look at the project page. react-router-dom provides DOM bindings for React Router (their docs). Reactstrap is a library of React components that leverage Bootstrap to provide a set of mobile-friendly UI components (their docs).

Add Bootstrap’s CSS file as an import in client/src/index.js.

import 'bootstrap/dist/css/bootstrap.min.css';

Update the client/src/App.js file:

import React, { Component } from 'react';
import './App.css';

class App extends Component {
  state = {
    isLoading: true,
    coffeeShops: []
  };

  async componentDidMount() {
    const response = await fetch('/api/coffeeshops');
    const body = await response.json();
    this.setState({coffeeShops: body._embedded.coffeeshops, isLoading: false});
  }

  render() {
    const {coffeeShops, isLoading} = this.state;

    if (isLoading) {
      return <p>Loading...</p>;
    }

    return (
      <div className="App">
        <header className="App-header">
          <div className="App-intro">
            <h2>Coffee Shop List</h2>
            {coffeeShops.map(coffeeShop =>
              <div key={coffeeShop.id}>
                {coffeeShop.name} - {coffeeShop.address}
              </div>
            )}
          </div>
        </header>
      </div>
    );
  }
}

export default App;

Instead of using config values to set the resource server’s URL, you can use a proxy. Do this by adding the following to the package.json file.

"proxy": "http://localhost:8080",

Take a look at the Create React App docs on this feature to learn more about proxying requests in development.

Run the React app using yarn start (ensure your Spring Boot resource server is running). You should see a very simple list of the coffee shop names and addresses.

Build a Full-Featured React UI

The UI as it is doesn’t do very much except demonstrate successful communication between the client and the server. The next step is to add some components, such as a navigation bar, a page for editing and adding coffee shops, and a nicer way to display the data. You’re also going to use routing to map URLs to app pages.

Change src/App.js to match the following. This adds three routes: a home route, a coffee shop list route, and a route for editing and creating new coffee shop entries. You’ll notice that the module uses composition (via the render() method) to pass the Api class and the NavBar module to the route components. In our current app state, without authentication and authorization, this is unnecessary. However, once you add in OAuth, you’ll see how this allows you to keep all of the auth logic in one place, avoiding a bunch of repeated code (or having to use something like MobX or Redux to manage a global state).

src/App.s

import React, { Component } from 'react';
import './App.css';
import Home from './Home';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import CoffeeShopsList from './CoffeeShopsList';
import CoffeeShopEdit from './CoffeeShopEdit';
import Api from './Api';
import NavBar from './NavBar';

const api = new Api();

class App extends Component {

  render() {
    const navbar = <NavBar/>;

    return (
      <Router>
        <Switch>
          <Route
            path='/'
            exact={true}
            render={(props) => <Home {...props} api={api} navbar={navbar}/>}
          />
          <Route
            path='/coffee-shops'
            exact={true}
            render={(props) => <CoffeeShopsList {...props} api={api} navbar={navbar}/>}
          />
          <Route
            path='/coffee-shops/:id'
            render={(props) => <CoffeeShopEdit {...props} api={api} navbar={navbar}/>}
          />
        </Switch>
      </Router>
    )
  }
}

export default App;

Create a new JavaScript file, src/Home.js, with the following contents. This will be a simple home page. All it does is display the navigation bar and a button to open the list of coffee shops.

src/Home.js

import React, { Component } from 'react';
import './App.css';
import { Link } from 'react-router-dom';
import { Button, Container } from 'reactstrap';

class Home extends Component {

  render() {
    return (
      <div className="app">
        {this.props.navbar}
        <Container fluid>
          <div>
            <Button color="secondary">
              <Link className="app-link" to="/coffee-shops">Manage Coffee Shops</Link>
            </Button>
          </div>
        </Container>
      </div>
    );
  }
}

export default Home;

Create the navigation bar JavaScript file, src/NavBar.js. The navbar displays a “Home” link, as well as a link to Okta’s Twitter channel and a link to the project repository.

src/NavBar.js

import React, { Component } from 'react';
import { Collapse, Nav, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink } from 'reactstrap';
import { Link } from 'react-router-dom';

class NavBar extends Component {

  constructor(props) {
    super(props);
    this.state = {isOpen: false};
    this.toggle = this.toggle.bind(this);
  }

  toggle() {
    this.setState({
      isOpen: !this.state.isOpen
    });
  }

  render() {
    return <Navbar color="light" light expand="md">
      <NavbarBrand tag={Link} to="/">Home</NavbarBrand>
      <NavbarToggler onClick={this.toggle}/>
      <Collapse isOpen={this.state.isOpen} navbar>
        <Nav className="ml-auto" navbar>
          <NavItem>
            <NavLink
              href="https://twitter.com/oktadev">@oktadev</NavLink>
          </NavItem>
          <NavItem>
            <NavLink href="https://github.com/oktadeveloper/okta-kotlin-react-crud-example">GitHub</NavLink>
          </NavItem>
        </Nav>
      </Collapse>
    </Navbar>;
  }
}

export default NavBar;

The next file holds the components that display the coffee shops in a responsive, card-style grid layout. Create a new file, src/CoffeeShopsList.js, and add the following contents. There are two components in this file. CoffeeShop is a simple, functional component that encapsulates the display of each coffee shop item. CoffeeShopsList manages the overall display logic as well as the asynchronous calls to the server for loading and updating data.

src/CoffeeShopsList.js

import React, { Component } from 'react';
import {
  Alert,
  Button
} from 'reactstrap';
import { Link } from 'react-router-dom';

const CoffeeShop = (props) => (
  <div className="coffeeshop-container p-2 m-2 d-flex flex-column">
    <h3>{props.name}</h3>
    <div className="coffeeshop-body">
      <div className="subtitle-container">
        <div>Cost: ${props.priceOfCoffee} / cup</div>
        <div>Internet Reliability: {props.internetReliability} / 5 </div>
        <div>{ props.powerAccessible ? "Power Accessible" : "Power NOT Accessible"} </div>
      </div>
      <div>{props.address}</div>
      <div>{props.phone}</div>
    </div>
    <div className="coffeeshop-footer">
      <Button color="secondary" tag={Link} to={"/coffee-shops/" + props.id}>Edit</Button>
      <Button color="danger" onClick={() => props.remove(props.id)}>Delete</Button>
    </div>
  </div>
);

class CoffeeShopsList extends Component {

  constructor(props) {
    super(props);
    this.state = {
      coffeeShops: [],
      isLoading: true,
      errorMessage: null
    };
    this.remove = this.remove.bind(this);
  }

  async componentDidMount() {
    this.setState({isLoading: true});
    const response = await this.props.api.getAll();
    if (!response.ok) {
      this.setState({
          errorMessage: `Failed to load coffee shops: ${response.status} ${response.statusText}`,
          isLoading: false
        }
      )
    }
    else {
      const body = await response.json();
      const coffeeShops = body._embedded.coffeeshops;
      this.setState({
        coffeeShops: coffeeShops,
        isLoading: false,
        errorMessage: null
      });
    }
  }

  async remove(id) {
    let response = await this.props.api.delete(id);
    if (!response.ok) {
      this.setState({errorMessage: `Failed to delete coffee shop: ${response.status} ${response.statusText}`})
    }
    else {
      let updatedCoffeeShops = [...this.state.coffeeShops].filter(i => i.id !== id);
      this.setState({coffeeShops: updatedCoffeeShops, errorMessage: null});
    }
  }

  render() {
    const {coffeeShops, isLoading, errorMessage} = this.state;

    if (isLoading) {
      return <p>Loading...</p>;
    }

    return (
      <div>
        {this.props.navbar}
        <div className="d-flex flex-row justify-content-between p-3">
          <h3 className="coffee-shops-title">Coffee Shops</h3>
          <Button color="success" tag={Link} to="/coffee-shops/new">Add New</Button>
        </div>
        { errorMessage ?
          <div className="d-flex flex-row justify-content-center">
            <Alert color="warning" style={{flex:1, maxWidth:'80%'}}>
              {errorMessage}
            </Alert>
          </div> : null
        }
        <div className="d-flex flex-row flex-container flex-wrap justify-content-center">
          { coffeeShops.map( coffeeShop =>
            <CoffeeShop {...coffeeShop} remove={this.remove.bind(this)} key={coffeeShop.id}/>
          )}
          { !coffeeShops || coffeeShops.length === 0 ? <p>No coffee shops!</p> : null}
        </div>
      </div>
    );
  }
}

export default CoffeeShopsList;

Add a React Component to Edit with Reactstrap Form Elements

The next new file, src/CoffeeShopEdit.js, is the component that is responsible for editing existing coffee shop entries and creating new ones. It demonstrates the use of Reactstrap form elements, as well as making some asynchronous calls to the server.

src/CoffeeShopEdit.js

import React, { Component } from 'react';
import { Link, withRouter } from 'react-router-dom';
import { Alert, Button, Container, Form, FormGroup, Input, Label } from 'reactstrap';

class CoffeeShopEdit extends Component {

  emptyItem = {
    name: '',
    address: '',
    phone: '',
    priceOfCoffee: '',
    powerAccessible: '',
    internetReliability: ''
  };

  constructor(props) {
    super(props);
    this.state = {
      item: this.emptyItem,
      errorMessage: null,
      isCreate: false
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  async componentDidMount() {
    this.state.isCreate = this.props.match.params.id === 'new'; // are we editing or creating?
    if (!this.state.isCreate) {
      const response = await this.props.api.getById(this.props.match.params.id);
      const coffeeShop = await response.json();
      this.setState({item: coffeeShop});
    }
  }

  handleChange(event) {
    const target = event.target;
    const value = target.value;
    const name = target.name;
    let item = {...this.state.item};
    item[name] = value;
    this.setState({item});
  }

  async handleSubmit(event) {
    event.preventDefault();
    const {item, isCreate} = this.state;

    let result = isCreate ? await this.props.api.create(item) : await this.props.api.update(item);

    if (!result.ok) {
      this.setState({errorMessage: `Failed to ${isCreate ? 'create' : 'update'} record: ${result.status} ${result.statusText}`})
    } else {
      this.setState({errorMessage: null});
      this.props.history.push('/coffee-shops');
    }

  }

  render() {
    const {item, errorMessage, isCreate} = this.state;
    const title = <h2>{isCreate ? 'Add Coffee Shop' : 'Edit Coffee Shop'}</h2>;

    return (
      <div>
        {this.props.navbar}
        <Container style={{textAlign: 'left'}}>
          {title}
          {errorMessage ?
            <Alert color="warning">
              {errorMessage}
            </Alert> : null
          }
          <Form onSubmit={this.handleSubmit}>
            <div className="row">
              <FormGroup className="col-md-8 mb-3">
                <Label for="name">Name</Label>
                <Input type="text" name="name" id="name" value={item.name || ''}
                       onChange={this.handleChange} autoComplete="name"/>
              </FormGroup>
              <FormGroup className="col-md-4 mb-3">
                <Label for="phone">Phone</Label>
                <Input type="text" name="phone" id="phone" value={item.phone || ''}
                       onChange={this.handleChange} autoComplete="phone"/>
              </FormGroup>
            </div>
            <FormGroup>
              <Label for="address">Address</Label>
              <Input type="text" name="address" id="address" value={item.address || ''}
                     onChange={this.handleChange} autoComplete="address-level1"/>
            </FormGroup>
            <div className="row">
              <FormGroup className="col-md-4 mb-3">
                <Label for="priceOfCoffee">Price of Coffee</Label>
                <Input type="text" name="priceOfCoffee" id="priceOfCoffee" value={item.priceOfCoffee || ''}
                       onChange={this.handleChange}/>
              </FormGroup>
              <FormGroup className="col-md-4 mb-3">
                <Label for="powerAccessible">Power Accessible?</Label>
                <Input type="select" name="powerAccessible" id="powerAccessible"
                       value={item.powerAccessible ? 'true' : 'false'}
                       onChange={this.handleChange}>
                  <option value="true">Yes</option>
                  <option value="false">No</option>
                </Input>
              </FormGroup>
              <FormGroup className="col-md-4 mb-3">
                <Label for="internetReliability">Internet Reliability</Label>
                <Input type="select" name="internetReliability" id="internetReliability"
                       value={item.internetReliability || '-'}
                       onChange={this.handleChange}>
                  <option>1</option>
                  <option>2</option>
                  <option>3</option>
                  <option>4</option>
                  <option>5</option>
                  <option value="-">-</option>
                </Input>
              </FormGroup>
            </div>
            <FormGroup>
              <Button color="primary" type="submit">Save</Button>{' '}
              <Button color="secondary" tag={Link} to="/coffee-shops">Cancel</Button>
            </FormGroup>
          </Form>
        </Container>
      </div>
    );
  }
}

export default withRouter(CoffeeShopEdit);

Add an Authentication-Aware Service for Server Requests

Create one more new file, src/Api.js. This module serves to centralize all of the server request logic. It is written so that it allows you to pass an authorization token to its constructor (which you’ll get to in the next section), and it will set the appropriate header. Without an auth token, it makes an unauthenticated request.

src/Api.js

class Api {

  constructor(authToken) {
    this.authToken = authToken;
  }

  headers = {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  };

  BASE_URL = '/api/coffeeshops';

  createHeaders() {
    return this.authToken ? {
      ...this.headers,
      'Authorization': 'Bearer ' + this.authToken
    } : this.headers;
  }

  async getAll() {
    return await fetch(this.BASE_URL, {
      method: 'GET',
      headers: this.createHeaders()
    });
  }

  async getById(id) {
    return await fetch(`${this.BASE_URL}/${id}`, {
      method: 'GET',
      headers: this.createHeaders()
    });
  }

  async delete(id) {
    return await fetch(`${this.BASE_URL}/${id}`, {
      method: 'DELETE',
      headers: this.createHeaders()
    });
  }

  async update(item) {
    return await fetch(`${this.BASE_URL}/${item.id}`, {
      method:'PUT',
      headers: this.createHeaders(),
      body: JSON.stringify(item),
    });
  }

  async create(item) {
    return await fetch(this.BASE_URL, {
      method:'POST',
      headers: this.createHeaders(),
      body: JSON.stringify(item),
    });
  }
}

export default Api;

Make Your React App Look Good

Finally, add some styling to make things look good. Modify src/App.css to have the CSS below.

html, #root {
  background-color: #282c34;
}

.row {
  margin-bottom: 10px;
}

a.app-link {
   color: #d3d8e3;
}

a.app-link:hover {
  color: #a2a9b8;
  text-decoration: none;
}

.container-fluid {
  color: white;
  text-align: center;
  padding-top: 40px;
}

.flex-container {
  color: white;
  text-align: center;
  padding-top: 40px;
}

.container {
  color: white;
  text-align: left;
  padding-top: 40px;
}

.coffee-shops-title {
  color: white;
}

.coffeeshop-container {
  width: 400px;
  min-width: 300px;
  background-color: #e9edf7;
  border-radius: 10px;
  color: #282c34;
  font-size: calc(10px + 1.0vmin);
}

.coffeeshop-container h3 {
  font-size: calc(10px + 2vmin);
}

.subtitle-container {
  font-size: calc(10px + 0.8vmin);
  color: #596273;
  margin-bottom: 10px;
}

.coffeeshop-body {
  flex: 1;
  margin-bottom: 10px;
}

.coffeeshop-footer {
  padding-top:8px;
  margin-top:8px;
  border-top: 1px solid #282c34;
}

.coffeeshop-footer .btn {
  margin: 5px 5px;
}

@media only screen and (max-width: 992px) {
  .coffeeshop-container {
    width: 300px;
  }
}

@media only screen and (max-width: 576px) {
  .coffeeshop-container {
    width: 80%;
  }
}

Run yarn start again if you need to (you may not need to; if you left it running, it should update automatically as you make changes). Make sure your resource server is running as well.

Take a look at the updated app at http://localhost:3000/.

You’ll see the new home page with the navbar.

Press the Manage Coffee Shops button.

You can now view, edit, create, and delete coffee shops.

Secure Your Kotlin + React App

You’ve got a nice, functional client and server application going. Don’t rest on your laurels yet! It’s unsecured, and if you leave that thing unattended, hackers will have it spewing spam and twist it into cheating little old ladies out of their retirement funds quicker than you can figure out what the heck a ‘hook’ is.

The next step is to secure it. You’re going to implement OAuth 2.0 login on the frontend. On the back end, you’re going to use a JSON Web Token (JWT) to secure the resource server. To make life much easier, you’re going to use Okta as your OAuth provider. Using Okta means you won’t have to write or maintain any login code or handle user passwords; nor will you have to waste any time mucking around writing code to verify tokens.

Okta has two projects that are going to make this painless: the Okta React SDK and the Okta Spring Boot Starter.

Before you make any code changes, though, you need to log into your Okta developer account and create an OpenID Connect (OIDC) application.

Create an OpenID Connect Application

OpenID Connect (or, OIDC) is an authentication protocol built on top of OAuth 2.0, which is an authorization protocol. Very briefly, OIDC allows you to know who a client is, and OAuth 2.0 allows you to determine what they’re allowed to do. Together they specify a complete authentication and authorization system. You’re going to use Okta’s implementation of these protocols as your OAuth 2.0 / OIDC provider.

To do this, you need to create an OIDC application in your Okta account. This configures and activates the OIDC application that your frontend application and backend resources server will interact with when verifying authentication and authorization.

If you haven’t already, head over to developer.okta.com to sign up for a free account. Once you have an account, open the developer dashboard and create an OpenID Connect (OIDC) application by clicking on the Applications top-menu item, and then on the Add Application button.

  • Select Single-Page App and click Next
  • Change the name to be “Kotlin React App”
  • Change the Base URI to http://localhost:3000
  • Change the Login redirect URIs to have http://localhost:3000/implicit/callback
  • Update the Logout redirect URIs to have http://localhost:3000

You’ll need your Client ID in a moment.

Configure the Resource Server for JWT Authentication

Securing the Spring Boot REST API is super easy. First, you need to add the Okta Spring Boot Starter to your Gradle project. This is a library we’ve created that streamlines adding OAuth 2.0/OIDC to your Spring Boot app with Okta.

Add the dependency in build.gradle.kts:

dependencies {
    ...
    implementation("com.okta.spring:okta-spring-boot-starter:1.3.0")
    ...
}

Next, create a SecurityConfiguration class to configure Spring Boot as an OAuth 2.0 resource server.

src/main/kotlin/com/okta/kotlin/SecurityConfiguration.kt

package com.okta.kotlin

import com.okta.spring.boot.oauth.Okta
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter

@Configuration
class SecurityConfiguration : WebSecurityConfigurerAdapter() {
  override fun configure(http: HttpSecurity) {
    http
      .csrf().disable()
      .authorizeRequests().anyRequest().authenticated()
      .and()
      .oauth2ResourceServer().jwt();

    // Send a 401 message to the browser (w/o this, you'll see a blank page)
    Okta.configureResourceServer401ResponseBody(http);
  }
}

NOTE: This file also does a couple of other things: 1) it disables CSRF (Cross-site forgery protection), and 2) it configures the resource server to send a 401 instead of a blank page if a request is not authorized. Disabling CSRF in production is definitely NOT recommended, and you’re doing it here to simplify things so you can focus on OAuth 2.0 login and JWT authentication. To see how to implement CSRF protection, take a look at some of the other blog posts at the end of this tutorial.

Finally, add some configuration to src/main/resources/application.properties. Here you need the Okta Issuer URL (from the Okta developer dashboard, go to API > Authorization Servers and look in the table under the default server). You also need the Client ID from the OIDC application you just created.

okta.oauth2.issuer=https://{yourOktaUrl}/oauth2/default
okta.oauth2.clientId={yourClientID}

That’s it. The resource server now requires a valid JWT for all requests.

Stop and restart the resource server: ./gradlew bootRun.

You can test that it requires a JWT by opening a shell and running a simple request using HTTPie:

http :8080/coffee-shops

You’ll get a 401 / Unauthorized:

HTTP/1.1 401
...

401 Unauthorized

Add OAuth 2.0 Login to the React Application

The first step to adding Okta OAuth 2.0 login to your frontend React application is to add the Okta React SDK. Take a look at the project’s GitHub page for more info.

Use Yarn to add the project dependency to your React client.

yarn add @okta/[email protected]

Now update src/App.js to match the following. Fill in your Client ID and your Issuer URL in the Security component properties.

import React, { Component } from 'react';
import './App.css';
import Home from './Home';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { Security, SecureRoute, ImplicitCallback } from '@okta/okta-react';
import CoffeeShopsList from './CoffeeShopsList';
import CoffeeShopEdit from './CoffeeShopEdit';
import { withAuth } from '@okta/okta-react';
import Api from './Api';
import NavBar from "./NavBar";

const AuthWrapper = withAuth(class WrappedRoutes extends Component {

  constructor(props) {
    super(props);
    this.state = { authenticated: null, user: null, api: new Api() };
    this.checkAuthentication = this.checkAuthentication.bind(this);
  }

  async checkAuthentication() {
    const authenticated = await this.props.auth.isAuthenticated();
    if (authenticated !== this.state.authenticated) {
      if (authenticated) {
        const user = await this.props.auth.getUser();
        let accessToken = await this.props.auth.getAccessToken();
        this.setState({ authenticated, user, api: new Api(accessToken) });
      }
      else {
        this.setState({ authenticated, user:null, api: new Api() });
      }
    }
  }

  async componentDidMount() {
    this.checkAuthentication();
  }

  async componentDidUpdate() {
    this.checkAuthentication();
  }

  async login() {
    if (this.state.authenticated === null) return; // do nothing if auth isn't loaded yet
    this.props.auth.login('/');
  }

  async logout() {
    this.props.auth.logout('/');
  }

  render() {
    let {authenticated, user, api} = this.state;

    if (authenticated === null) {
      return null;
    }

    const navbar = <NavBar
      isAuthenticated={authenticated}
      login={this.login.bind(this)}
      logout={this.logout.bind(this)}
    />;

    return (
      <Switch>
        <Route
          path='/'
          exact={true}
          render={(props) => <Home {...props} authenticated={authenticated} user={user} api={api} navbar={navbar} />}
        />
        <SecureRoute
          path='/coffee-shops'
          exact={true}
          render={(props) => <CoffeeShopsList {...props} authenticated={authenticated} user={user} api={api} navbar={navbar}/>}
        />
        <SecureRoute
          path='/coffee-shops/:id'
          render={(props) => <CoffeeShopEdit {...props} authenticated={authenticated} user={user} api={api} navbar={navbar}/>}
        />
      </Switch>
    )
  }
});

class App extends Component {

  render() {
    return (
      <Router>
        <Security issuer='https://{yourOktaUrl}/oauth2/default'
              clientId='{yourClientId}'
              redirectUri={window.location.origin + '/implicit/callback'}
              pkce={true}>
          <Route path='/implicit/callback' component={ImplicitCallback} />
          <AuthWrapper />
        </Security>
      </Router>
    )
  }
}

export default App;

The Security component is where the Okta OAuth configuration happens. You need to fill in your clientId and your issuer in the properties there.

You’ll also notice that I chose to centralize all the security logic in a wrapper component called AuthWrapper. This allows you to handle all authentication-related logic in one place and pass down the authentication state as properties. It also allows you to pass down the Api module with the access token to the child components. This keeps a lot of the security logic out of the route/view components and avoids some repeated code, which I like.

However, the withAuth() function supplied by the Okta React SDK can be applied to any React component (that is a child of the Security component). Thus, it’s also possible not to use a wrapper class like this and inject the auth prop into the various routes directly. Ultimately, in an app in production, the auth state would likely be moved to a global state using something like MobX or Redux.

Two more files need to be updated, the home page and the navigation bar.

Update src/Home.js:

import React, { Component } from 'react';
import './App.css';
import { Link } from 'react-router-dom';
import { Button, Container } from 'reactstrap';

class Home extends Component {

  render() {
    if (this.props.authenticated === null) {
      return <p>Loading...</p>;
    }

    return (
      <div className="app">
        {this.props.navbar}
        <Container fluid>
          { this.props.authenticated ?
            <div>
              <p>Welcome, {this.props.user.name}</p>
              <Button color="secondary">
                <Link className="app-link" to="/coffee-shops">Manage Coffee Shops</Link>
              </Button>
            </div> :
            <div>
              <p>Please log in to manage coffee shops.</p>
              <Button color="secondary" disabled={true}>
                Manage Coffee Shops
              </Button>
            </div>
          }
        </Container>
      </div>
    );
  }
}

export default Home;

Update src/NavBar.js to add login and logout buttons:

import React, { Component } from 'react';
import { Button, Collapse, Nav, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink } from 'reactstrap';
import { Link } from 'react-router-dom';

class NavBar extends Component {

  constructor(props) {
    super(props);
    this.state = {isOpen: false};
    this.toggle = this.toggle.bind(this);
  }

  toggle() {
    this.setState({
      isOpen: !this.state.isOpen
    });
  }

  render() {
    const {isAuthenticated, login, logout} = this.props;

    return <Navbar color="light" light expand="md">
      <NavbarBrand tag={Link} to="/">Home</NavbarBrand>
      <NavbarToggler onClick={this.toggle}/>
      <Collapse isOpen={this.state.isOpen} navbar>
        <Nav className="ml-auto" navbar>
          <NavItem>
            <NavLink
              href="https://twitter.com/oktadev">@oktadev</NavLink>
          </NavItem>
          <NavItem>
            <NavLink href="https://github.com/oktadeveloper/okta-kotlin-react-crud-example">GitHub</NavLink>
          </NavItem>
          { !isAuthenticated ?
            <NavItem>
              <Button color="secondary" outline onClick={login}>Login</Button>
            </NavItem> :
            <NavItem>
              <Button color="secondary" outline onClick={logout}>Logout</Button>
            </NavItem>
          }
        </Nav>
      </Collapse>
    </Navbar>;
  }
}

export default NavBar;

Time to test the secured app.

Test Your Secured Kotlin + React Application

Run the resource server (if you need to):

./gradlew bootRun

Start the React client:

yarn start

Open a browser: http://localhost:3000.

Click the Login button in the header. You’ll be redirected to the Okta login page. Log in using your Okta credentials.

When you return to your client app’s homepage, click the Manage Coffee Shops button.

From this page, you can edit, delete, and add new coffee shops.

All done! In this tutorial, you created a web-based application using a React frontend with data being served by a Kotlin Spring Boot resource server. You also saw how to use a free developer account from Okta to add OAuth 2.0 login to your application and to secure your resource server.

You can find the source code for this example on GitHub in the okta-kotlin-react-crud-example repository.

Originally published by Andrew Hughes at https://developer.okta.com

Hire React Js Developer from Expert React JS Development Company

Hire React Js Developer from Expert React JS Development Company

Are you looking to [hire React JS developer](https://www.mobiwebtech.com/react-js-development-company/ "hire React JS developer") from a prestigious and reliable React JS development company? Visit at Mobiweb Technologies here we have a big team...

Are you looking to hire React JS developer from a prestigious and reliable React JS development company? Visit at Mobiweb Technologies here we have a big team of expert React JS developers, you can hire them on an hourly, weekly or monthly basis for the successful completion of your dream project.

Learn React.js: Front-End Web Development for Beginners

Learn React.js: Front-End Web Development for Beginners

Learn React.js - Frontend Web Development for Beginners. In this React tutorial, you will learn the core fundamentals of React JS and Modern JavaScript so that you can start building lightning fast web apps using React JS. Learn Modern JavaScript and React JS from absolute scratch. Learn to make AJAX requests to get data from remote API and display into your web application. Learn React JS, which is one of the most exciting technology of recent time

Learn React.js - Frontend Web Development for Beginners - Web Development in 2019. In this video you will learn the core fundamentals of React JS and Modern JavaScript so that you can start building lightning fast web apps using React JS.

In this video, you will learn Modern JavaScript and React JS from absolute scratch. you will learn to make AJAX requests to get data from remote API and display into your web application.

So if you are ready to learn React JS, which is one of the most exciting technology of recent time

Thanks for watching

If you liked this post, share it with all of your programming buddies!

Follow us on Facebook | Twitter

Further reading

React - The Complete Guide (incl Hooks, React Router, Redux)

**☞ **Modern React with Redux [2019 Update]

**☞ **50+ Java Interview Questions for Programmers

**☞ **Top 100 Python Interview Questions and Answers

**☞ **100+ Basic Machine Learning Interview Questions and Answers

**☞ **Introduction to Java String Interview Questions and Answers

**☞ **Best 50 React Interview Questions and Answers in 2019

**☞ **Top 50+ SQL Interview Questions and Answers in 2019

**☞ **Best Java Microservices Interview Questions In 2019

**☞ **Best 50 Nodejs interview questions from Beginners to Advanced in 2019

**☞ **100+ Java Interview Questions and Answers In 2019

Develop this one fundamental skill if you want to become a successful developer

Throughout my career, a multitude of people have asked me&nbsp;<em>what does it take to become a successful developer?</em>

Throughout my career, a multitude of people have asked me what does it take to become a successful developer?

It’s a common question newbies and those looking to switch careers often ask — mostly because they see the potential paycheck. There is also a Hollywood level of coolness attached to working with computers nowadays. Being a programmer or developer is akin to being a doctor or lawyer. There is job security.

But a lot of people who try to enter the profession don’t make it. So what is it that separates those who make it and those who don’t? 

Read full article here