Giter Club home page Giter Club logo

rest-schemagen's Introduction

rest-schemagen

Build Status Coverage Status MavenCentral APL2 License

Jersey add-on for dynamic link and schema building. This add-on is for building HATEOAS-conform responses with your jersey REST-API. Creating and managing your links and schemas of your REST-API becomes as easy as making a method call.

It also works for reverse proxies (like jetty behind apache/nginx)

Quick start

In your jersey configuration simply include:

LinkFactoryResourceConfig.configure(rs); 

Where "rs" is your jersey application ResourceConfig. Please choose Jackson as your JSON provider

In your resources you simply type:

@Path("somethings")
@Produces(MediaType.APPLICATION_JSON)
public class ResourceClass {
    @Inject
    private LinkMetaFactory linkMetaFactory; // security and baseURIs already injected
 
    @Path("{id}")
    @GET
    @RolesAllowed("test")
    public ObjectWithSchema<Something> getSomething(@PathParam("id") int id) {
 
        Optional<Link> link = linkMetaFactory
            .createFactoryFor(ResourceClass.class)
            .forCall(Rel.SELF, r -> r.getSomething(id));
 
        final JsonHyperSchema hyperSchema = JsonHyperSchema.fromOptional(link);
        return ObjectWithSchema.create(json, hyperSchema);
    }
}

Responses will look like this:

{
  "id": 1,
  "something": 1321892112432,
  "_schema":
    {
      "links":
        [{
            "href": "http://localhost:8081/somethings/1",
            "rel": "self",
            "targetSchema":
                {
                    "type":"object",
                    "properties":{
                        "id":{"type":"integer"},
                        "something":{"type":"integer"}
                    }
                },
            "method": "GET"
       }]
    }
}

or if you have subresources:

@Path("parent")
@Produces(MediaType.APPLICATION_JSON)
public class ParentResourceClass {
    @Inject
    private LinkMetaFactory linkMetaFactory; // security and baseURIs already injected
 
    @Path("/subpath")
    public ResourceClass getSubResourceInParentResource() {
        return new ResourceClass();
    }
}

Then, in ResourceClass, you need to generate the link like this:

Optional<Link> link = linkMetaFactory
    .createFactoryFor(ParentResourceClass.class)
    .subResource(p -> p.getSubResourceInParentResource()), ResourceClass.class)
    .forCall(Rel.SELF, r -> r.getSomething(id));

Note, that all calls have properly typed return values. So you get code completion, call hierarchy and all other features you are used to have in your IDE.

Then responses will look like this:

{
  "id": 1,
  "something": 1321892112432,
  "_schema":
    {
      "links":
        [{
            "href": "http://localhost:8081/parent/subpath/1",
            "rel": "self",
            "targetSchema":
                {
                    "type":"object",
                    "properties":{
                        "id":{"type":"integer"},
                        "something":{"type":"integer"}
                    }
                },
            "method": "GET"
       }]
    }
}

Allowed and default values

There is a way to manipulate allowed and default values. The central class is CallContext. With CallContext you can also bring custom values to your plugins (see next section). The following sample shows how to bring dynamic computed default/allowed values to an address (based e.g. on the country the current user comes from).

Optional<Link> link = Optional.empty();
 
final CallContext context = Parameter.createContext();
 
final Parameter.Builder<AddressJson> addressJsonBuilder = context.builderFor(AddressJson.class) //
        .allowValues(getAllowedAddressTypes());
 
if (!addressJsonBuilder.isEmpty()) {
    final Parameter<AddressJson> addressJson = addressJsonBuilder //
            .allowValues(getAvailableContryCodes())
            .defaultValue(getDefaultAddressValue()).build();
 
    link = linkFactoryForAddressResource.forCall(Rel.CREATE, r -> r.createAddress(addressJson.get()),
            context);
}

The context and the parameter, which is build by context.builderFor() are still connected.

Plugins

There are three possibilities to customize the way the schema generation works. All of them are located in the plugin package.

Determine if a link should be made from a method

You should bring you own implementation of the MethodCheckerForLink interface and bind it with your own factory. A common use-case would be if you want to check security roles. The implementation can be found in the plugin package.

Determine if a field should be included in the schema

You should bring you own implementation of the FieldCheckerForSchema interface and bind it with your own factory. A common use-case is included in the package. There, you do the filtering with jackson's JsonView annotation. In the future, we plan to do the filtering based on the roles of a user. This feature depends on https://java.net/jira/browse/JERSEY-2998.

Mapping of a field

Provide an IndividualSchemaGenerator with the PropertySchema annotation at the desired field.

Creating your own relations

If you need your own relations you can do the following:

public enum OwnRel implements RelationContainer {
 
    FOO, BAR(RelType.OTHER);
 
    private final Relation relation;
 
    OwnRel() {
        this(RelType.SELF);
    }
 
    OwnRel(RelType type) {
        relation = Relation.of(this, type);
    }
 
    public Relation getRelation() {
        return relation;
    }
}

Examples

Troubleshooting import in IDEs

If you have compile errors using an IDE, it is most likely because of immutables. Please refer to the immutables help page. Keep in mind to choose the right package version of the value-jar.

rest-schemagen's People

Contributors

wuan avatar joergadler avatar yasammez avatar skynetsonar avatar mweirauch avatar busoniu avatar bernhardbln avatar leflamm avatar renemazala avatar m-kn avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.