fern/01-guide/02-languages/rest.mdx
BAML allows you to expose your BAML functions as RESTful APIs:
We integrate with OpenAPI (universal API definitions), so you can get typesafe client libraries for free!
<Steps> ### Install BAML VSCode Extension https://marketplace.visualstudio.com/items?itemName=boundary.baml-extension - syntax highlighting
- testing playground
- prompt previews
<Tabs>
<Tab title="macOS (brew)" language="bash">
```bash
brew install npm openapi-generator
# 'npm' will install npx
# 'openapi-generator' will install both Java and openapi-generator-cli
```
</Tab>
<Tab title="Linux (apt)" language="bash">
OpenAPI requires `default-jdk`
```bash
apt install npm default-jdk -y
# 'npm' will install npx; 'default-jdk' will install java
```
</Tab>
<Tab title="Linux (yum/dnf)" language="bash">
OpenAPI requires Java
```bash
dnf install npm java-21-openjdk -y
# dnf is the successor to yum
```
Amazon Linux 2023:
```bash
dnf install npm java-21-amazon-corretto -y
# 'npm' will install npx
# 'java-21-amazon-corretto' will install java
```
Amazon Linux 2:
```bash
curl -sL https://rpm.nodesource.com/setup_16.x | bash -
yum install nodejs -y
# 'nodejs' will install npx
amazon-linux-extras install java-openjdk11 -y
# 'java-openjdk11' will install java
```
</Tab>
<Tab title="Windows" language="powershell">
To install `npx` and `java` (for OpenAPI):
1. Use the [Node.js installer](https://nodejs.org/en/download/prebuilt-installer) to install `npx` (default installer settings are fine).
2. Run `npm install -g npm@latest` to update `npx` (there is currently an [issue][npx-windows-issue] with the default install of `npx` on Windows where it doesn't work out of the box).
3. Run the [Adoptium OpenJDK `.msi` installer](https://adoptium.net/temurin/releases/?os=windows) (install the JDK; default installer settings are fine).
You can verify that `npx` and `java` are installed by running:
```powershell
npx -version
java -version
```
</Tab>
<Tab title="Other" language="bash">
To install `npx`, use the [Node.js installer](https://nodejs.org/en/download/prebuilt-installer).
To install `java` (for OpenAPI), use the [Adoptium OpenJDK packages](https://adoptium.net/installation/linux/).
</Tab>
</Tabs>
This will give you some starter BAML code in a `baml_src` directory.
<Tabs>
<Tab title="C#" language="bash">
```bash
npx @boundaryml/baml init \
--client-type rest/openapi --openapi-client-type csharp
```
</Tab>
<Tab title="C++" language="bash">
<Tip>OpenAPI supports [5 different C++ client types][openapi-client-types];
any of them will work with BAML.</Tip>
```bash
npx @boundaryml/baml init \
--client-type rest/openapi --openapi-client-type cpp-restsdk
```
</Tab>
<Tab title="Go" language="bash">
```bash
npx @boundaryml/baml init \
--client-type rest/openapi --openapi-client-type go
```
</Tab>
<Tab title="Java" language="bash">
```bash
npx @boundaryml/baml init \
--client-type rest/openapi --openapi-client-type java
```
Notice that `on_generate` has been initialized for you to:
- run the OpenAPI generator to generate a Java client library, and _also_
- run `mvn clean install` to install the generated client library to your
local Maven repository
<Warning>
If you only use Maven through an IDE (e.g. IntelliJ IDEA), you should
remove `&& mvn clean install` from the generated `on_generate` command.
</Warning>
</Tab>
<Tab title="PHP" language="bash">
```bash
npx @boundaryml/baml init \
--client-type rest/openapi --openapi-client-type php
```
</Tab>
<Tab title="Ruby" language="bash">
```bash
npx @boundaryml/baml init \
--client-type rest/openapi --openapi-client-type ruby
```
</Tab>
<Tab title="Rust" language="bash">
```bash
npx @boundaryml/baml init \
--client-type rest/openapi --openapi-client-type rust
```
</Tab>
<Tab title="Other" language="bash">
As long as there's an OpenAPI client generator that works with your stack,
you can use it with BAML. Check out the [full list in the OpenAPI docs][openapi-client-types].
```bash
npx @boundaryml/baml init \
--client-type rest/openapi --openapi-client-type $OPENAPI_CLIENT_TYPE
```
</Tab>
</Tabs>
```bash
npx @boundaryml/baml dev --preview
```
This will do four things:
- serve your BAML functions over a RESTful interface on `localhost:2024`
- generate an OpenAPI schema in `baml_client/openapi.yaml`
- run `openapi-generator -g $OPENAPI_CLIENT_TYPE` in `baml_client` directory to
generate an OpenAPI client for you to use
- re-run the above steps whenever you modify any `.baml` files
After running the npx @boundaryml/baml dev command, you can check that the
server is up and running by making an HTTP request to these routes:
http://localhost:2024/_debug/ping:
Open in the browser or use curl to check that the server is up. You should
see a text response similar to this: pong (from baml v0.206.1).
http://localhost:2024/docs: Open in the
browser to see and interact with all your routes through the Swagger UI
generated from the OpenAPI schema.
openapi-generator will generate a README with instructions for installing
and using your client; we've included snippets for some of the most popular
languages below. Check out
baml-examples for example
projects with instructions for running them.
Run this with go run main.go:
package main
import (
"context"
"fmt"
"log"
baml "my-golang-app/baml_client"
)
func main() {
cfg := baml.NewConfiguration()
b := baml.NewAPIClient(cfg).DefaultAPI
extractResumeRequest := baml.ExtractResumeRequest{
Resume: "Ada Lovelace (@gmail.com) was an English mathematician and writer",
}
resp, r, err := b.ExtractResume(context.Background()).ExtractResumeRequest(extractResumeRequest).Execute()
if err != nil {
fmt.Printf("Error when calling b.ExtractResume: %v\n", err)
fmt.Printf("Full HTTP response: %v\n", r)
return
}
log.Printf("Response from server: %v\n", resp)
}
You can use the default on_generate command, which will tell baml dev to
install the OpenAPI-generated client into your local Maven repository by running
mvn clean install every time you save a change to a BAML file.
To depend on the client in your local Maven repo, you can use these configs:
<CodeGroup> ```xml pom.xml <dependency> <groupId>org.openapitools</groupId> <artifactId>openapi-java-client</artifactId> <version>0.1.0</version> <scope>compile</scope> </dependency> ```repositories {
mavenCentral()
mavenLocal()
}
dependencies {
implementation("org.openapitools:openapi-java-client:0.1.0")
}
You'll probably want to comment out on_generate and instead use either the OpenAPI Maven plugin or OpenAPI Gradle plugin to build your OpenAPI client.
plugins {
id("org.openapi.generator") version "7.8.0"
}
openApiGenerate {
generatorName.set("java") // Change to 'kotlin', 'spring', etc. if needed
inputSpec.set("${projectDir}/baml_client/openapi.yaml")
outputDir.set("$buildDir/generated-sources/openapi")
apiPackage.set("com.boundaryml.baml_client.api")
modelPackage.set("com.boundaryml.baml_client.model")
invokerPackage.set("com.boundaryml.baml_client")
additionalProperties.set(mapOf("java8" to "true"))
}
sourceSets["main"].java {
srcDir("$buildDir/generated-sources/openapi/src/main/java")
}
tasks.named("compileJava") {
dependsOn("openApiGenerate")
}
Then, copy this code into wherever your main function is:
import com.boundaryml.baml_client.ApiClient;
import com.boundaryml.baml_client.ApiException;
import com.boundaryml.baml_client.Configuration;
// NOTE: baml_client/README.md will suggest importing from models.* - that is wrong.
// See https://github.com/OpenAPITools/openapi-generator/issues/19431 for more details.
import com.boundaryml.baml_client.model.*;
import com.boundaryml.baml_client.api.DefaultApi;
public class Example {
public static void main(String[] args) {
ApiClient defaultClient = Configuration.getDefaultApiClient();
DefaultApi apiInstance = new DefaultApi(defaultClient);
ExtractResumeRequest extractResumeRequest = new ExtractResumeRequest(); // ExtractResumeRequest |
try {
Resume result = apiInstance.extractResume(extractResumeRequest);
System.out.println(result);
} catch (ApiException e) {
System.err.println("Exception when calling DefaultApi#extractResume");
System.err.println("Status code: " + e.getCode());
System.err.println("Reason: " + e.getResponseBody());
System.err.println("Response headers: " + e.getResponseHeaders());
e.printStackTrace();
}
}
}
First, add the OpenAPI-generated client to your project:
"repositories": [
{
"type": "path",
"url": "baml_client"
}
],
"require": {
"boundaryml/baml-client": "*@dev"
}
You can now use this code to call a BAML function:
<?php
require_once(__DIR__ . '/vendor/autoload.php');
$apiInstance = new BamlClient\Api\DefaultApi(
new GuzzleHttp\Client()
);
$extract_resume_request = new BamlClient\Model\ExtractResumeRequest();
$extract_resume_request->setResume("Marie Curie was a Polish and naturalised-French physicist and chemist who conducted pioneering research on radioactivity");
try {
$result = $apiInstance->extractResume($extract_resume_request);
print_r($result);
} catch (Exception $e) {
echo 'Exception when calling DefaultApi->extractResume: ', $e->getMessage(), PHP_EOL;
}
Use ruby -Ilib/baml_client app.rb to run this:
require 'baml_client'
require 'pp'
api_client = BamlClient::ApiClient.new
b = BamlClient::DefaultApi.new(api_client)
extract_resume_request = BamlClient::ExtractResumeRequest.new(
resume: <<~RESUME
John Doe
Education
- University of California, Berkeley
- B.S. in Computer Science
- graduated 2020
Skills
- Python
- Java
- C++
RESUME
)
begin
result = b.extract_resume(extract_resume_request)
pp result
edu0 = result.education[0]
puts "Education: #{edu0.school}, #{edu0.degree}, #{edu0.year}"
rescue BamlClient::ApiError => e
puts "Error when calling DefaultApi#extract_resume"
pp e
end
cargo watch --delay 1 -- cargo build
First, add the OpenAPI-generated client to your project:
[dependencies]
baml-client = { path = "./baml_client" }
You can now use cargo run:
use baml_client::models::ExtractResumeRequest;
use baml_client::apis::default_api as b;
#[tokio::main]
async fn main() {
let config = baml_client::apis::configuration::Configuration::default();
let resp = b::extract_resume(&config, ExtractResumeRequest {
resume: "Tony Hoare is a British computer scientist who has made foundational contributions to programming languages, algorithms, operating systems, formal verification, and concurrent computing.".to_string(),
}).await.unwrap();
println!("{:#?}", resp);
}