[JAVA] Introduction to Ratpack (5) --Json & Registry

Ratpack introductory series

  1. Introduction to Ratpack (1) --What is Ratpack
  2. Introduction to Ratpack (2) --Architecture
  3. Introduction to Ratpack (3) --Hello world detailed explanation
  4. Introduction to Ratpack (4) --Routing & Static Content
  5. Introduction to Ratpack (5) --Json & Registry
  6. Introduction to Ratpack (6) --Promise
  7. Introduction to Ratpack (7) --Guice & Spring
  8. Introduction to Ratpack (8) --Session
  9. Introduction to Ratpack (9) --Thymeleaf

Json

Ratpack has built-in JSON support using Jackson. JSON is available as standard and does not require a separate ratpack-jackson module.

Official

@Data
@AllArgsConstructor
@NoArgsConstructor
public static final class User {
    private int id;
    private String name;
}

public static void main( String[] args ) throws Exception {

    Action<Chain> handlers = chain -> {
        chain.all( ctx -> {
            ctx.byMethod( m -> {
                m.get( iCtx -> iCtx.render( Jackson.json( new User( 123, "John" ) ) ) );
                m.post( iCtx -> iCtx.parse( Jackson.fromJson( User.class ) ).then( user -> {
                    iCtx.render( "Received user: " + user );
                } ) );
                // m.post( iCtx -> iCtx.parse( User.class ).then( user -> {
                //     iCtx.render( "Received user: " + user );
                // } ) );
            } );
        } );
    };

    RatpackServer.start( server -> server
            .serverConfig( ServerConfig.builder().development( true ).build() )
            .handlers( handlers ) );
}

(I'm using lombok)

It's easy to use, just wrap it in each method of ratpack.jackson.Jackson. Marshall / unmarshall objects through Jackson. Jackson.fromJson () can be omitted and replaced with the commented out part. This is because the NoOptParserSupport for when the raw Class is passed is automatically added.

Relationship between Registry and Renderer, Parser

render () takes ʻObject as an argument, and parse () takes any Class as an argument. At this time, it is necessary to convert from ʻObject to an appropriate HTTP response. As I mentioned a bit earlier, this conversion uses the Renderer and Parser classes registered in the Registry. It will be converted appropriately by being called according to the requested person. Therefore, you can achieve your own conversion by registering your own custom renderer in the registry.

Here, as an example, let's create a mechanism for receiving and returning data in CSV. ʻUser` is the same as the above example.

First, define Renderer.

public static final class UserRenderer extends RendererSupport<User> {
    @Override
    public void render( Context ctx, User user ) throws Exception {
        ctx.getResponse().contentType( "text/plain" );
        ctx.render( user.getId() + "," + user.getName() );
    }
}

It inherits from RendererSupport, which is the skeleton of the Render interface. When Context.render () in the handler is called with ʻUser as an argument, this renderer that can output the ʻUser class is called. The arguments are the Context of the request and the ʻUser passed to render () `. I think it's almost as you would expect. The method of outputting the response is the same as when I was doing it with the handler.

public static final class UserParser extends NoOptParserSupport {
    @Override
    protected <T> T parse( Context context, TypedData requestBody, TypeToken<T> type ) throws Exception {
        if ( type.getRawType().equals( User.class ) ) {
            String[] csv = requestBody.getText().split( "," );
            User user = new User( Integer.parseInt( csv[0] ), csv[1] );
            return Types.cast( user );
        } else {
            return null;
        }
    }
}

Like the renderer, the parser inherits the NoOptParserSupport skeleton that implements the Parser interface. NoOptParserSupport is used to provide the simplest parser, especially whenparse (Class)is called. If TypeToken, that is, the person requested is not ʻUser, returns null` to indicate that this parser cannot handle it.

public static final class CustomHandler implements Handler {
    @Override
    public void handle( Context ctx ) throws Exception {
        ctx.byMethod( m -> {
            m.get( iCtx -> {
                iCtx.render( new User( 123, "John" ) );
            } );
            m.post( iCtx -> {
                iCtx.parse( User.class ).then( user -> {
                    iCtx.render( "Received: " + user );
                } );
            } );
        } );
    }
}

In order to show the behavior when registering in the registry, I also tried to make the handler an independent class here.

public static void main( String[] args ) throws Exception {
    RatpackServer.start( server -> server
            .serverConfig( ServerConfig.builder().development( true ) )
            .registryOf( spec -> {
                spec.add( new UserRenderer() )
                    .add( new UserParser() )
                    .add( new CustomHandler() );
            } )
            .handler( CustomHandler.class ) );
}

You need to register your own class in Registry. Notice that we are passing the handler () method to the Class, not the instance.

Execution result

$ curl localhost:5050 && echo
123,John
$ curl -X POST localhost:5050 --data "456,Jack" && echo
Received: Sample5_2_Registry.User(id=456, name=Jack)

I was able to confirm that CSV is being processed through a renderer and parser that is uniquely defined.

Recommended Posts

Introduction to Ratpack (5) --Json & Registry
Introduction to Ratpack (8)-Session
Introduction to Ratpack (6) --Promise
Introduction to Ratpack (9) --Thymeleaf
Introduction to Ratpack (2)-Architecture
Introduction to Ratpack (7) --Guice & Spring
Introduction to Ratpack (1) --What is Ratpack?
Introduction to Ruby 2
Introduction to SWING
Introduction to Ratpack (Extra Edition) --Using Sentry
Introduction to web3j
Introduction to Micronaut 1 ~ Introduction ~
[Java] Introduction to Java
Introduction to migration
Introduction to Ratpack (3) --hello world detailed explanation
Introduction to java
Introduction to Doma
Introduction to Ratpack (Extra Edition) --Ratpack written in Kotlin
Introduction to JAR files
Introduction to RSpec 1. Test, RSpec
Introduction to bit operation
Introduction to PlayFramework 2.7 ① Overview
Introduction to Android Layout
Introduction to design patterns (introduction)
Introduction to Practical Programming
Introduction to javadoc command
Introduction to jar command
Introduction to lambda expression
Introduction to java command
Introduction to RSpec 2. RSpec setup
Introduction to Keycloak development
Introduction to javac command
Introduction to Design Patterns (Builder)
Introduction to RSpec 5. Controller specs
Introduction to RSpec 6. System specifications
Introduction to Android application development
Introduction to RSpec 3. Model specs
Introduction to Metabase ~ Environment Construction ~
(Dot installation) Introduction to Java8_Impression
Introduction to Design Patterns (Composite)
Introduction to Micronaut 2 ~ Unit test ~
Introduction to JUnit (study memo)
Introduction to Spring Boot ① ~ DI ~
Introduction to design patterns (Flyweight)
[Java] Introduction to lambda expressions
Introduction to Spring Boot ② ~ AOP ~
Introduction to Apache Beam (2) ~ ParDo ~
[Ruby] Introduction to Ruby Error statement
Introduction to EHRbase 2-REST API
Introduction to design patterns Prototype
GitHub Actions Introduction to self-made actions
[Java] Introduction to Stream API
Introduction to Design Patterns (Iterator)
Introduction to Spring Boot Part 1
XVim2 introduction memo to Xcode12.3
Introduction to RSpec-Everyday Rails Summary-
Introduction to Design Patterns (Strategy)
[Introduction to rock-paper-scissors games] Java
Introduction to Linux Container / Docker (Part 1)
Introduction to swift practice output Chapter5
Convert ruby object to JSON format