CodepaLOUsa 2019 - Presentations

You can find the slide decks and collateral from my CodepaLOUsa 2019 session here.

Contract-First API Development from Deven Phillips


Start with an example JSON object:



{
    "title": "Something I need to do",
    "description": "A long description",
    "dueDate": "2019-09-14T09:00:00.000Z",
    "complete": false,
    "created": "2019-09-27T14:00:00.000Z",
    "id": "543da998-a186-11e9-96b9-2b86a7060fde"
}


  • Open APICur.io and create a new API using the blank template
  • Edit the API
  • Click on “Add a data type”
  • Give it a name and paste the example JSON data
  • Select “REST Resource” and click “Save”
  • Show OpenAPI YAML Source
  • Explain about creating a “Request” type and a “Hydrated” type.
    • Request type would not have “id” or “created”
    • Explain “allOf” and “$ref”
    • Explain about inheritance and discriminator
  • Download the OpenAPI YAML
  • Install OpenAPI Generator
    • npm install -g openapi-generator


Generate Server Implementation using JAX-RS
  • Show “openapi-generator help generate”
  • Create configuration JSON file
{
  "apiPackage": "com.redhat.labs.todo.api",
  "artifactId": "todo",
  "artifactVersion": "1.0.0-SNAPSHOT",
  "groupId": "com.redhat.labs",
  "packageName": "com.redhat.labs.todo",
  "modelPackage": "com.redhat.labs.todo.models",
  "withXml": true,
  "dateLibrary": "java8",
  "java8": true,
  "booleanGetterPrefix": "is",
  "serverPort": 8080
}
  • Run generator
    • openapi-generator generate -i ~/Downloads/todo_2.yml -g jaxrs-jersey -c todo-api-config.json -o todo-jax-rs
  • Open new application in VSCode
  • Explain about shortcomings in OpenAPI Generator
    • Inheritence
    • Annotations/DAO/Database
  • Add manually written code
    • Implement ToDo JPA Entity
package com.redhat.labs.todo.models;

import java.util.UUID;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "todos")
public class ToDoImpl extends Todo {

 @Id
 public UUID getId() {
   return super.getId();
 }
}
    • Show ToDoApiServiceImpl and how you would implement business logic


Generate Client SDK Using typescript-axios
  • Create generator config
{
  "modelPackage": "models",
  "apiPackage": "api",
  "modelPropertyNaming": "camelCase",
  "supportsES6": true,
  "npmName": "todo-ts-sdk",
  "npmVersion": "1.0.0",
  "snapshot": true,
  "withSeparateModelsAndApi": true
}
  • Generate Client SDK:
    • openapi-generator generate -i ~/Downloads/todo_2.yml -g typescript-axios -c todo -ts-sdk-config.json -o todo-typescript-axios
  • Open Client SDK in VSCode
  • Show models
  • Show how to use the API in an application

Generate Spring application from OpenAPI
  • Show “openapi-generator help generate”
  • Create configuration JSON file
{
  "artifactId": "todo",
  "artifactVersion": "1.0.0-SNAPSHOT",
  "groupId": "com.redhat.labs",
  "packageName": "com.redhat.labs.todo",
  "basePackage": "com.redhat.labs.todo",
  "apiPackage": "com.redhat.labs.todo.api",
  "modelPackage": "com.redhat.labs.todo.models",
  "configPackage": "com.redhat.labs.todo.configuration",
  "withXml": true,
  "dateLibrary": "java8",
  "java8": true,
  "booleanGetterPrefix": "is",
  "serverPort": 8080,
  "modelNameSuffix": "Base",
  "minimalUpdate": true,
  "library": "spring-boot"
}
  • Run generator
    • openapi-generator generate -i ~/Downloads/todo_2.yml -g spring -c todo-spring-config.json -o todo-spring
    • Open new application in VSCode
  • Explain about shortcomings in OpenAPI Generator
    • Inheritence
    • Annotations/DAO/Database
  • Add spring-boot-starter-data-jpa to dependencies
  • Add manually written code
    • Implement ToDo JPA Entity
@Entity
@Table(name = "todos")
public class ToDo extends TodoBase {

 private static final Logger LOG = LoggerFactory.getLogger(ToDo.class);

 @Override
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 public @NotNull UUID getId() {
   return super.getId();
 }

 @Override
 @Transient
 public String getDiscriminator() {
   return super.getDiscriminator();
 }

 /* … */

 public static final ToDo fromTodoRequest(ToDoRequestBase request) {
   ToDo newToDo = new ToDo();
   newToDo.setComplete(request.isComplete());
   newToDo.setDescription(request.getDescription());
   newToDo.setDiscriminator("ToDo");
   newToDo.setDueDate(request.getDueDate());
   newToDo.setTitle(request.getTitle());
   LOG.debug(newToDo.toString());
   return newToDo;
 }
}
      • This POJO extends the generated POJO which has the Swagger and Jackson annotations. All persisted field getters MUST be overriden even just to call the super() method.


  • Implement API methods from Interface
    • REMEMBER to copy the parameter annotations except for the Swagger annotations.
  @Override
   public ResponseEntity<Void> createTodo(@Valid @RequestBody ToDoRequestBase toDoRequestBase) {
       ToDo newToDo = ToDo.fromTodoRequest(toDoRequestBase);
       ToDo persisted = dao.save(newToDo);
       if (persisted.getId() != null) {
           return ResponseEntity.ok().build();
       } else {
           return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
       }
   }

Alternative OpenAPI Methods



Direct OpenAPI Support

The benefit of direct OpenAPI support is that there is no code generation step which can sometimes be problemmatic.


Comments

Popular Posts