A framework for creating a RESTful API.
This framework provides a default implementation of a JAX-RS Web Resource (sometimes called an endpoint) that maps the more complicated HTTP-compliant access to simpler CRUD functions. This has the benefit of providing standards-compliant as well as consistent behavior for your API without needing to understand the complexity of standards like HTTP. As API developer you only have to implement CRUD functions which are much simpler and more concretely defined. This level of consistency in the API also allows for additional convenience and features to be implemented generically, with little to no effort required from the API developer to enable it.
- The implementation is based on JAX-RS and can be used with any JAX-RS framework.
- The HTTP methods are mapped to simple CRUD functions (Create, Read, Update, Delete and List by default). The exact details of how each of these methods should behave is provided in the accompanying javadoc.
- Make sure you have designed your API resources and identified their attributes, links, embedded resources and hypermedia controls
- Add a dependency on
SimplyRESTful
to your project
For each of your API resources, create a POJO that extends APIResource and provide it with a custom JSON media type.
public class MyResource extends APIResource {
public static final String MEDIA_TYPE_JSON = "application/x.myresource-v1+json";
@Override
public MediaType getCustomJsonMediaType(){
return MediaType.valueOf(MEDIA_TYPE_JSON);
}
// Add the rest of your resource as well
}
For each POJO, create a JAX-RS Web Resource (sometimes called an endpoint) that extends DefaultWebResource and uses that POJO as its generic type T.
public class MyWebResource extends DefaultWebResource<MyResource>{
@Override
public MyResource create(MyResource resource, UUID resourceUUID){/* Add your implementation*/}
@Override
public MyResource read(UUID resourceUUID){/* Add your implementation*/}
@Override
public MyResource update(MyResource resource, UUID resourceUUID){/* Add your implementation*/}
@Override
public MyResource delete(UUID resourceUUID){/* Add your implementation*/}
@Override
public MyResource list(long pageNumber, long pageSize, List<String> fields, String query, List<SortOrder> sort){/* Add your implementation*/}
}
In this Web Resource, you can now implement the create()
, read()
, update()
, delete()
and list()
methods to connect to your backend as needed. Though you should mostly implement these methods as you would expect, there are some things to keep in mind.
- The
create()
method should return the exact resource that was stored, not what was provided (since storing the resource may sometimes change it). - If the
read()
method cannot find a resource with the given ID, it should returnnull
. - Same as with
create()
, theupdate()
method should return the exact resource that was updated. - Same as with
read()
, thedelete()
method should returnnull
if it could not find the resource with the given ID. - The
list()
method works as expected and just returns a list of resources.- The list should be filtered according to the
query
parameter, which is specified as a FIQL query. - It should also be sorted according to the
sort
parameter, which is specified as an ordered list of fields, along with their sort direction. - While the
fields
parameter can be used to restrict which fields are retrieved, it is optional. The fields filtering can be done outside of this implementation, unlike querying and sorting. This is implemented in the framework as a Jakarta Servlet filter.
- The list should be filtered according to the
- For improved performance, you should also override the
count()
andexists()
methods with a more efficient implementation for your specific backend. By default, it wil use thelist()
andread()
methods, respectively, to provide this functionality.
You can configure your JAX-RS framework manually, as described below, or you can use one of the convenience deploy libraries provided by the framework (see the main README for more details).
In your JAX-RS framework, register:
- the
JacksonJsonProvider
class (to correctly serialize and deserialize our plain JSON documents).
// Example for Jersey (in ResourceConfig)
register(JacksonJsonProvider.class);
- the Swagger classes (to generate the OpenAPI Specification document).
// Example for Jersey (in ResourceConfig)
register(OpenApiResource.class);
register(AcceptHeaderOpenApiResource.class);
- the
UriCustomizer
class (optional, allows the original URL used by the client to be retrieved from an HTTP header and used in the API when creating links).
// Example for Jersey (in ResourceConfig)
register(UriCustomizer.class);
- the
WebResourceRoot
class (to provide the ServiceDocument at the root of your API).
// Example for Jersey (in ResourceConfig) with JAX-RS-managed lifecycle
register(WebResourceRoot.class);
- the Web Resources you created for each POJO (to make them available in the API).
// Example for Jersey (in ResourceConfig) with package scanning
packages("com.name.of.my.root.package");
If you registered the UriCustomizer
class, you will need to provide SIMPLYRESTFUL_URI_HTTP_HEADER
as environment variable with the HTTP header name containing the original URL as its value, e.g. SIMPLYRESTFUL_URI_HTTP_HEADER=xoriginalurl
with the xoriginalurl
HTTP header containing the absolute URL used by the client.
Deploy and run your SimplyRESTful API as you would any other JAX-RS API, e.g. start your Jetty server or run your Spring Boot application.
The SimplyRESTful framework will ensure that there is a service document at the root of your deployed API as the main entry point to your API. This service document provides discoverable documentation, i.e. a link to the OpenAPI Specification where the API is described fully. You can then use the API as you normally would, or you can use one of the provided clients, in Java or TypeScript, to access the API more easily.