We live in a interconnected world, were every day new devices, systems, and applications are connected to share information or interact between them. Thus, the importance of designing systems prepared to offer their services and data to a wide range of customers, that could discover, navigate and use their API in a standard and easy way to be consumed. But designing a headless platform to be used easily through their services is not straightforward. In this talk we will go over the challenges that we've found in adding headless nature to our platform and the foundations and tools that we have
21. Resources
@Path("recipe")
public class RecipeResource {
@GET @Path("{id}")
public RecipeDTO retrieveRecipe(@PathParam("id") long id) {
return new RecipeDTO(_recipeService.getRecipe(id).getName());
}
@Reference
private RecipeService _recipeService;
}
‣ Manages the endpoints in a specific Path
22. Data Objects
@XmlRootElement
public class RecipeDTO {
@XmlElement
public List<String> getSteps() {
return steps;
}
@XmlElement
public long getId() {
return id;
}
‣ Annotated with binding info
23. Data Objects
public class RecipeDTO {
@JsonGetter(value = "steps")
public List<String> getSteps() {
return steps;
}
@JsonGetter(value = “id")
public long getId() {
return id;
}
‣ Annotated with binding info
24. Extensions
@PreMatching
public class AuthFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext ctx) throws IOException {
String authHeader = ctx.getHeaderString(HttpHeaders.AUTHORIZATION);
if (!verifyUser(authHeader)) {
throw new NotAuthorizedException("Not Authorized!");
}
}
private boolean verifyUser(String authHeader) {}
}
‣ Adds additional logic to the API
32. The Web is still a case of success
On the other side
33. REST style is an abstraction of
the architectural elements within
a distributed hypermedia system
-- Roy Fielding, 2000
34.
35. Hypermedia Controls
Consumers must only know
ONE URL
And how to navigate from it
Contract with consumer defines
affordance types
(relations, actions, …)
Start with IANA’s 80 relation types
Home URL Link TypesAffordance Types
46. {
"@id": "http://localhost:8080/o/api/f/u/recipe",
"title": "The recipe updater form",
"description": "This form can be used to update a recipe",
"supportedProperty": [
{
"@type": "SupportedProperty",
"property": "alternateName",
"readable": false,
"required": false,
"writeable": true
},
{
"@type": "SupportedProperty",
"property": “password”,
"readable": false,
"required": true,
"writeable": true
},
...To Forms
JSON+LD
Affordance Types
47. Shared Vocabularies
Standard types
schema.org: 597 types y 867
properties
ActivityStreams, microformats,
…
Never expose internal models
Custom types must be
consumer focused
Well defined custom types
56. Creating Types (I)
@Type(“Restaurant")
public interface RestaurantType extends Identifier<Long> {
@Id
public long getId();
@Field(“chefId”) @LinkedModel(PersonType.class)
public Long getChefId();
@Field("name")
public String getName();
@Field("logoUrl")
public String getLogoURL();
@Field("address")
public PostalAddressType getAddress();
}
57. Making DTO implement Types
@Type(“Restaurant")
public class OrganizationDTO implements RestaurantType {
}
And get rid of all those JAXB or Jackson annotations!!!
62. Method mapping annotations
@Remove
public void remove(@Id long id) {...}
@Id indicates an Identifier
@Body parses the body content
@Create
public BlogPostiong create(@Body BlogPosting blogPosting) {...}
@ParentId links to the Id of a parent resource
@Retrieve
public List<BlogPosting> retrieveBlogPosts(
@ParentId(Organization.class) long groupId)
63. Special context parameters
@Retrieve
public List<BlogPosting> retrieveBlogPosts(
@ParentId(Organization.class) long groupId, User user)
User extracted from Context, logged User
Pagination & PageItems to handle pagination
@EntryPoint @Retrieve
public PageItems<BlogPosting> retrievePage(Pagination pagination)
64. A more complex ActionRouter
@Component
public class BlogPostingActionRouter implements ActionRouter<BlogPosting> {
@Create
public BlogPosting create(@Body BlogPosting blogPosting) {...}
@Remove
public void remove(@Id long id) {...}
@Replace
public BlogPosting replace(@Id long id, @Body BlogPosting blogPosting) {...}
@Retrieve
public BlogPosting retrieve(@Id long id) {...}
@EntryPoint @Retrieve
public PageItems<BlogPosting> retrievePage(Pagination pagination) {return null;}
@Subscribe
public BlogSubscription subscribe(@Id long id, @Body BlogSubscription subscrption){...}
65. Resource embedding and Sparse field sets
http://localhost:8080/o/api/restaurant
?embedded=creator
&fields[Person]=name,image
&sort=datePublished:desc
&filter=name eq ‘Chopping Victory’
&page=1
&per_page=10
66. Search, Sort and filter (Affordances w URL templates)
http://localhost:8080/o/api/restaurant
?embedded=creator
&fields[Person]=name,image
&sort=datePublished:desc
&filter=name eq ‘Chopping Victory’
&page=1
&per_page=10
79. Spend time defining your vocabulary
It is the most important design activity
for an API
80. Make consumers & their
developers the focus of your
API design strategy
● Provide features that make their job easier
● APIs should speak their language, not yours
81. Enable clients and tools to
discover and navigate your API
● Same code could work for different scenarios