# MetaOxide Spring Boot Service
An enterprise REST API demonstrating how to build a metadata extraction service using MetaOxide in Java with Spring Boot.
## What This Example Shows
This Spring Boot application demonstrates:
- Using MetaOxide Java bindings
- Building enterprise REST APIs
- Spring Boot dependency injection
- Request/response handling
- Exception mapping
- Async processing
- Logging and monitoring
- Deployment on application servers
## Prerequisites
- Java 8+ ([Install](https://openjdk.org/install/))
- Maven 3.6+ ([Install](https://maven.apache.org/install.html))
- Spring Boot 2.6+ or 3.0+
## Installation & Setup
```bash
# Build the project
mvn clean install
# Run with Spring Boot
mvn spring-boot:run
# Or run the generated JAR
java -jar target/metaoxide-spring-*.jar
```
## Running the Service
```bash
# Start the application
mvn spring-boot:run
# Server runs at http://localhost:8080
```
## API Endpoints
### POST /api/extract
Extract all metadata from provided HTML.
**Request:**
```bash
curl -X POST http://localhost:8080/api/extract \
-H "Content-Type: application/json" \
-d '{
"html": "<html><head><title>Example</title></head></html>",
"baseUrl": "https://example.com"
}'
```
**Response:**
```json
{
"success": true,
"data": {
"meta": {
"title": "Example",
"description": "..."
},
"openGraph": {
"og:title": "Example",
...
}
}
}
```
### POST /api/extract/{format}
Extract specific metadata format.
**Formats:** `meta`, `open-graph`, `twitter`, `json-ld`, `microdata`, `microformats`, `rdfa`, `dublin-core`, `manifest`, `oembed`, `rel-links`
```bash
curl -X POST http://localhost:8080/api/extract/json-ld \
-H "Content-Type: application/json" \
-d '{"html": "...", "baseUrl": "https://example.com"}'
```
### GET /actuator/health
Spring Boot health check.
```bash
curl http://localhost:8080/actuator/health
```
## Usage Examples
### Java with RestTemplate
```java
RestTemplate restTemplate = new RestTemplate();
Map<String, String> request = new HashMap<>();
request.put("html", "<html><head><title>Test</title></head></html>");
request.put("baseUrl", "https://example.com");
ResponseEntity<Map> response = restTemplate.postForEntity(
"http://localhost:8080/api/extract",
request,
Map.class
);
System.out.println(response.getBody());
```
### Spring Boot Service
```java
@Service
public class MetadataExtractionService {
public Map<String, Object> extractMetadata(String html, String baseUrl) {
Extractor extractor = new Extractor(html, baseUrl);
return extractor.extractAll();
}
}
```
## How It Works
### Main Components
1. **Controller** (`MetadataController.java`)
- REST endpoints
- Request handling
- Response formatting
2. **Service** (`MetadataExtractionService.java`)
- Business logic
- MetaOxide integration
- Error handling
3. **Models**
- Request objects (ExtractionRequest)
- Response objects (ExtractionResponse)
### Key Code Pattern
```java
@RestController
@RequestMapping("/api")
public class MetadataController {
@Autowired
private MetadataExtractionService service;
@PostMapping("/extract")
public ResponseEntity<Map<String, Object>> extractAll(
@RequestBody ExtractionRequest request) {
Map<String, Object> result = service.extractMetadata(
request.getHtml(),
request.getBaseUrl()
);
return ResponseEntity.ok(result);
}
}
```
## Configuration
### application.yml
```yaml
spring:
application:
name: metaoxide-api
jpa:
database-platform: org.hibernate.dialect.H2Dialect
server:
port: 8080
servlet:
context-path: /
management:
endpoints:
web:
exposure:
include: health,metrics
metrics:
enable:
jvm: true
process: true
```
## Performance
Expected performance on standard hardware:
- **Single extraction**: <20ms
- **10 concurrent requests**: <100ms
- **100 requests/second**: Easily handled with 4 threads
**Performance tuning:**
```yaml
server:
tomcat:
threads:
max: 200
min-spare: 10
max-connections: 10000
```
## Deployment
### Executable JAR
```bash
# Build
mvn clean package
# Run
java -jar target/metaoxide-spring-*.jar
# With custom port
java -Dserver.port=8081 -jar target/metaoxide-spring-*.jar
```
### Docker Deployment
```dockerfile
FROM maven:3.8-eclipse-temurin-17 as builder
WORKDIR /app
COPY . .
RUN mvn clean install -DskipTests
FROM eclipse-temurin:17-jre-alpine
COPY --from=builder /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]
```
Build and run:
```bash
docker build -t metaoxide-api .
docker run -p 8080:8080 metaoxide-api
```
### Application Server (Tomcat, Jetty)
```bash
# Build WAR
mvn clean package -Pwar
# Deploy to Tomcat
cp target/*.war /opt/tomcat/webapps/
```
## Testing
Run tests:
```bash
mvn test
# With coverage
mvn clean test jacoco:report
# View report
open target/site/jacoco/index.html
```
Example test:
```java
@SpringBootTest
@AutoConfigureMockMvc
public class MetadataControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void testExtractAll() throws Exception {
String html = "<html><head><title>Test</title></head></html>";
mockMvc.perform(post("/api/extract")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"html\": \"" + html + "\"}"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true));
}
}
```
## Android Integration
Use MetaOxide in Android applications:
```gradle
dependencies {
implementation 'io.github.yfedoseev:meta-oxide:0.1.0'
}
```
```java
// In Android Activity
Extractor extractor = new Extractor(htmlContent, baseUrl);
Map<String, Object> result = extractor.extractAll();
// Display results
textView.setText(result.toString());
```
## Logging
Configure logging in `application.yml`:
```yaml
logging:
level:
root: INFO
com.example.metaoxide: DEBUG
pattern:
console: "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
```
## Monitoring with Actuator
Spring Boot Actuator provides metrics:
```bash
# Get metrics
curl http://localhost:8080/actuator/metrics
# View specific metric
curl http://localhost:8080/actuator/metrics/http.server.requests
```
Add custom metrics:
```java
@Component
public class ExtractionMetrics {
private final AtomicInteger extractionCount = new AtomicInteger(0);
public void recordExtraction() {
extractionCount.incrementAndGet();
}
}
```
## Exception Handling
Global exception handling:
```java
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<ErrorResponse> handleIllegalArgument(
IllegalArgumentException e) {
return ResponseEntity.badRequest()
.body(new ErrorResponse("Invalid input: " + e.getMessage()));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGeneral(Exception e) {
return ResponseEntity.internalServerError()
.body(new ErrorResponse("Internal server error"));
}
}
```
## Learning Resources
- [MetaOxide Getting Started (Java)](../../../docs/getting-started/getting-started-java.md)
- [Java API Reference](../../../docs/api/api-reference-java.md)
- [Spring Boot Documentation](https://spring.io/projects/spring-boot)
- [Spring REST Guide](https://spring.io/guides/gs/rest-service/)
## Troubleshooting
### Port Already in Use
```bash
# Use different port
mvn spring-boot:run -Dspring-boot.run.arguments="--server.port=8081"
```
### Native Library Not Found
```bash
# Ensure MetaOxide dependency is installed
### Out of Memory
```bash
# Increase heap size
export MAVEN_OPTS="-Xmx1024m"
mvn clean install
```
## License
This example is licensed under the same dual license as MetaOxide: **MIT OR Apache-2.0**
---
**Questions?** Check the main [MetaOxide documentation](../../../README.md) or open an issue.